Custom React Native Plugin is null (iOS) - react-native

I'm creating a react native plugin. Android works like charm, but iOS makes some troubles. The plugin is always null.
Files:
myPlugin-bridging-header.h
#import <React/RCTBridgeModule.h>
myPlugin.m
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(MyPlugin, NSObject)
RCT_EXTERN_METHOD(multiply:(float)a withB:(float)b
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
#end
myPlugin.swift
import Foundation
#objc(MyPlugin)
class MyPlugin: NSObject {
#objc(multiply:withB:withResolver:withRejecter:)
func multiply(a: Float, b: Float, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
resolve(a*b)
}
}
index.js
import { NativeModules } from 'react-native';
const { MyPlugin } = NativeModules;
export default MyPlugin;
Usage
import MyPlugin from 'my-plugin';
[...]
console.log(MyPlugin); // is null
MyPlugin.multiply(2, 8).then((value) => {
console.log('value: ', value);
});
I don't know what is missing. The plugin is always null. Is #interface RCT_EXTERN_MODULE(MyPlugin, NSObject) not enough to make the module available?

Add missing function moduleName in your swift file
override class func moduleName() -> String! {
return "MyPlugin"
}

Related

Not able to import "project-name-Swift.h" file xcode

I have 2 files.
"CodeInjection.m"
#import <Foundation/Foundation.h>
#import "BiplovCodeInjection-Swift.h"
#interface CodeInjection: NSObject
#end
#implementation CodeInjection
static void __attribute__((constructor)) initialize(void){
NSLog(#"==== Code Injection in Action==== with sniffer");
[[CodeInjectionSwift shared] performTask];
}
#end
My second file is.
"BiplovCodeInjectionSwift.swift"
import Foundation
import NetworkInterceptor
#objc class CodeInjectionSwift: NSObject {
#objc public static let shared = CodeInjectionSwift()
override private init(){}
#objc func performTask(){
let requestSniffers: [RequestSniffer] = [
RequestSniffer(requestEvaluator: AnyHttpRequestEvaluator(), handlers: [
SniffableRequestHandlerRegistrable.console(logginMode: .nslog).requestHandler()
])
]
let requestRedirectors: [RequestRedirector] = [
RequestRedirector(requestEvaluator: DomainHttpRequestEvaluator(domain: "www.antennahouse.com"), redirectableRequestHandler: AlternateUrlRequestRedirector(url: URL(string: "https://www.rhodeshouse.ox.ac.uk/media/1002/sample-pdf-file.pdf")!))
]
let networkConfig = NetworkInterceptorConfig(requestSniffers: requestSniffers,
requestRedirectors: requestRedirectors)
NetworkInterceptor.shared.setup(config: networkConfig)
NetworkInterceptor.shared.startRecording()
}
}
It fails on the line "#import "BiplovCodeInjection-Swift.h"
I built a new project > framework.
Here's my file strucuture
Why is it that I can't import the header file?

How to call swift native function from react native?

I have a swift class, which i am exposing to react-native, inside that i have a function that is also exposed to react-native. Now when react native calls that function it does a lot of this internally, but after some point of time it returns an object.
Now it will call a specific function that will get the object. I cannot change the parameter to that function. But i have another function, to which i want to return to react native. How can i do it.
func AckCallback(response:APIResponse) -> Void
{
print(response)
}
for this function I cannot change the paremeter, becaused it had been used a lot of places, But I want to return that response from this function to react-native. If anybody know this issue, please let me know.
#objc func sendEvent(_ response: APIResponse, callback: (NSObject) -> ())
-> Void {
callback( [[
"responseCode" : "Working",
]] as NSObject)
}
I just want to know how to use this sendEvent inside the AckCallback, or is there any other way to send that **
response: APIResponse
**
to react-native.
For the first create Swift class (e.g YourModule.swift)
//
// YourModule.swift
//
#objc(YourModule)
class YourModule: NSObject {
#objc func callNativeEvent(callback:RCTResponseSenderBlock)
-> Void {
// Here you can do your work and pass an object to the callback function.
// You can save assign a `callback` to the class property (e.g self.eventCallback = callback)
// and invoke that self.eventCallback after the asynchronous code ol somewhere else
NSObject *obj = [[NSObject alloc] init]; // your object here
callback([NSNull(), obj]);
// or if you want to return an error
// callback(["Error calling NativeEvent", NSNull()]);
// I'm not sure that RCTResponseSenderBlock works the same as in previous react-native versions. Maybe now you can pass an Object instead of an Array.
}
}
Create a Bridge file (e.g. YourModuleBridge.m)
//
// YourModuleBridge.m
//
#import <Foundation/Foundation.h>
#import "UIKit/UIKit.h"
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(YourModule, NSObject)
RCT_EXTERN_METHOD(callNativeEvent:(RCTResponseSenderBlock)callback);
#end
Also, you need Bridging-Header file if it doesn't exist in your project.
//
// YourModule-Bridging-Header.h
//
#ifndef YourModule_Bridging_Header_h
#define YourModule_Bridging_Header_h
#if __has_include("RCTBridgeModule.h")
#import "RCTBridgeModule.h"
#else
#import <React/RCTBridgeModule.h>
#endif
#endif /* YourModule_Bridging_Header_h */
And from JS
import { NativeModules } from 'react-native';
const YourModule = NativeModules.YourModule;
...
YourModule.callNativeEvent((error, response) => {
console.log('Error', error, 'Response', response);
});
In iOS Project Create 2 Files
SwiftComponentManager.swift and SwiftComponentManager.m create these 2 files.
SwiftComponentManager.swift ->
#objc(SwiftComponentManager)
class SwiftComponentManager: NSObject {
#objc func passValueFromReact(_ value : String) {
debugPrint(" Print Here \(value)")
}
}
In SwiftComponentManager.m
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#interface RCT_EXTERN_MODULE(SwiftComponentManager, NSObject)
RCT_EXTERN_METHOD(passValueFromReact:(NSString *)value) //Here exported your swift function for React Native
#end
Here start work in React-Native project
Now How will call this Swift function in React Native.
Import your SwiftComponent in React JS file
const { SwiftComponentManager } = NativeModules
Now call your function with value where you want in JS file
SwiftComponentManager.passValueFromReact("Hello World")

Why do I have to label my second argument for a react native to swift bridged function

Say I have the following Swift class:
#objc(ExampleClass)
class ExampleClass: NSObject {
init() {}
#objc func exampleMethod(_ message: String, _ properties: [String: Any]? = nil) -> Void {}
}
And the following Header:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(ExampleClass, NSObject)
RCT_EXTERN_METHOD(exampleMethod:(NSString *)name (NSDictionary *)properties)
#end
Which I then call with the following React Native code:
import { NativeModules } from 'react-native'
NativeModules.ExampleClass.exampleMethod('example', {'hello': 'world'})
This results in the following error message:
ExceptionsManager.js:73 Exception 'exampleMethod: is not a recognized Objective-C method.' was thrown while invoking trackEvent on target SegmentTracker with params (
"example",
{
hello = world;
}
)
However, if I change the function signature to be labelled like so:
#objc func exampleMethod(_ message: String, withProperties properties: [String: Any]? = nil) -> Void {}
}
And adjust the RCT_EXTERN_METHOD function like so:
RCT_EXTERN_METHOD(exampleMethod:(NSString *)name withProperties:(NSDictionary *)properties)
Why does the second argument have to be labelled? Why doesn't the first one?

Why does Luxe/Flow quit unexpectedly after building with my PhysicsHandler class?

My PhysicsHandler class seems to be causing Luxe to quit unexpectedly, and I have no idea why.
Everything runs fine until I declare a class-variable, at which point it crashes a couple of seconds after loading. What's weird is that I have another class (InputHandler) that declares class-variables and runs fine. Not sure whether this is a problem with my code (somehow... ), Luxe, or Flow.
Main class:
import luxe.Input;
import luxe.Parcel;
import luxe.ParcelProgress;
import InputHandler;
import PhysicsHandler;
import Player;
enum GAME_STATE
{
play;
pause;
}
class Main extends luxe.Game {
var INPUT_HANDLER: InputHandler;
override function ready() {
var assetsParcel = new Parcel
({
textures:
[
{ id:"assets/block.png" },
{ id:"assets/background.png" }
]
});
new ParcelProgress
({
parcel : assetsParcel,
oncomplete : onAssetsLoaded
});
assetsParcel.load();
INPUT_HANDLER = new InputHandler();
INPUT_HANDLER.GameState = GAME_STATE.play;
}
private function onAssetsLoaded(_)
{
var player = new Player();
INPUT_HANDLER.setPlayerEntity(player);
}
override function update(dt:Float) {
INPUT_HANDLER.update();
}
}
InputHandler class:
import luxe.Input;
import luxe.Entity;
import Main;
class InputHandler
{
public var GameState: EnumValue;
private var player: Entity;
// functions, etc. below here...
}
PhysicsHandler class (the troublemaker... ):
import Main;
class PhysicsHandler
{
public var GameState: EnumValue;
}
This is all it takes to crash the game somehow. As you can see, I'm not even instantiating the PhysicsHandler class yet, just importing it.
Okay, so I was able to sort this with some help on the Snowkit forums. Apparently, Luxe doesn't play well with the latest version of hxcpp, so downgrading to 3.2.102 worked. Result.

swift class in Objective-C: unknown receiver

I wrote a class in a swift-file:
class UtilityMethods {
class func userId() -> Integer {
...
}
class func setUserId(userId : Int) {
...
}
}
I'm importing the -swift.h-header which compiles fine, but I can't use
[UtilityMethods userId];
in my Objective-C code:
Unknown receiver 'UtilityMethods'; did you mean 'UtilMethods'?
UtilMethodsis an Objective-C class I'd like to replace. Am I missing something?
EDIT
With the help of Lance, the class is now recognized, but the getter method isn't, unfortunately, the header files looks like the following:
SWIFT_CLASS("_TtC15...14UtilityMethods")
#interface UtilityMethods : NSObject
+ (void)setUserId:(NSInteger)userId;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
Why is the getter missing?
In order to have a Swift class available to Objective C you have two options:
Option 1: Subclass NSObject (or some other Objective C class)
class UtilityMethods : NSObject {
class func userId() -> Int {
...
}
class func setUserId(userId: Int) {
...
}
}
Option 2: Add the #objc attribute to your class telling the Swift compiler to make an Objective C object that uses dynamic dispatch rather than static dispatch for method calls
#objc class UtilityMethods {
class func userId() -> Int {
...
}
class func setUserId(userId: Int) {
...
}
}
In my case, I was doing #objc correctly, but in changing from my old Objective-C .h file to my new swift file, I had accidentally lost the Target Membership of the new file, so it wasn't being included in the build.