user2977578 user2977578 - 6 months ago 36
iOS Question

Can React-Native's Native side request information from React? (Bridging/Native Modules)

TLDR: Is there some way I can use a callback or get a return value from react to my native code (iOS)? Or can I use a set of locks to enforce ordering for eventdispatcher and eventemitter listeners to enforce an ordering?

More Information:

So I'm using the event dispatcher in my iOS code (self.bridge.eventDispatcher) and that's working great. I'm able to send events with information to my react code.

However, I noticed that this works asynchronously. I currently use this because if I require information on my iOS side, I send a ping to my react side requesting this information. I then lock upon the request and wait for my react code to use NativeModules and invoke an iOS method where I get the requested data.

Basically, enforcing a synchronous pattern feels a little dangerous because I'm not sure whether bridging methods can fail. For example, I can send an event to react and then lock. If my react side does not get it, or fails to send a notification to the iOS side, then I will never unlock and then will have deadlock. So to this, I have two questions. Is bridging reliable enough to avoid deadlocking through this method? Or is there a better way to accomplish the same result and request information from my react side from my iOS code?

Answer

Awesome so I got it, turns out there's a structure called RCTResponseSenderBlock. I made another

iOS method:

-(void)tmpMethod:(RCTResponseSenderBlock)callback{

  [self.bridge.eventDispatcher sendAppEventWithName:@"channel" body:@{@"Block":callback}

   ] ;

}

javascriptReciever:

EventEmitter.addListener("channel", async event => {
  console.log(event)
  event.Block(["Hello There"]);
  return;

});

ios Method Invocation:

[self tmpMethod:^(NSArray* response){
    NSLog((NSString*)[response objectAtIndex:0]); //prints Hello There
  }];

UPDATE Turns out when I try to do the same for Android, I can't. The Android platform uses WriteableMap or WriteableArray to send events using the following method:

private void sendEvent(ReactContext reactContext,
                           String eventName,
                           @Nullable WritableMap params) {
        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, params);
    }

WriteableMap and WriteableArray both do not accept objects such as callbacks which made it not possible to request information from the Javascript side. I also attempted to pass in a Promise as opposed to a WriteableMap or WriteableArray and that threw an error. To communicate asynchronously in a synchronous context for android,

  1. I will have to send an event from native to javascript
  2. lock twice to prevent further execution in side native
  3. on my javascript side invoke a method on my native side once viewing the request with the requested data
  4. unlock within the native method invoked by javascript
  5. resume execution since the program has been unlocked
  6. unlock once further after handling whatever needed to be handled synchronously. (Comment if you want my code implementation)