Skip to content

Intent (data sharing)

Jacques Bonet edited this page Dec 23, 2019 · 13 revisions

Introduction

React-native provide mechanism that permits to share a document into the desired application.

The application could be in two states:

  • close
  • in background

In Android, we can achieve this with the help of Intent Filters.

#Intent Filter

Intent filters are basically filters that define what an app can expect as its input.

Intent filter are specified in androidmanifest.xml file.

Here an extract for ent containing the intent-filter sections:

         <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
                android:windowSoftInputMode="adjustResize"
                android:launchMode="singleTask"
                android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="application/*"/>
                <data android:mimeType="audio/*"/>
                <data android:mimeType="image/*"/>
                <data android:mimeType="text/*"/>
                <data android:mimeType="video/*"/>
            </intent-filter>
        </activity>

The first intent filter permits to:

  • create an icon on the desktop of the application
  • launch the application from the desktop icon

The second intent filter permits to:

  • associate data (intent) to the application
  • launch the application

Another thing very interesting: intents are embedded inside android activities

API

Concept

There is differents possibilities to receive intents. We have privilegied API with loose coupling like messaging to communicate.

react-native provide api which permits that:

/**
 * Listener for receiving activity events. Consider using {@link BaseActivityEventListener} if
 * you're not interested in all the events sent to this interface.
 */
public interface ActivityEventListener {

  /** Called when host (activity/service) receives an {@link Activity#onActivityResult} call. */
  void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data);

  /** Called when a new intent is passed to the activity */
  void onNewIntent(Intent intent);
}
/**
 * Listener for receiving activity lifecycle events.
 *
 * <p>When multiple activities share a react instance, only the most recent one's lifecycle events
 * get forwarded to listeners. Consider the following scenarios:
 *
 * <ol>
 *   <li>Navigating from Activity A to B will trigger two events: A#onHostPause and B#onHostResume.
 *       Any subsequent lifecycle events coming from Activity A, such as onHostDestroy, will be
 *       ignored.
 *   <li>Navigating back from Activity B to Activity A will trigger the same events: B#onHostPause
 *       and A#onHostResume. Any subsequent events coming from Activity B, such as onHostDestroy,
 *       are ignored.
 *   <li>Navigating back from Activity A to a non-React Activity or to the home screen will trigger
 *       two events: onHostPause and onHostDestroy.
 *   <li>Navigating from Activity A to a non-React Activity B will trigger one event: onHostPause.
 *       Later, if Activity A is destroyed (e.g. because of resource contention), onHostDestroy is
 *       triggered.
 * </ol>
 */
public interface LifecycleEventListener {

  /**
   * Called either when the host activity receives a resume event (e.g. {@link Activity#onResume} or
   * if the native module that implements this is initialized while the host activity is already
   * resumed. Always called for the most current activity.
   */
  void onHostResume();

  /**
   * Called when host activity receives pause event (e.g. {@link Activity#onPause}. Always called
   * for the most current activity.
   */
  void onHostPause();

  /**
   * Called when host activity receives destroy event (e.g. {@link Activity#onDestroy}. Only called
   * for the last React activity to be destroyed.
   */
  void onHostDestroy();
}

These API are Java API, so a native java/kotlin module need to be developped to subscribe to theses events

So how to transmit these notifications to our react-native js code?

It will be a pitty to do polling, will lost all the benefice to do publish subscribe on the android side.

Another react-native api is to our rescue:

We forked the project react-native-file-intent. We add the following enhancments:

  • return the content uri
  • have a "publush subscribe " API to receive share event.

Native code

Here the corresponding native code permitting to notify intent

public RNFileShareIntentModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
    reactContext.addActivityEventListener(this);
    reactContext.addLifecycleEventListener(this);
  }

  @Override
  public void onNewIntent(Intent aIntent) {
    /* if all processing is made on onNewIntent, that not works on the second call when application in background */

    if (mIntent == null) {
      mIntent = aIntent;
    }
  }

  @Override
  public void onHostResume() {
    Intent aIntent =  mIntent;

    if (mIntent != null) {
      mIntent = null;
      shareFile(aIntent);
    }
  }

  @Override
  public void onHostPause() {
  }

  @Override
  public void onHostDestroy() {
  }

...




We choice two:
* polling the corresponding activity to see if there is an intent
* receive intents from activities notification 

Activities notifications are not received on the application when the application is close. So we need to do polling in that case.

Clone this wiki locally