{"id":7869,"date":"2018-04-04T07:50:30","date_gmt":"2018-04-04T14:50:30","guid":{"rendered":"\/developerblog\/?p=7869"},"modified":"2020-03-14T17:07:23","modified_gmt":"2020-03-15T00:07:23","slug":"app-app-communication-react-native-android","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/app-app-communication-react-native-android\/","title":{"rendered":"App-to-app communication with React Native on Android"},"content":{"rendered":"<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">The <\/span><a href=\"http:\/\/ixo.foundation\/\">ixo Foundation<\/a><span style=\"color: #000000\">\u00a0was created to build a decentralized impact evaluation protocol using blockchain and the\u00a0<\/span><a href=\"https:\/\/w3c-ccg.github.io\/did-spec\/\">W3C decentralized identifier specification<\/a><span style=\"color: #000000\">. Impact, in this case, refers to impact investments, which are funding for projects that can make a <\/span><a href=\"http:\/\/www.socialimpactinvestment.org\/reports\/Measuring%20Impact%20WG%20paper%20FINAL.pdf\">measurable change<\/a><\/span><span style=\"color: #000000;font-family: Calibri\"> in society. Impact projects are based on the UN&#8217;s 17 <a href=\"https:\/\/sustainabledevelopment.un.org\/post2015\/transformingourworld\">Sustainable Development Goals<\/a>, including projects to eliminate hunger, improve education, supply clean water, and increase gender equality. One of the key challenges with impact projects is producing, measuring, and valuing impact data at scale, and this is what ixo aims to address with the ixo protocol.\u00a0<\/span><span style=\"font-family: Calibri\"><span style=\"color: #000000\">In addition to the protocol, ixo is also building sample apps and SDKs for interacting with the impact protocol on the blockchain. They developed a <\/span><a href=\"https:\/\/github.com\/ixofoundation\/ixo-web\">Web client<\/a><span style=\"color: #000000\"> in <\/span><a href=\"https:\/\/reactjs.org\/\">React.js<\/a><span style=\"color: #000000\"> and an <\/span><a href=\"https:\/\/github.com\/ixofoundation\/ixo-module\">SDK<\/a><span style=\"color: #000000\"> based on <\/span><a href=\"https:\/\/github.com\/ethjs\/ethjs\">ethjs<\/a><span style=\"color: #000000\"> to run using <\/span><a href=\"https:\/\/metamask.io\/\">MetaMask<\/a><span style=\"color: #000000\"> or any other DApps (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Decentralized_application\">Decentralized Application<\/a>) browser. <\/span><\/span><\/p>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">We recently worked with ixo to develop a sample client in <\/span><a href=\"https:\/\/facebook.github.io\/react-native\/\">React Native,<\/a><\/span><span style=\"color: #000000;font-family: Calibri\">\u00a0with the goals of sharing as much code as possible with the Web client and investigating strategies to allow different organizations to set their own standards for signing impact project documents.<\/span><\/p>\n<p><!--more--><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: x-large\">Problem<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">When using a DApps browser like MetaMask, the user is already authenticated in the browser context. On mobile, ixo needed a way to store the user\u2019s decentralized identifier (DID) and a mechanism to sign impact projects and verifications. <\/span><\/p>\n<p><span style=\"color: #000000;font-family: Calibri\">One of ixo\u2019s use cases is to support multiple cryptographic signing algorithms and to allow different organizations to set their own standards for what and how an impact project or verification is signed. The approach to this use case that we investigated was to separate the impact project creation and verification app (henceforth, the <em>impact app<\/em>) from the signing app, so organizations would be allowed to publish their own signing apps with their own standards.<\/span><\/p>\n<p><span style=\"color: #000000;font-family: Calibri\">ixo chose React Native because they were already familiar with React.js, and they wanted to leverage their existing JavaScript SDK for managing DIDs and signing documents as much as possible. We needed to find a way to support app-to-app communication in React Native apps. Specifically, we needed to enable the impact app to send a JSON document to a signing app and await the signed response. While ixo does intend to eventually support Android and iOS, the first version of the app is only targeting Android.<\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: x-large\">Attempt #1: Linking Module<\/span><\/h2>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">Our first attempt at app-to-app communication was the <\/span><a href=\"https:\/\/facebook.github.io\/react-native\/docs\/linking.html\"><code>Linking<\/code> module<\/a><\/span><span style=\"color: #000000;font-family: Calibri\"> that already existed in the core React Native library. The benefit of this approach was that it was cross-platform out-of-the-box; iOS, Android, and even <a href=\"https:\/\/github.com\/Microsoft\/react-native-windows\">Windows 10<\/a>\u00a0support the Linking module. Our primary concern with this approach was that you are limited to sending data to other apps using URL parameters.<\/span><\/p>\n<pre class=\"lang:js decode:true\">Linking.openURL(url).catch(err =&gt; console.error('An error occurred', err));<\/pre>\n<p><span style=\"color: #000000;font-family: Calibri\">For the impact app to send the JSON document to a signing app using the <code>Linking<\/code> module, we\u2019d have to URL encode the JSON document and send it as a URL parameter. Before we did this, we checked for any limitations on the number of characters that could be used in a URL for the <code>Linking<\/code> module and found that, on Android, the limit was between 100K and 200K characters. While this limit may have been reasonable for most JSON documents, ixo did not want to impose an arbitrary limit on the length of data being signed.<\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: x-large\">Solution: Custom Native Modules for Android<\/span><\/h2>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">While looking at the <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/modules\/intent\/IntentModule.java\">native implementation<\/a><span style=\"color: #000000\"> of the <code>Linking<\/code> module on Android, we discovered that the <code>Linking<\/code> module only supports triggering new activities using the <\/span><a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity.html#startActivity(android.content.Intent)\"><code>Activity.startActivity<\/code> API<\/a><span style=\"color: #000000\">. What we really wanted to use was the <\/span><a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity.html#startActivityForResult(android.content.Intent, int, android.os.Bundle)\"><code>Activity.startActivityForResult<\/code> API<\/a><span style=\"color: #000000\">, which supported getting a response back when the launched activity finished. Since React Native does not have any core modules for invoking this API, we had to create our own custom native module, which we called <code>StartActivityModule<\/code>. Snippets of the <code>StartActivityModule<\/code> are provided throughout this section, but you can find the full implementation on <\/span><a href=\"https:\/\/github.com\/ixofoundation\/ixo-mobile\/blob\/master\/android\/app\/src\/main\/java\/com\/ixomobile\/StartActivityModule.java\">GitHub<\/a><\/span><span style=\"color: #000000;font-family: Calibri\">.<\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Starting an Activity from React Native Android<\/span><\/h2>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">To create a native module for React Native on Android, you need to create a new class that implements the <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/NativeModule.java\"><code>NativeModule<\/code> interface<\/a><span style=\"color: #000000\">. It\u2019s rare that you implement this interface directly, as React Native also provides a few useful base classes, including <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/BaseJavaModule.java\"><code>BaseJavaModule<\/code><\/a><span style=\"color: #000000\"> and <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/ReactContextBaseJavaModule.java\"><code>ReactContextBaseJavaModule<\/code><\/a><\/span><span style=\"color: #000000;font-family: Calibri\">. In this case of <code>StartActivityModule<\/code>, we chose the abstract <code>ReactContextBaseJavaModule<\/code> because we required access to the <code>ReactContext<\/code> inside the module. To derive from <code>ReactContextBaseJavaModule<\/code>, you must supply an implementation for the <code>getName<\/code> method and a constructor that takes the <code>ReactApplicationContext<\/code> as a parameter.<\/span><\/p>\n<pre class=\"lang:java decode:true\">public class StartActivityModule extends ReactContextBaseJavaModule implements ActivityEventListener {\r\n\r\n  private final SparseArray&lt;Promise&gt; mPromises;\r\n\r\n  public StartActivityModule(ReactApplicationContext reactContext) {\r\n    super(reactContext);\r\n    mPromises = new SparseArray&lt;&gt;();\r\n  }\r\n\r\n  @Override\r\n  public String getName() {\r\n    return \"StartActivity\";\r\n  }\r\n}<\/pre>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">To add a native method that gets exposed to JavaScript, use the <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/ReactMethod.java\"><code>ReactMethod<\/code> attribute<\/a><span style=\"color: #000000\">. The method must be void-returning, and parameters can only use:<\/span><\/span><\/p>\n<ul>\n<li><span style=\"font-family: Calibri\"><span style=\"color: #000000\"> a few primitive types, i.e., strings, ints, doubles, bools, etc.<\/span><\/span><\/li>\n<li><span style=\"font-family: Calibri\"><span style=\"color: #000000\">the JSON array data model type,\u00a0<\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/ReadableArray.java\"><code>ReadableArray<\/code><\/a><\/span><\/li>\n<li><span style=\"font-family: Calibri\"><span style=\"color: #000000\">the JSON object data model type,\u00a0<\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/ReadableMap.java\"><code>ReadableMap<\/code><\/a><\/span><\/li>\n<li><span style=\"font-family: Calibri\"><span style=\"color: #000000\">React Native specific types that represent callbacks,\u00a0<\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/Callback.java\"><code>Callback<\/code><\/a>,\u00a0<span style=\"color: #000000\">and promises,\u00a0<\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/Promise.java\"><code>Promise<\/code><\/a><\/span><\/li>\n<\/ul>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">More information about implementing native modules for React Native Android can be found in the <\/span><a href=\"https:\/\/facebook.github.io\/react-native\/docs\/native-modules-android.html\">documentation<\/a><\/span><span style=\"color: #000000;font-family: Calibri\">.<\/span><\/p>\n<p><span style=\"color: #000000;font-family: Calibri\">The method we use to expose <code>Activity.startActivityForResult<\/code> in <code>StartActivityModule<\/code> is below. It takes four parameters: <code>requestCode<\/code>, a unique request ID; <code>action<\/code>, the name of the Android intent (henceforth, just <em>intent<\/em>) to call; <code>data<\/code>, the JSON data to pass via the intent extra data; and <code>promise<\/code>, a promise to resolve once an activity result matching the <code>requestCode<\/code> is triggered. We store the\u00a0<code>promise<\/code>\u00a0parameter in a\u00a0<code>SparseArray<\/code>\u00a0(the\u00a0<code>mPromises<\/code>\u00a0field from the class stub above) so that it can be looked up later to resolve the promise.\u00a0\u00a0<\/span><\/p>\n<pre class=\"lang:java decode:true\">@ReactMethod\r\npublic void startActivityForResult(int requestCode, String action, ReadableMap data, Promise promise) {\r\n  Activity activity = getReactApplicationContext().getCurrentActivity();\r\n  Intent intent = new Intent(action);\r\n  intent.putExtras(Arguments.toBundle(data));\r\n  activity.startActivityForResult(intent, requestCode);\r\n  mPromises.put(requestCode, promise);\r\n}<\/pre>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">Part of the problem was packaging the JSON document for signing in a way that it could be passed along with the intent. As it turns out, there is a very useful helper called <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/Arguments.java\"><code>Arguments<\/code><\/a><span style=\"color: #000000\"> inside React Native for converting React Native\u2019s Java representation of a JSON object to an Android <\/span><a href=\"https:\/\/developer.android.com\/reference\/android\/os\/Bundle.html\"><code>Bundle<\/code><\/a><\/span><span style=\"color: #000000;font-family: Calibri\">.<\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Listening for Activity results in React Native Android<\/span><\/h2>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">We also needed a way to resolve the promise we generated for the <code>startActivityForResults<\/code> call. Typically, to listen for results from activities triggered by your Android app, you need to override the <code>onActivityResult<\/code> method on your main activity. However, the base class for the <code>MainActivity<\/code> in a React Native Android project already overrides these methods to expose a much simpler mechanism for subscribing to these notifications in native modules, via the <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/bridge\/ActivityEventListener.java\"><code>ActivityEventListener<\/code> interface<\/a><span style=\"color: #000000\">. Once you add the <code>ActivityEventListener<\/code> interface to your native module, you can add the logic you would have added to your main activity directly in the native module. You also need to register your <code>ActivityEventListener<\/code> implementation with the <code>ReactContext<\/code>, which is typically done through the <code>NativeModule<\/code> <code>initialize<\/code> and <code>onCatalystInstanceDestroy<\/code> lifecycle methods. This is also outlined in the <\/span><a href=\"https:\/\/facebook.github.io\/react-native\/docs\/native-modules-android.html#getting-activity-result-from-startactivityforresult\">React Native documentation<\/a><\/span><span style=\"color: #000000;font-family: Calibri\">.<\/span><\/p>\n<pre class=\"lang:java decode:true\">@Override\r\npublic void initialize() {\r\n  super.initialize();\r\n  getReactApplicationContext().addActivityEventListener(this);\r\n}\r\n\r\n@Override\r\npublic void onCatalystInstanceDestroy() {\r\n  super.onCatalystInstanceDestroy();\r\n  getReactApplicationContext().removeActivityEventListener(this);\r\n}<\/pre>\n<p><span style=\"color: #000000;font-family: Calibri\">In the case of the <code>StartActivityModule<\/code>, when we get an <code>onActivityResult<\/code> callback from the <code>ActivityEventListener<\/code> interface, we look up the provided <code>requestCode<\/code> in the map of pending promises. If we find a match, we resolve the promise with the converted data from the intent extra data <code>Bundle<\/code> (again using the <code>Arguments<\/code> helpers from React Native).<\/span><\/p>\n<pre class=\"lang:java decode:true\">@Override\r\npublic void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {\r\n  Promise promise = mPromises.get(requestCode);\r\n  if (promise != null) {\r\n    WritableMap result = new WritableNativeMap();\r\n    result.putInt(\"resultCode\", resultCode);\r\n    result.putMap(\"data\", Arguments.makeNativeMap(data.getExtras()));\r\n    promise.resolve(result);\r\n  }\r\n}<\/pre>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Checking for Intent handling app<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">We needed a mechanism to alert the user to install the signing app if it had not yet been installed on the same device. Without such a check, the\u00a0<code>startActivityForResult<\/code> call would result in an exception, as no handler for the custom intent would have been registered. To implement this, we exposed an additional <code>ReactMethod<\/code> called <code>resolveActivity<\/code>, which allows us to check if there is an\u00a0app on the device registered to handle the intent. If the result of the\u00a0<code>resolveActivity<\/code>\u00a0call is null, we can trigger an alert from JavaScript, and potentially display a link to install the required app from.<\/span><\/p>\n<pre class=\"lang:java decode:true\">@ReactMethod\r\npublic void resolveActivity(String action, Promise promise) {\r\n  Activity activity = getReactApplicationContext().getCurrentActivity();\r\n  Intent intent = new Intent(action);\r\n  ComponentName componentName = intent.resolveActivity(activity.getPackageManager());\r\n  if (componentName == null) {\r\n    promise.resolve(null);\r\n    return;\r\n  }\r\n\r\n  WritableMap map = new WritableNativeMap();\r\n  map.putString(\"class\", componentName.getClassName());\r\n  map.putString(\"package\", componentName.getPackageName());\r\n  promise.resolve(map);\r\n}<\/pre>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Exposing the native module to React Native JavaScript<\/span><\/h2>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">React Native Android uses the <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/ReactPackage.java\"><code>ReactPackage<\/code> interface<\/a><span style=\"color: #000000\"> to bundle together related native modules in a plugin. The <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/1490ab12ef156bf3201882eeabfcac18a1210352\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/ReactNativeHost.java\"><code>ReactNativeHost<\/code><\/a><span style=\"color: #000000\">, configured in the <code>MainActivity.java<\/code> file generated by the React Native CLI, returns a list of <code>ReactPackage<\/code> instances that are used to configure the native modules exposed to JavaScript. For the impact app, we bundled the <code>StartActivityModule<\/code> into a simple package called <\/span><a href=\"https:\/\/github.com\/ixofoundation\/ixo-mobile\/blob\/a8a0b061111b233e614a578dd13590e50fac5907\/android\/app\/src\/main\/java\/com\/ixomobile\/IxoMobileReactPackage.java\"><code>IxoMobileReactPackage<\/code><\/a><\/span><span style=\"color: #000000;font-family: Calibri\">, which we added to the <code>MainApplication.java<\/code> file for the project. <\/span><\/p>\n<pre class=\"lang:java decode:true\">public class IxoMobileReactPackage implements ReactPackage {\r\n  @Override\r\n  public List&lt;NativeModule&gt; createNativeModules(ReactApplicationContext reactContext) {\r\n    return Arrays.&lt;NativeModule&gt;asList(\r\n      new StartActivityModule(reactContext)\r\n    );\r\n  }\r\n\r\n  @Override\r\n  public List&lt;ViewManager&gt; createViewManagers(ReactApplicationContext reactContext) {\r\n    return Collections.emptyList();\r\n  }\r\n}\r\n\r\npublic class MainApplication extends Application implements ReactApplication {\r\n\r\n  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {\r\n    \/* ... *\/\r\n\r\n    @Override\r\n    protected List&lt;ReactPackage&gt; getPackages() {\r\n      return Arrays.&lt;ReactPackage&gt;asList(\r\n        new MainReactPackage(),\r\n        new IxoMobileReactPackage()\r\n      );\r\n    }\r\n\r\n    \/* ... *\/\r\n}<\/pre>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Invoking the native method from JavaScript<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">Once the app is configured to expose the native module and its methods to JavaScript, it is added to the <code>NativeModules<\/code> JavaScript module in React Native. Since we included the <code>Promise<\/code> parameter as the last parameter to our native method, React Native automatically returns a JavaScript promise when the method is called, so we can invoke the native method for <code>startActivityForResults<\/code> using async\/await, or your pattern of choice for handling promises, as follows:<\/span><\/p>\n<pre class=\"lang:js decode:true\">import {\r\n  NativeModules\r\n} from 'react-native';\r\n\r\nlet requestCode = 0;\r\n\r\nasync function startActivityForResult(intent, extraData) {\r\n  const { StartActivity } = NativeModules;\r\n  const componentName = await StartActivity.resolveActivity(intent);\r\n  if (!componentName) {\r\n    \/\/ You could also display a dialog with the link to the app store.\r\n    throw new Error(`Cannot resolve activity for intent ${intent}. Did you install the app?`);\r\n  }\r\n\r\n  const response = await StartActivity.startActivityForResult(\r\n    ++requestCode,\r\n    action,\r\n    extraData);\r\n\r\n  if (response.resultCode !== StartActivity.OK) {\r\n    throw new Error('Invalid result from child activity.');\r\n  }\r\n\r\n  return response.data;\r\n};\r\n\r\nexport default startActivityForResult;<\/pre>\n<p><span style=\"color: #000000;font-family: Calibri\">In the case of the impact app, after the signing app does its work, the promise resolves with the signed JSON document, and the continuation after the <code>await<\/code> in the above code resumes execution. <\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: x-large\">Solution: Receiving the Intent on React Native Android<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">Both the sample impact app and the signing app were being written in React Native. We needed a mechanism to listen for the custom intent generated from the impact app in the signing app and pass the JSON document to be signed to the JavaScript runtime.<\/span><\/p>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">We created a custom <\/span><a href=\"https:\/\/github.com\/facebook\/react-native\/blob\/master\/ReactAndroid\/src\/main\/java\/com\/facebook\/react\/ReactActivityDelegate.java\"><code>ReactActivityDelegate<\/code><\/a><\/span><span style=\"color: #000000;font-family: Calibri\"> implementation for our app that stored the <code>Bundle<\/code> from the main activity intent and returned that value for in the overridden <code>getLaunchOptions<\/code> method. The value returned from <code>getLaunchOptions<\/code> is converted into a JSON object and provided to the root level React component as props.<\/span><\/p>\n<pre class=\"lang:java decode:true\">public class MainActivity extends ReactActivity {\r\n\r\n  \/* ... *\/\r\n\r\n  @Override\r\n  protected ReactActivityDelegate createReactActivityDelegate() {\r\n    return new InitialPropsReactActivityDelegate(this, getMainComponentName());\r\n  }\r\n\r\n  public static class InitialPropsReactActivityDelegate extends ReactActivityDelegate {\r\n    private final @Nullable Activity mActivity;\r\n    private @Nullable Bundle mInitialProps;\r\n\r\n    public InitialPropsReactActivityDelegate(Activity activity, String mainComponentName) {\r\n      super(activity, mainComponentName);\r\n      this.mActivity = activity;\r\n    }\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n      mInitialProps = mActivity.getIntent().getExtras();\r\n      super.onCreate(savedInstanceState);\r\n    }\r\n\r\n    @Override\r\n    protected Bundle getLaunchOptions() {\r\n      return mInitialProps;\r\n    }\r\n  }\r\n}<\/pre>\n<p><span style=\"color: #000000;font-family: Calibri\">In the case of the ixo signing app, the root level props include a <code>content<\/code> prop, which we can use to decide if the purpose of the app running is to sign a JSON document. When the <code>content<\/code> prop is set, the app asks the user to confirm the contents of the JSON document to be signed and validate their identity via a fingerprint or PIN code. The app then proceeds to sign the JSON document and return the signed JSON to the calling app.<\/span><\/p>\n<p><span style=\"font-family: Calibri\"><span style=\"color: #000000\">To return results for an activity in Android, the app needs to call <\/span><a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity.html#setResult(int, android.content.Intent)\"><code>Activity.setResult<\/code><\/a><span style=\"color: #000000\"> and then <\/span><a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity.html#finish()\"><code>Activity.finish<\/code><\/a><span style=\"color: #000000\">. There is currently no native module for invoking this API in React Native, so, using the same approach we described for creating a native module in the impact app, we created a native module called <code>ActivityCompletionModule<\/code> to expose this API. Below is the <code>ReactMethod<\/code> implementation, and the full native module implementation can be found on <\/span><a href=\"https:\/\/github.com\/ixofoundation\/ixo-sign\/blob\/master\/android\/app\/src\/main\/java\/com\/ixosign\/ActivityCompletionModule.java\">GitHub<\/a><\/span><span style=\"color: #000000;font-family: Calibri\">.<\/span><\/p>\n<pre class=\"lang:java decode:true\">public class ActivityCompletionModule extends ReactContextBaseJavaModule {\r\n\r\n  public ActivityCompletionModule(ReactApplicationContext reactContext) {\r\n    super(reactContext);\r\n  }\r\n\r\n  @Override\r\n  public String getName() {\r\n    return \"ActivityCompletion\";\r\n  }\r\n\r\n  @ReactMethod\r\n  public void finish(int result, String action, ReadableMap map) {\r\n    Activity activity = getReactApplicationContext().getCurrentActivity();\r\n    Intent intent = new Intent(action);\r\n    intent.putExtras(Arguments.toBundle(map));\r\n    activity.setResult(result, intent);\r\n    activity.finish();\r\n  }\r\n}<\/pre>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: large\">Alternate Approach: Reading Intent Bundle from native module<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">We decided to pass the JSON document to be signed through the <code>getLaunchOptions<\/code> method in <code>ReactActivityDelegate<\/code>, but we could have just as easily created another native module to check the original intent at a later point after the React Native app had initialized. The reason we chose not to do this was that JavaScript in React Native runs on a separate thread from the native modules and UI main thread, and any communication to the native layer is asynchronous. Passing the JSON document to JavaScript in this way would have created the need for a loading dialog or activity indicator of some sort, while we waited for the asynchronous native module calls.<\/span><\/p>\n<h2><span style=\"color: #2f5496;font-family: Calibri Light;font-size: x-large\">Conclusion<\/span><\/h2>\n<p><span style=\"color: #000000;font-family: Calibri\">We worked with ixo not only to unblock the usage of their SDK for signing impact documents in React Native but also to implement the impact project management and signing behaviors in separate apps on Android, using custom native modules for React Native. Once ixo starts to develop and test the app for iOS and Windows 10, there is remaining work to implement the app-to-app communication modules for those platforms. <\/span><\/p>\n<p><span style=\"color: #000000;font-family: Calibri\">The pattern we applied for app-to-app communication between the project management and signing apps can be generalized to any app-to-app communication scenario for React Native Android. In fact, we merged the native modules described above for the\u00a0<code>startActivityForResults<\/code> and <code>finish<\/code>\u00a0native methods in a single React Native plugin, <a href=\"https:\/\/www.npmjs.com\/package\/react-native-activity-result\">react-native-activity-result<\/a>. The README includes instructions for getting started with the module, which you can easily install from NPM and add to your React Native Android app using the <code>react-native link<\/code>\u00a0command. Any feedback or issues with using the plugin or anything described in this code story can be filed on <a href=\"https:\/\/github.com\/rozele\/react-native-activity-result\">GitHub<\/a>.<\/span><\/p>\n<p><span style=\"color: #000000;font-family: Calibri\">ixo also created a declarative representation of impact form templates using <a href=\"https:\/\/json-ld.org\/\">JSON-LD<\/a> that they use to dynamically render form entry UI on their Web app. We helped them re-implement the form module from React.js to ReactXP so the UI code, and any improvements or maintenance to it, could be shared across their Web and mobile apps. You can learn more about this work from another one of our code stories (coming soon!).<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The ixo Foundation is building a decentralized impact evaluation protocol using blockchain and W3C decentralized identifier specification. We worked with them to develop a sample client in React Native, including a native Android plugin for app-to-app communication.<\/p>\n","protected":false},"author":21361,"featured_media":10777,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[12,17],"tags":[42,259,306],"class_list":["post-7869","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blockchain","category-frameworks","tag-android","tag-mobile","tag-react-native"],"acf":[],"blog_post_summary":"<p>The ixo Foundation is building a decentralized impact evaluation protocol using blockchain and W3C decentralized identifier specification. We worked with them to develop a sample client in React Native, including a native Android plugin for app-to-app communication.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/7869","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21361"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=7869"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/7869\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/10777"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=7869"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=7869"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=7869"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}