3

Disclaimer: because this question pertains to my work stuff, I cannot get into the actual details. I will try to provide as much information as possible about the issue. Also, I am new to ReactNative. Just started using it since a week and I might be asking something extremely trivial.

Background
There are two apps, let’s call them App-A and App-B. App-A has provisions to start Activities or get some kind of information from App-B. The way the communication contract is established when requesting some information is that App-A will startActivityForResult. The intent will explicitly cite App-B’s Activity (a headless Activity; no UI; every operation is handled in the background) in question. App-B should (ideally) place the request to it’s backend services, get the response and setResult(...) for the activity before calling finish(). I don't have the last part working yet (which is the crux of the problem discussed below)

App-B's structure
App-B makes use of ReactNative for most of the client side stuff. The Network API calls made by App-B are all done in the JavaScript code. When App-A places a “search” request, it passes the “searchTerm” which App-B must send to it’s backend services to get the results/response. Once the response is received, it must be sent back to App-A by “setting the result” using setResult(…) in Activity’s context.

Problem
The problem is passing the response/results from the JavaScript code to the Native code in App-B. Since I need to “keep the request alive" on App-B’s activity, I need to “wait” for the results to be available before setting the result for App-A’s consumption (setResult(...)).

Here is what I tried so far

  • Make use of EventEmitters: With this, the Java code in App-B will emit an event with an identifier to the ReactNative JavaScript code. However, the emit(…) method takes only two parameters - “event_name/event_identifier” and an Object. The Object can either be primitive datatypes, a Callback or WritableArray/WritableMap (collections defined in ReactNative framework). Since I need to pass the aforementioned “searchTerm” to the JavaScript code to place the network request, I cannot pass the Callback object. If I send a Callback object, then I cannot send the “searchTerm” since I can only pass one parameter. I don't think Promise works here since I still won't be able to send the "searchTerm"
// The "emit" method call below only takes 2 arguments. I can only pass
// either the "searchTerm" or a "Callback"
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)(eventName, someObject);
  • Define JavaScriptModule: Defining and exposing a "JavaScriptModule" is a way in which the Native/Java code can invoke a method defined in the JavaScript code. This method can be defined to take as many parameters/arguments as seen necessary. The idea with this was to call the JavaScript method from the Native code and pass both the searchTerm and the Callback Object. However, when the passed Arguments are verified, a RuntimeException is thrown since JavaScriptModules can only pass arguments that are of the primitive type or "WritableMap/Array" objects. Callback Objects are not supported. Same with Promise objects; they aren't supported argument types.
// Defined a SearchModule like so (required Module registration is done using ReactPackage 
// and setting it in the setPackages() method)
// Followed this: https://stackoverflow.com/questions/38661060/are-there-any-guides-for-implementing-javascriptmodule-in-react-native

// Unfortunately, this throws a RuntimeException since "Callback" is not a 
// supported argument
public interface MySearchModule extends JavaScriptModule {
    void call(String eventType, String searchQuery, Callback callback);
}

/**
 * Different file below
 */

// Arguments.java code snippet in the RN framework
for(int i = 0; i < args.length; ++i) {
    Object argument = args[i];
    if (argument == null) {
        arguments.pushNull();
    } else {
        Class argumentClass = argument.getClass();
        if (argumentClass == Boolean.class) {
            arguments.pushBoolean((Boolean)argument);
        } else if (argumentClass == Integer.class) {
            arguments.pushDouble(((Integer)argument).doubleValue());
        } else if (argumentClass == Double.class) {
            arguments.pushDouble((Double)argument);
        } else if (argumentClass == Float.class) {
            arguments.pushDouble(((Float)argument).doubleValue());
        } else if (argumentClass == String.class) {
            arguments.pushString(argument.toString());
        } else if (argumentClass == WritableNativeMap.class) {
            arguments.pushMap((WritableNativeMap)argument);
        } else {
            if (argumentClass != WritableNativeArray.class) {
                throw new RuntimeException("Cannot convert argument of type " + argumentClass);
            }

            arguments.pushArray((WritableNativeArray)argument);
        }
    }
}

Questions I have
- Is it even possible to achieve something like this in ReactNative framework where the Java code (activity) can call the JavaScript code by passing a bunch of parameters and get a response back?
- Is there anything with respect to EventEmitters/JavaScriptModule using which I could achieve the required outcome?
- Is there any other method for Native/JavaScript communications other than EventEmitters/JavaScriptModule?
- Any other possibilities for this use-case?

Some guy
  • 1,210
  • 1
  • 17
  • 39

0 Answers0