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
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?
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")
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?
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.
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.