Tebogo Legodi
Tebogo Legodi

Reputation: 11

React Native intents interaction (onActivityResults running before an activity starts)

I need help or guidance in resolving the issue that I have regarding React Native interacting with other native applications via intents. I know that React Native supports deeplinking out of the box but does not cater for intents, which means that one needs to create an android native module (https://reactnative.dev/docs/native-modules-android). I created a native module that calls 3rd party applications via intents and passing data using startActivityForResults and created onActivityResult that is supposed to handle data returned from 3rd party applications after closing. However, the onActivityResult executes prematurely before external applications open.

Starting the activity using startActivityForResults:

    @ReactMethod
    public void launchApp(String stringArgument, ReadableMap args, Promise promise) throws JSONException{

        try {
            final JSONObject options = convertMapToJson(args);
            Bundle extras = new Bundle();;
            int LAUNCH_REQUEST = 0;

            if (options.has("extras")) {
                extras = createExtras(options.getJSONArray("extras"));
                Log.d(TAG,"Extras found");
                Log.d(TAG, options.getString("extras"));
            } else {
                extras = new Bundle();
                Log.d(TAG,"No extras");
            }

            if (options.has("launchRequestCode")) {
                LAUNCH_REQUEST = options.getInt("launchRequestCode");
            }

            Intent packageIntent = this.reactContext.getPackageManager().getLaunchIntentForPackage(stringArgument);
            if(packageIntent != null){
                packageIntent.putExtras(extras);
                //callback.invoke("Starting activity for: "+stringArgument);
                Activity activity = getReactApplicationContext().getCurrentActivity();
                //this.reactContext.startActivityForResult(packageIntent, LAUNCH_REQUEST, extras);
                activity.startActivityForResult(packageIntent, LAUNCH_REQUEST);
                return;
                //mPromise.put(LAUNCH_REQUEST, promise);
            }
            else{
                Log.d(TAG, stringArgument+" package not found");
                //callback.invoke("Package not found: "+stringArgument);
            }
        } catch (JSONException e) {
            //TODO: handle exception
            Log.d(TAG, e.toString());
        }
        // TODO: Implement some actually useful functionality
        
    }

Expecting the data back using onActivityResults

ActivityEventListener mActivityEventListener = new ActivityEventListener(){

        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
            //super.onActivityResult(requestCode, resCode, data);
    
            Log.d(TAG,"On activity result");
           
            if (mPromise != null && resultCode == activity.RESULT_OK) {
                WritableMap result = new WritableNativeMap();
                result.putInt("resultCode", resultCode);
                result.putMap("data", Arguments.makeNativeMap(data.getExtras()));
                mPromise.resolve(result);
            }
            else{
                Log.d(TAG,"Promise and intent data are empty");
                //mPromise.reject("Unable to get promise or intent data is empty");
            }

            if(resultCode == activity.RESULT_CANCELED ){
                Log.d(TAG,"Result cancelled or no result or crashed with code");
            }
        }

        @Override
        public void onNewIntent(Intent intent){
            Log.d(TAG,"New Intent");
        }

    };

Android Manifest file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.navapp">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

By using Android Studio Logcat to debug, I found out that the onActivityResults executes immediately before the external app opens up. Logcat screenshot

Upvotes: 0

Views: 1021

Answers (1)

Tebogo Legodi
Tebogo Legodi

Reputation: 11

Thanks to this explanation here, I was able to drill down to what was causing the issue. In my React Native application, I used the package name of the external application instead of the action name to open it.

Manifest File of the external app:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter>
            <action android:name="com.bld.pushnotification.Main"/>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
</application>

I also modified the my code for launching the app:

@ReactMethod
public void launchApp(String stringArgument, ReadableMap args, Promise promise) throws JSONException{

    try {
        final JSONObject options = convertMapToJson(args);
        Bundle extras = new Bundle();;
        int LAUNCH_REQUEST = 0;

        if (options.has("extras")) {
            extras = createExtras(options.getJSONArray("extras"));
            Log.d(TAG,"Extras found");
            Log.d(TAG, options.getString("extras"));
        } else {
            extras = new Bundle();
            Log.d(TAG,"No extras");
        }

        if (options.has("launchRequestCode")) {
            LAUNCH_REQUEST = options.getInt("launchRequestCode");
        }

        Intent packageIntent = new Intent(stringArgument);
        Activity activity = getReactApplicationContext().getCurrentActivity();
        activity.startActivityForResult(packageIntent, LAUNCH_REQUEST);

    } catch (JSONException e) {
        //TODO: handle exception
        Log.d(TAG, e.toString());
    }
    
}

Upvotes: 1

Related Questions