All about Electrode Native

Apurv Pandey
22 min readDec 14, 2020

--

If you have heard about Electrode Native and curious about it or planning to use Electrode Native in your project then you must read this blog before you proceed any further. This blog provides all the details about Electrode Native, its components, implementation details, when to use Electrode Native, advantages and disadvantages of Electrode Native. This blog will help you make the correct decision by providing correct details.

Electrode Native is a platform based on React Native. It simplifies the development and reduces the complication of integrating React Native components into existing (single and native) mobile applications. All this with minimal changes to the existing mobile code base and infrastructure. So with this, developers can work seamlessly on cross-platform components written in JavaScript using React Native — that can then be added to any iOS or Android mobile application. At its core, Electrode Native is made for integrating into an existing native mobile app.

The core of the Electrode Native is written in TypeScript and ES6. Some parts also contain native code : Java and Swift — mostly in the form of Mustache templates used for native code generation. In addition to React Native, it has its own local version of other tools such as Yarn and CodePush. It runs on Node 6 runtime or newer versions. In addition to Mac OS, it also runs on Linux & Windows; however only minimal testing has verified this support. Talking about platform code percentage of JavaScript code versus Native code, a good approximation would be 70% JavaScript and 30% native code.

Electrode Native was released by Walmart Labs in 2017. It was a solution to take their existing apps and slowly migrate parts of their code to React Native, which was later open sourced.

Electrode Native CLI

The Electrode Native CLI is a command line tool that contains the commands and subcommands that developers can use to work with the Electrode Native platform. The commands are very similar to React Native commands. However, if developers are working only on the mobile application, they may not need to use the Electrode Native CLI at all.

Electrode Native Bridge

This is a cross-platform, low-level bi-directional communication library used to simplify the communication process between the native mobile application and JavaScript. This is a standalone native module and not a part of the Electrode Native platform . It is actually a React Native native module and it contains some JavaScript code as well as iOS and Android platform code. In terms of code sizing, most of the Electrode Native bridge code is native (95% native & 5% JavaScript).

We can use it without Electrode Native. However, if we are using Electrode Native, we’ll not directly interact with the Electrode Native bridge in our mobile applications or “mini apps”. Instead, we’ll use Electrode Native APIs which are generated from a Swagger schema.

APIs

In order for our mini apps to interact with our mobile application or vice-versa, we need some form of APIs and that’s where Electrode Native APIs generation come into play. Powered by the [Electrode Native Bridge] and automatically generated by Electrode Native from a Swagger schema of our own, Electrode Native APIs provide clearly defined methods of communication between the native Android or iOS side and the JavaScript side. Using a Swagger schema, we can define interactions between JavaScript and native as requests and/or events. Electrode Native takes care of generating all the native and JavaScript boilerplate code for us.

There are two components to Electrode Native APIs: the API module itself and the API implementation.

Container

The Electrode Native container is a native library similar to other common native third-party libraries available in the market. The Electrode Native platform takes care of generating the container and packages it as an Android (AAR) library for Android and as a Framework for iOS.

The container includes the code for Electrode Native engine initialisation as well as all the JavaScript React Native MiniApps(described below) that we want to include in our mobile application — along with all their native dependencies and assets. Each mobile application will have its own custom Electrode Native container.

Cauldron

A Cauldron is like a centralised document database that is used to store information about mobile application versions, native dependencies, and information about MiniApps(described below). Each application has its own Cauldron. So for each mobile application version, there will be a corresponding entry in the cauldron database. For example, Walmart iOS 17.14 or Walmart Android 17.10.0. With appropriate permissions, we can use the Electrode Native CLI commands to access and modify the data stored in a Cauldron.

It doesn’t come with the downside of having to install and set it up on a dedicated box, as it is just hosted in a git repository. Setting up a cauldron is is similar to creating a Git repository and storing the data in the repository. To host our cauldron, we can use any provider offering Git repository storage. However, unlike the manifest(described below), the cauldron should not be updated manually. The cauldron should only be accessed and updated using the ern cauldron subcommands. The cauldron repository will be our own, as a cauldron is bound to a mobile application.

The cauldron document ( which is actually a single JSON document: cauldron.json) could contain information like:

  • A list of all the MiniApps (and their versions) that are part of any given version of our mobile application(s)
  • A list of all native dependencies (and their versions) used by these MiniApps
  • Data pertaining to a specific mobile application version including all MiniApps (and their versions) that are currently part of it.
  • One record for each mobile application version.

Each MiniApp that needs to be added to our mobile application should be first added to Cauldron. In addition to keeping track of what is included in our mobile application versions, it also acts as a “gatekeeper” to verify native dependencies versions before adding a MiniApp version to a Container (or deliver it through an OTA update).

Because the cauldron verifies which MiniApps versions and native dependencies versions are part of any given mobile application version, it can perform necessary version control checks whenever a MiniApp needs to be added to a mobile application version. Before allowing entry of the MiniApp in the cauldron, checks are performed to ensure that the versions of the native dependencies used by the MiniApp do not conflict with current native dependencies included in the targeted mobile application version. This should not happen often if MiniApps are correctly created based on a manifest — but this can happen, so we should be extra cautious and perform final checks at the cauldron level.

All OTA(Over The Air) MiniApps updates move through the cauldron so that Electrode Native verifies whether or not it contains any conflicting native dependencies versions with the targeted mobile application version.

Manifest

While the Electrode Native cauldron makes sure that no misaligned or non-supported native dependency version makes it into our mobile application — the Electrode Native manifest aligns native dependency versions across multiple MiniApps(described below) in the first place. Each Electrode Native platform version is associated with an array of supported native dependencies along with their versions.

The Electrode Native platform stores its master manifest in a GitHub repository. The master manifest is public and open sourced so that anyone can add native dependency support. By default, Electrode Native relies on the master manifest. For more advanced use cases, it is possible to override the master manifest with our own. When native dependencies are added to a MiniApp using the ern add command (based on the Electrode Native version used), the command verifies if the dependency is supported and if it is supported, the version declared in the Electrode Native manifest is used.

The Electrode Native manifest repository contains:

  • The Electrode Native manifest file: manifest.json
  • Configurations for all supported third-party native modules (The configurations are used by the container generator to inject the native dependencies in the container during generation.)

The Electrode Native platform guarantees that any MiniApp targeting a given Electrode Native version will only include supported dependencies at the same versions — making it possible to add all MiniApps to a single Electrode Native container. By default, Electrode Native uses the master manifest. In order to update the manifest at any time, it is stored in a Git repository. This allows for adding new supported dependencies for an Electrode Native version at any time, without having to wait for the next Electrode Native main version to be released.

For any Electrode Native version defined in the master manifest:

  • We can add new native dependencies support.
  • We cannot change or remove existing native dependencies versions (except for bridge and APIs as the following a versioning allowing for more flexibility). If we change the version of or remove native dependencies, the version alignment guarantees offered by the manifest will be lost.

To align our native dependencies to a new Electrode Native version, use the ern upgrade-miniapp command. When we align the native dependencies to a new Electrode Native version, our MiniApp will be able to be added to any mobile application using any Electrode Native version.

We might also consider using the same version of React Native for our mobile application, for a while, before upgrading to a new version of React Native. Indeed, upgrading (the version of react-native or associated native modules) too frequently might harm our release process because we cannot use CodePush to release updates to versions of your mobile application that have already been released with a different version of React Native.

For each new Electrode Native version, the master manifest will contain updated versions of most of the native dependencies, including the version of React Native itself. The master manifest will always use the latest available version of React Native for each new Electrode Native release.

Runner

The Electrode Native platform contains two runners, one for each mobile platform (Android and iOS). Both runners are very simple and light-weight mobile applications — similar to new application projects in Android Studio or Xcode.

The Electrode Native runner application is used to run our standalone MiniApp so that we can effectively develop, debug, and test our MiniApp — before releasing a new or updated version of the MiniApp. An Electrode Native runner application is automatically generated the first time we use the ern run-ios or ern run-android commands for our MiniApp. Relative to our MiniApp root directory, the runner application is generated in new Android and iOS directories.

When the Electrode Native runner application is generated, we can make manual code modifications to it, if needed — they aren’t overwritten the next time we run the ern run-ios or ern run-android commands. The only way to trigger a complete regeneration of the Electrode Native runner is to remove the Android or iOS directories.

Each time we run the ern run-ios or ern run-android commands, a new local container is generated to include our MiniApp along with all of its native dependencies. The Electrode Native runner mobile application depends on the local container in order to launch the MiniApp.

By default, when launching the Electrode Native runner using the ern run-ios or ern run-android commands, a local React Native Packager is launched and our MiniApp bundle is served from this packager. This is the normal development workflow. However, we can also serve our MiniApp directly from the container stored within the binary of the application using additional command options.

Multiple MiniApp support

The Electrode Native runner supports containers that include multiple MiniApps. However, since only one MiniApp can be launched when the Electrode Native runner starts, we’ll need to specify the primary MiniApp that should be launched when the Electrode Native runner application starts.

What is a MiniApp in Electrode Native?

A MiniApp is just a JavaScript React Native application. Electrode native team made the choice to distinguish a MiniApp from a full-fledged React Native application considering that a MiniApp is not a complete application on its own — but rather a “mini” application that can be combined with other MiniApps to form parts of a mobile application.

  • A MiniApp is a JavaScript React native project representing a specific feature or component.
  • A MiniApp can be a single, simple UI component with minimal logic or it can be a single page application that includes business logic and can communicate with the native side.
  • A MiniApp can be a multi-page application containing a complete application feature.
  • A MiniApp can be shipped and updated inside a mobile application, either included as a native container for in-development mobile application version or as an Over The Air (OTA) update for released mobile application versions.

What does MiniApp mean to a mobile developer?

As a mobile app developer, we won’t directly deal with the JavaScript MiniApps. Selected MiniApps are packaged inside the Electrode Native container library that we’ll add to our mobile application project. The container includes the MiniApps as native Views that we can embed inside our own Activities on Android and ViewControllers on iOS — and launch them when appropriate, based on our overall mobile application UX flow.

Interactions and communication between the MiniApps and our mobile application are conducted using APIs that are also part of our container. The APIs can be consumed in our mobile application in a way that is very intuitive and mobile-development friendly — while also leveraging a high degree of type-safety at compile time.

Why Electrode native?

When developing, integrating, and reusing multiple and distinct React Native components into an existing mobile application, developers face clear challenges.

Electrode Native takes on those challenges by providing an open source platform that reduces the friction for both React Native developers and other mobile app developers. Using the Electrode Native platform solution, developers can leverage their knowledge without having to drastically change their workflow to accommodate the integration of multiple React Native components in their mobile application(s).

React Native allows JavaScript developers to leverage their existing knowledge of React / React Native and they can use a single JavaScript code base to develop mobile applications targeting multiple platforms. React Native also gives developers the power to transparently update their code as over the air (OTA) updates without having to go through the standard store release process and delays-not to mention actual adoption of updates by the users. React Native can (seemingly) also be used to build and reuse some components written in React Native — and “plug” them into existing mobile applications. However, this capability is not yet widely adopted — primarily due to the friction of the required infrastructural changes as well as the absence of adequate tooling — either within the React Native platform itself or as third party tools to effectively help deal with this use case. The learning curve and investment required for mobile application developers who are working on a solution that actually works well for their mobile application, is often too much for many developers and development teams.

There are few solutions to this integration challenge and those that are available are not well documented enough — most require additional tooling as well as infrastructure changes such as switching the mobile code base to a monorepo.

Electrode Native includes a well developed set of open source custom tools that successfully addresses this challenge. Electrode Native allows JavaScript developers to work on their own React Native based components, called MiniApps — from within their dedicated repository, using their own release lifecycle. The MiniApps can be published and reused within potentially any mobile application. Existing JavaScript React Native developers will experience little change to their workflow.

The only difference: developers use a short list of Electrode Native CLI commands. The development experience remains the same as it was when developers worked on pure React Native components. A MiniApp, after all, is really nothing more than a small JavaScript React Native JavaScript application.

Electrode Native allows Mobile application developers to easily integrate individual React Native components within their existing mobile application — without changes to their infrastructure or the need to deal with or install any JavaScript based tools — not even Electrode Native itself!

The bottom line: Using Electrode Native, developers can concentrate on functionality and building their apps — without the hassles of reuse or integration issues.

It provides seamless integration between mobile apps and React Native by packaging our React Native app into an AAR (Android) or framework (iOS), depending on the platform. With Electrode Native, we generate a container that can be added easily to the existing app and start using the React Native component right away. Just add the container as a new native dependency to the mobile application, as any other native third-party dependency. With Electrode Native, React Native acts as a versioned third-party library that is pulled into our mobile app.

It also provides easy Native to React Native Communication — write the Swagger specs and Electrode Native will take care of the communication between the technologies.

And last but not least, Electrode Native ensures that we are not releasing bundles that can potentially crash our customer’s application when releasing multiple over the air updates simultaneously.

Electrode Native workflow

There are three main stages in the Electrode Native workflow:

  • Stage 1: Create MiniApps
  • Stage 2: Add or Update MiniApps
  • Stage 3: Integrate MiniApps in a mobile application

Stage 1: Create MiniApps

Everything starts with one or more MiniApps. MiniApps are typically developed by JavaScript developers — having some experience (or looking towards gaining experience) on front-end applications written in JavaScript — using React or React Native.

Experienced React Native developers won’t notice much difference compared to their familiar React Native application development workflow. The Electrode Native workflow is very similar to the React Native workflow and most of the Electrode Native CLI commands are the equivalent to React Native commands.

Workflow for MiniApps development

  • Create a new MiniApp project using the Electrode Native ern create-miniapp command. This command is equivalent to the React Native react-native init command.
  • Add JavaScript and/or native dependencies (platform APIs or supported third party native modules) to the MiniApp using the Electrode Native ern add command. This command is equivalent to the yarn add or npm install commands.
  • Launch the MiniApp inside the Electrode Native platform runner mobile application. The runner allows you to develop, debug, and test the MiniApp standalone, using the ern run-android and/or the ern run-ios commands. These commands are the equivalent of the react-native run-android and react-native run-ios commands.

If we want maximum reach for our MiniApp, we should also make sure to update the versions of the native dependencies our MiniApp uses to align with the dependencies declared in the Electrode Native master manifest at every platform release (every 2 weeks on Monday). This can easily be achieved using the Electrode Native ern upgrade-miniapp command. We should ideally have one branch for each Electrode Native version (there is no automated support for this, but might come at some point to easily align many MiniApps on a selected Electrode Native version).

  • Publish our MiniApp version (and every update) to npm — then let mobile applications use it!

Note — If we are creating MiniApps for a single target mobile application or a very limited set of mobile applications (for example, if we are not creating an open source MiniApp such as only to be used for our company or private mobile applications), our workflow might involve the following:

  • Launch, Debug, Test our MiniApp within the target mobile applications and not on its own in the platform runner. Since our MiniApp may coexist with other MiniApps in the same mobile application, we will use the Electrode Native ern link and/or ern unlink and the ern start commands to help us in this use case. There is no built-in support yet to easily launch MiniApps in a target mobile application.

Stage 2: Add or Update MiniApps

Here, we choose the MiniApps (and their versions) that we want to add to our mobile application.

Depending on our organisational structure and development operations, Stage 2 might be handled by a dedicated Release Manager or Mobile Application Lead. In some cases, Stage 2 could also be handled by MiniApps Developers. This stage also includes shipping updated versions of MiniApps using Over The Air (OTA) updates through CodePush.

Most of the dependency versioning control of the platform takes place in Stage 2. This is also when the cauldron, manifest, and container generator also work hand in hand.

This involves interacting with the Electrode Native cauldron commands.

Workflow for adding or updating MiniApps to/in a mobile application version

  • Create new mobile application versions in the cauldron using the Electrode Native ern cauldron add nativeapp command. We need to issue the command for each new mobile application version.
  • Add, Remove, and Update MiniApps for a target in-development mobile application version (shipped in a container) using the ern cauldron [add/del/update] miniapps commands.
  • Add, Remove, and Update native dependencies for target in-development mobile application version using the ern cauldron [add/del/update] dependencies commands (shipped in a container)

Note — Native dependencies that MiniApps directly depend on are automatically added to the container when adding or updating a MiniApp version to a given mobile application version. This workflow item is therefore limited only to native dependencies that no MiniApps are actually depending upon — usually to add standalone native API implementations.

  • Update the release status of mobile application versions using the ern cauldron update nativeapp command.

Flagging a mobile application version as being released, actually ‘freezes’ the mobile application version — to disallow any new changes to the native dependencies; we cannot update native code OTA. It will activate a CodePush for this mobile application version, allowing us to effectively push JavaScript changes of MiniApps as OTA updates.

  • Add or update MiniApps versions using OTA CodePush updates using the ern code-push command.

Stage 3. Integrate MiniApps in a mobile application

Stage 3 does not require the use of the Electrode Native platform CLI commands. And Mobile developers working at this stage do not need to install any JavaScript tools or even Electrode Native itself.

At Stage 3, Mobile Application Developers interact with the Container library only — which is shipped as an AAR file for Android, and as an umbrella Framework for iOS.

The container includes everything that is needed to launch and interact with the MiniApps. In addition to the MiniApps (stored in a composite single JavaScript bundle), the container also includes all the native dependencies needed by the MiniApps — including React Native.

Also included in the container are the MiniApps assets (images and fonts mostly) and the initialisation code — to call from our mobile application to initialise the container and get access to the MiniApps stored within.

Workflow for integrating MiniApps in a mobile application

  • Add a dependency to our container library in our mobile application.
  • Add the required code to properly initialise the container.
  • Bump the container version every time it gets regenerated — that is anytime a new MiniApp (or native dependency) is added, removed, or updated.
  • Launch the MiniApps when needed in our mobile application UX flow.
  • Implement APIs in the mobile application itself if necessary — this is not the recommended way for implementing native APIs, but might be necessary in some use cases.

Bonus Stage: Generate and implement APIs

This stage is very similar to Stage 1: Create MiniApps, but it can be performed by either JavaScript React Native Developers or Mobile Application Developers — depending on whether the implementation of the API is done on the JavaScript side or the native side. This stage may be performed by JavaScript React Native Developers — on the JavaScript side, or Mobile Application Developers — on the native side.

APIs facilitate secure interaction and communication between our MiniApps and our mobile application:

  • For MiniApps, a native API can be consumed to access data or functionality from the native side or it can be used to trigger actions on the native side.
  • For a Mobile Application or another MiniApp, a JavaScript API can be consumed to access data or functionality from the JavaScript side, or it can be used to trigger actions on the JavaScript side.

Workflow for generating and implementing APIs

  • Create a new API using the ern create-api command. The complete JavaScript, Android, and iOS client API code is generated along with optional models. All we need to do is then to publish the generated API version on npm. The API code should not be modified. The implementation of the API is kept separate as is the code we actually will need to do on our own. We keep implementation separate from the API itself to ease regeneration and to allow for multiple implementations — that can be easily switched depending on our context, for example, development vs production.
  • Update an existing API using the ern regen-api command. This should be done if we are adding new requests, events, or models to our existing API. Simply update the Swagger schema accordingly and invoke the command. We can then publish this new version of the API to npm.
  • Implement an API. Because API generation and implementation are decoupled, the developer generating the API might not be the developer actually implementing it. We can kickstart an API implementation project using the ern create-api-impl command. Then add the code implementing the API functionality — either as a native implementation (which can then be consumed by any MiniApp depending on this API) or as a JavaScript implementation (which can be consumed by any MiniApp or Mobile Application depending on this API). Implementations can be standalone (not bound to a specific mobile application or MiniApp), which is the recommended approach. Implementations can also be directly done in the mobile application or MiniApp.

Native Dependencies Management

Electrode Native includes support for managing, tracking, and controlling the versions of the native dependencies that MiniApps depend on. The reason behind this support is that while JavaScript applications can contain multiple versions of a given dependency in their dependency graph, mobile applications can’t achieve the same for their native dependencies.

For example, React Native itself will be a native dependency of the mobile application. It contains some native code that is going to be compiled and shipped within the binary of the application. Given that it is a native dependency, there can be only one version of it included in the mobile application at any given time. An iOS or Android mobile application cannot include two versions of the same native dependency. To illustrate this, A mobile application cannot contain React Native 0.42.0 and React Native 0.43.0 at the same time. This is not a restriction of Electrode Native, nor React Native, but just the way mobile applications work regarding native dependencies.

On top of React Native itself, other native dependencies used by MiniApps can be either third-party React Native native modules supported by the platform (react-native-code-push, react-native-vector-icons, or react-native-maps for example) or can be platform-generated APIs or API implementations.

Because of this constraint and the fact that the Electrode Native platform allows us to package multiple MiniApps from different repositories into a single native library, Electrode Native offer support to help align the native dependency versions across all MiniApps as well as guarantees that no MiniApp with a non-aligned native dependency version will make its way into our mobile application.

This support is provided through two modules of the platform: the Electrode Native manifest and the Electrode Native cauldron.

Using Electrode Native APIs

  • APIs are fully generated. We’ll just have to define the interactions our API should offer (as events and requests) in a Swagger schema, and the API code will be generated for JavaScript, iOS, and Android.
  • APIs also support the generation of model classes. We’ll just have to define our models in your Swagger schema and the necessary classes will be generated. Relying on the Electrode Native bridge support means that on the mobile application side, developers are able to work with typed model classes and will be able to leverage compile time checks when dealing with APIs.
  • APIs decouple the client code of the API from its implementation. We can implement the API on the native side or the JavaScript side. Because of this decoupling, it is also possible to write multiple implementations for a single API.
  • APIs are not native modules, they are clients of the Electrode Native bridge which is the native module. There is no react native linking required for APIs.
  • APIs are generated and therefore will follow the exact same file system structure. This means that APIs don’t need any customised configuration to be written for Electrode Native to properly add them to a container.
  • APIs are expected to follow a certain versioning convention, which offers more flexibility in terms of compatibility checks between different versions.

Updating Electrode Native

When we upgrade to a newer version of Electrode Native, previous installed versions of Electrode Native remain on our system; an upgrade does not overwrite the older versions.

Before we upgrade to a newer version of Electrode Native, we should read through the following upgrade guidelines for Electrode Native:

  • Be sure to read the Release Notes for the new version.
  • An upgrade is usually backward compatible although backwards compatibility with every release is not guaranteed. Check to see if upgrading will impact our current workflow.
  • Electrode Native contains a built-in platform version management system — similar to what nvm uses for Node.js — which allows us to keep multiple versions of the platform installed on our local system. The system allows us to easily rollback to a previous platform version or to actually switch back to an older version for some use cases.
  • Only one version of the platform can be active at any given time.

Disadvantages of Electrode Native :

  • Not good or portable enough for starting any project from scratch.
  • ERN project supports JavaScript & TypeScript.
  • Navigation — The Electrode Native platform currently does not ship with its own navigation library nor does it reuse a specific navigation library.
    Navigation is a difficult problem to tackle with React Native. And when we start mixing mobile native screens with JavaScript React Native screens, we must account for potential navigation to and from mobile views and React Native MiniApps, as well as in between React Native MiniApps themselves; not to mention the fact that we need a solution that can work with many different mobile application code bases — the problem becomes even more complex.
    Currently Electrode Native does not ship with a navigation mechanism. As of now, if we want our MiniApp to reach maximum reusability and maximum reach potential, we should consider writing single page MiniApps. For example, MiniApps that are composed of a single screen only and do not involve navigation from one screen to another screen.
  • Third-party native modules — The Electrode Native platform offers support for third-party React Native native modules that do not require JavaScript React Native developers to actually use any command to properly link native modules with their MiniApp.
    However, the Electrode Native platform also does not support “all” third-party native modules. Each native module needs to be listed in the platform manifest and configurations must be modified so that the native modules can be properly injected into any container.
    Considering that the Electrode Native master manifest is a public GitHub repository, and is not bound to a specific platform release lifecycle — anyone can contribute to it in order to add new native module support for their own — as well as any other developer’s use!
  • CodePush OTA updates — There is no solution in place yet to customise OTA updates for MiniApps.
  • Less support available.
  • Not mature or popular enough.
  • Only one version of any native library can be used on the native side.

Since now you know all about Electrode Native and its implementation details, so go ahead and make an informative and wise decision.

Walmart can thank me later 😛

Happy coding 😃

--

--

No responses yet