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 runyarn publish
. Assuming this publishes version 1.0.0 ofern-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 theandroid
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 thefindItems
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 changepluginConfig
configuration for theroot
folder for android to remove/lib
at the end. Otherwise,ern run-android
fails with a folder missing error when theern-helloworld-api-impl-native
is added to temp1-miniapp. -
Run
yarn publish
fromern-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/
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);
}