Skip to content

Instantly share code, notes, and snippets.

@hemanth-manoharan
Last active January 23, 2021 02:16
Show Gist options
  • Save hemanth-manoharan/ed223d9c53804dab72b1e485f31aa82d to your computer and use it in GitHub Desktop.
Save hemanth-manoharan/ed223d9c53804dab72b1e485f31aa82d to your computer and use it in GitHub Desktop.
Tutorial #4: Mini-app to outer app communication

Tutorial #4: Mini-app to outer app communication

This post is the 4th one in a series of posts on Electrode Native.

It assumes that one has already completed the steps in Tutorial #3 here - https://gist.github.com/hemanth-manoharan/5460456f019faae2678776427f879bac

In this tutorial, we are going to demonstrate how to communicate between the JS code in the mini-app and the native code in the outer app. We will be using the concept of Electrode Native APIs for the same.

Ref: https://native.electrode.io/introduction/what-is-ern/js-native-communication

  • Create the API definition. Ensure that you choose an unique api name since we will be publishing the same to npm. The following command will generate an API with the name ern-helloworld-api

ern create-api ern-helloworld

  • Change directory into the generated ern-helloworld-api folder and run yarn publish. Assuming this publishes version 1.0.0 of ern-helloworld-api

  • Create the API implementation project. We are going to implement it in native code specifically for android.

ern create-api-impl ern-helloworld-api -n

  • The generated scaffolding for the implementation project will be in the folder ern-helloworld-api-impl-native

  • Change directory into the generated ern-helloworld-api-impl-native folder and open the android sub-folder in Android Studio.

  • Open the file lib/src/main/java/com/ern/api/impl/WalmartItemApiRequestHandlerProvider.java

  • Replace the function definition for registerFindItemsRequestHandler as follows. We are implementing only the findItems function for now.

    @Override
    public void registerFindItemsRequestHandler() {
        WalmartItemApi.requests().registerFindItemsRequestHandler(new ElectrodeBridgeRequestHandler<Integer, List<Item>>() {
            @Override
            public void onRequest(Integer payload, ElectrodeBridgeResponseListener<List<Item>> responseListener) {
                List<Item> items = new ArrayList<Item>() {{
                    add(new Item.Builder((long) 1, "iPhone 11").build());
                    add(new Item.Builder((long) 2, "iPhone 12").build());
                }};
                responseListener.onSuccess(items);
            }
        });
    }
  • Important Note: Potential fix needed in Electrode Native native implementation generator. In package.json, need to change pluginConfig configuration for the root folder for android to remove /lib at the end. Otherwise, ern run-android fails with a folder missing error when the ern-helloworld-api-impl-native is added to temp1-miniapp.

  • Run yarn publish from ern-helloworld-api-impl-native folder

  • Now, add the API and the implementation dependencies to the temp1-miniapp

cd temp1-miniapp
ern add [email protected]
ern add [email protected]
  • Update version in package.json for temp1-miniapp and publish the same to npm.

yarn publish

  • Now, add the updated miniapp to the cauldron and create a container. Then, build the updated aar and embed the same into the outer app. This is so that the new native dependency (the api implementation) is available to the app.
ern cauldron update miniapps [email protected] -d ErnOuterApp:android:0.0.1 -v 1.0.3
ern create-container -d ErnOuterApp:android:0.0.1 -p android
  • Then, invoke the new API inside temp1-miniapp and render the output inside the same. Some relevant snippets to add to App.js is listed below.
import { WalmartItemApi } from 'ern-helloworld-api';

...
  
  _keyExtractor = (item) => item.id;
  
  constructor() {
    super();

    WalmartItemApi.requests().findItems(100, 500).then((items) => {
      if (items) {
        this.setState(previousState => {
          return {items};
        });
      }
    }).catch(error => {
      let items = [{
        id: 1,
        name: "Mi A2"
      }, {
        id: 2,
        name: "Mi A3"
      }];

      this.setState(previousState => {
        return {items};
      });
    });

    this.state = {
      items: []
    };
  }

...

    <FlatList
      style={styles.listContainer}
      data={this.state.items}
      keyExtractor={this._keyExtractor}
      renderItem={({item}) =>
        <View style={styles.listRow}>
          <Text style={styles.itemId}>{item.id}</Text>
          <Text style={styles.itemName}>{item.name}</Text>
        </View>
      }
    />

...

  listContainer: {
    flex: 1,
    marginTop: 20,
    padding: 5,
    backgroundColor: 'black'
  },
  listRow: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    backgroundColor: 'white',
    padding: 12
  },
  itemId: {
    fontSize: 20,
  },
  itemName: {
    paddingTop: 5,
    flex: 1,
    fontSize: 12
  },
  
...
  • Update version in package.json for temp1-miniapp and publish the same to npm.

  • Publish a new version of temp1-miniapp via an OTA update as explained in the previous blog post.

ern cauldron update miniapps [email protected] -d ErnOuterApp:android:0.0.1 -v 1.0.4
ERN_LOG_LEVEL=debug ern code-push release --miniapps [email protected] -d ErnOuterApp:android:0.0.1 --deploymentName Staging
appcenter codepush release -a hemanth-aero-pmdp/ErnOuterAppAndroid -c TEMP_FOLDER_PATH/bundleOut -t 0.0.1 -d Staging
  • Finally, run the outer android app to see if the results from the API are displayed.

  • Now, let's also see how to invoke the same API from the outer app. This is very much similar to the way we did it in JavaScript. In MainActivity.java of the outer app, perform the following changes.


import com.ernhelloworld.ern.api.WalmartItemApi;

...

WalmartItemApi.requests().findItems(100, new ElectrodeBridgeResponseListener<List<Item>>() {
    @Override
    public void onSuccess(@Nullable List<Item> items) {
        System.out.println("findItems API call successful!");
        System.out.println(items);
    }
    @Override
    public void onFailure(@NonNull FailureMessage failureMessage) {
        System.out.println("findItems API call failed!");
        System.out.println(failureMessage);
    }
});

  • Now, run the app and check if the API call output is displayed in the console logs.

  • In the next article, we will explore the use of ern-navigation API for back-button script logic.

Ref: https://www.electrode.io/ern-navigation/

Appendix

Electrode Native code-base - AndroidGenerator.ts

The following snippet expects that the path for relPathToApiImplSource starts with lib. Hence, the corresponding root path in the package.json should exclude the lib part.

if (await coreUtils.isDependencyPathNativeApiImpl(pluginSourcePath)) {
  // Special handling for native api implementation as we don't
  // want to copy the API and bridge code (part of native api implementations projects)
  const relPathToApiImplSource = path.normalize(
    'lib/src/main/java/com/ern',
  );
  const absPathToCopyPluginSourceTo = path.join(
    config.outDir,
    'lib/src/main/java/com',
  );
  shell.cp('-R', relPathToApiImplSource, absPathToCopyPluginSourceTo);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment