Tutorial #1: How to create a mini app in Electrode Native and embed it within an outer Android native app
This is the first in a series of posts around Electrode Native.
Was not able to directly find a "hello world" type of guide that demonstrates all the capabilities of Electrode Native - like mini-app packaging and OTA (Over-The-Air updates) in the documentation here - https://www.electrode.io/site/docs/getting_started.html
Hence, decided to write one as part of my journey. These posts are more focused on getting the code running than on explanation of the underlying concepts. For details on the concepts, please refer to the Electrode Native documentation directly.
Note: Electrode Native version at the time of writing this tutorial - v0.45.5
Note: The tutorial assumes a basic knowledge of Android development
- First, install Electrode Native with the following command
npm install -g electrode-native
- Then, create a folder for this tutorial say 'ern'. Change directory into the same and run the following command.
ern create-miniapp app1-miniapp
where app1-miniapp is the name of the mini app we are creating.
-
Now, start up the Android emulator.
-
Then, change directory into the app1-miniapp folder that has been created and run
ern run-android
-
By now, the mini-app should be running within the default Runner app provided by Electrode Native
-
Then, publish the mini app (Ref: https://classic.yarnpkg.com/en/docs/publishing-a-package/)
yarn login
yarn publish
Assuming the package/version is app1-miniapp@0.0.1
-
Now, let's create a sub-folder to hold the cauldron repository under the
ern
folder itself, where all the app metadata will be managed. Let's say it's calledern-outer-app-cauldron
-
Now, create the cauldron itself
ern cauldron repo add ern-outer-app <full path to local cauldron repository directory>
-
Then, create a basic hello-world Android app to be used as the outer wrapper native app in Android Studio. Let's assume its named ErnOuterApp
-
Now, add the same to the cauldron
ern cauldron add nativeapp ErnOuterApp:android:0.0.1
- Now, add the miniapp created earlier to the same cauldron
ern cauldron add miniapps app1-miniapp@0.0.1
- Then, lets create the container locally using the cauldron metadata.
ern create-container -d ErnOuterApp:android:0.0.1 -p android
-
Change directory to
~/.ern/containergen/out/android
. This directory contains the output of the previous commandcreate-container
-
Then, run the build
./gradlew build
-
The generated
.aar
file will be in thelib/build/outputs/aar
folder -
Now, add the .aar as a direct dependency in the native android app (ErnOuterApp) created earlier as explained below (Ref: https://stackoverflow.com/questions/16682847/how-to-manually-include-external-aar-package-using-new-gradle-android-build-syst)
-
Copy the
lib-debug.aar
file generated in the previous step into thelibs
folder underapp
module in ErnOuterApp. -
In the
build.gradle
file at the project level, make the following change to add aflatDir
in therepositories
list
allprojects { repositories { google() jcenter() flatDir { dirs 'libs' } } }
- In the
build.gradle
file at theapp
module level, add the following dependency
api(name:'lib-debug',ext:'aar')
- Continue on to the next step after verifying the build configuration at the link below
-
Then, initialize the library as explained below (Ref: https://native.electrode.io/reference/index-1/container-initialization)
-
Add the following code snippet in the
onCreate
method ofMainActivity
ElectrodeReactContainer.initialize(
getApplication() /* Application instance */,
new ElectrodeReactContainer.Config().isReactNativeDeveloperSupport(BuildConfig.DEBUG)
/* Additional plugins configuration here */);
- Add a button in
MainActivity
. In the button click handler, add the following snippet to launch the mini-app (Ref: https://native.electrode.io/reference/index-1/launching-miniapps)
Intent intent = new Intent(this, App1MiniappActivity.class);
startActivity(intent);
Note: The name of the Activity can be found in the AndroidManifest.xml
in the mini-app container repository that was published earlier.
-
Now, launch the app in Android Studio and verify that the mini-app launches on the button press.
-
Surprise! The
ElectrodeReactContainer
does not launch at this point. It fails with the following error.
java.lang.NoClassDefFoundError Failed resolution of lcom/facebook/soloader/SoLoader
-
This is because the core React-Native "native modules" are not part of the mini-app aar itself. They need to be added as a dependency of the outer app explicitly.
-
Hence, had to provide the required react-native modules to the outer android app namely,
ErnOuterApp
. The steps followed for the same below are a subset of the instructions at this link https://reactnative.dev/docs/integration-with-existing-apps
-
Create a new wrapper folder named
ernouterappwrapper
. -
Move the contents of the existing
ErnOuterApp
android project to anandroid
sub-folder underernouterappwrapper
-
At the root directory of the
ernouterappwrapper
wrapper folder - create apackage.json
file with the following content
{
"name": "ernouterappwrapper",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
- Then, run the following
yarn
commands in theernouterappwrapper
folder to add react and react-native packages to the same.
yarn add react-native
yarn add react@16.13.1
The version used for react in the 2nd command is based on a warning that will have been printed for the first command like the following
warning "react-native@x.x.x" has unmet peer dependency "react@y.y.y".
- Now, add the React Native dependency in the
build.gradle
file in the app module in theErnOuterApp
android app
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
...
implementation "com.facebook.react:react-native:+" // From node_modules
api(name:'lib-debug',ext:'aar')
...
}
- Add an entry for the local React Native directorie to the top-level
build.gradle
. Be sure to add it to the “allprojects” block, above other maven repositories so that it looks as follows.
allprojects {
repositories {
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
google()
jcenter()
flatDir {
dirs 'libs'
}
}
}
- Enable native modules autolinking (Ref: https://reactnative.dev/docs/integration-with-existing-apps#enable-native-modules-autolinking)
To use the power of autolinking, we have to apply it a few places. First add the following entry to settings.gradle:
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
Next add the following entry at the very bottom of the app/build.gradle:
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
- Finally, modify the following code snippet in the
onCreate
method ofMainActivity
to remove theisReactNativeDeveloperSupport
setting so that it renders the content of the mini app directly.
ElectrodeReactContainer.initialize(
getApplication() /* Application instance */,
new ElectrodeReactContainer.Config()
/* Additional plugins configuration here */);
- Finally, launch the app in Android Studio and verify that the mini-app launches on the button press as expected.
Also, needed to add the following dependencies in the app's build.gradle file if we get the error "Cannot resolve symbol 'ViewModelProviders'"
implementation "android.arch.lifecycle:livedata:1.1.0"
implementation "android.arch.lifecycle:viewmodel:1.1.0"
implementation "android.arch.lifecycle:extensions:1.1.0"