Consume Your React Native App on Native Android and iOS

Hamzah Tossaro
8 min readAug 25, 2023

--

Image by buffaloboy on Shutterstock

Assalamu’alaikum geeks!
On this article I wouldn’t explaining detail of React Native, however I will show you how does it work and how we can collaborate with them.
I know it’ll be long post, but I hope you will be satisfied for the result that you can achieve.

React Native Advantages

Nowadays we face on many multi platform framework that help us to fasten our delivery product, such as React Native. This framework is using the most popular JavaScript UI library, so web developers could be easily develop mobile application that feel native.

Using very same codebase we can build apps on multiple platforms like iOS, Android, and also web applications.

The most important part of React Native’s architecture is React Native’s Bridge. It allows us to communicate between javascript and Native layers.

Native Layers

As you know on React Native’s Folder Structure, they have both android and ios folder, it can be change on react-native.config.js. React Native read that folder to need to know the native layers for any platform behavior.

Android folder stucture:

As you can see they have build.gradle to handle required dependency for android platform. If we go deeper, we can see they apply another script from react-native folder that has installed on node_modules:

iOS folder structure:

Now for iOS they have Podfile to handle required dependency for iOS platform. And if we go deeper again, we can see they also apply another script from react-native folder that has installed on node_modules:

So for both Android and iOS they require the node_modules folder to know each dependencies they required. Therefore, we need to export all of the required dependencies to be able consume your React Native App outside of React Native’s Environtment.

Convert to Android Library

First thing if you want to consume your React Native App for your Native Android Project, you need to convert current android application become android library. Let’s open android folder with Android Studio.

  1. Rename app folder to YOUR_APP_NAME same with project name at package.json with right click app folder choose refactor > rename > rename module > fill ‘YOUR_APP_NAME’ > hit enter
  2. Edit YOUR_APP_NAME/build.gradle file
//change below
//apply plugin: "com.android.application"
//to
apply plugin: "com.android.library"

//change below
//applicationVariants.all
//to
libraryVariants.all

Using above script your React Native App become un-runnable for android, so we need add new runnable module to keep your React Native App capable for next development and testable.

  1. On Android Studio Toolbar, Choose File > New > New Module
  2. You can fill module name with app, for rest of field you can align with your React Native App. (uncheck using .kts)

If you done creating new module, then edit app/build.gradle

...
dependencies {
//add
implementation(project(":YOUR_APP_NAME"))
implementation("com.facebook.react:react-native:+")
..
}

So now you have 2 module inside of android folder, one for library another one for run the library. You can try creating .aar for your library with this command at your android folder :

./gradlew assemble

After command finished you can see .aar file on android/YOUR_APP_NAME/build/outputs/aar folder. You can import your .aar to current Android Native Project but still, it wouldn’t work for now as you expected. Why it wouldn’t work? you think you already consume the .aar its enough like other simple library right?

As I explain before, we need to export all of dependencies required to run your library outside of React Native’s Environtment. Therefore we will use maven package registry to store all of React Native Dependencies and your library also.

Maven Package Registry

So many maven package registry provider:

  1. https://jitpack.io/ (for github)
  2. https://docs.gitlab.com/ee/user/packages/maven_repository/ (for gitlab)
  3. https://jfrog.com/help/r/jfrog-artifactory-documentation/maven-repository (privately)
  4. etc..

You can follow instructions step by step on their documentations to publishing your library. After you have succeed to publish your library let’s go further, I’ve created a helper file using groovy script to cover publications of all dependencies:

*note: For example purpose I using gitlab package registry project, you can change on maven url and credentials with your project.
Save above code with extension .gradle (example: publications.gradle) put it inside android folder (don’t forget to adjust bolded text). Then edit android/build.gradle to attach those publications scripts.

...
apply from: file("publications.gradle")

Before we publish to package registry, we still need to add additional module to fulfill all dependencies:

  1. Create new 2 directory on android folder with name: “android-jsc” and “react-native
    (if you use hermes you should add “android-hermes” directory too)
  2. Create build.gradle file inside those folders with content:
    (please adjust for each version did you used, you can check directly on node_modules folder present .aar file)
//android-jsc/build.gradle
configurations.maybeCreate("default")
artifacts.add("default", file("${rootDir}/../node_modules/jsc-android/dist/org/webkit/android-jsc/r250230/android-jsc-r250230.aar"))
//react-native/build.gradle
configurations.maybeCreate("default")
artifacts.add("default", file("${rootDir}/../node_modules/react-native/android/com/facebook/react/react-native/0.68.7/react-native-0.68.7.aar"))

Now, we ready to publish all dependencies together with your React Native App as Library to package registry, you can run this command at android folder:

./gradlew publish

After all libraries published, then you can consume your library depend on where your library stored on package registry. example gitlab:

//build.gradle
...
allprojects {
repositories {
...
maven {
name = "YOUR_APP"
url = uri("https://gitlab.com/api/v4/projects/YOUR_REPO_ID/packages/maven")
credentials(HttpHeaderCredentials) {
name = "Deploy-Token"
value = "YOUR_GITLAB_DEPLOY_TOKEN"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}

//app/build.gradle
...
dependency {
implementation("YOUR_GROUP:YOUR_APP:VERSION")
...
}

iOS Podspec

For iOS side we can use Cocoapods Repository to store our React Native App together with all dependencies required. I would suggest you to store your app privately so React libraries won’t conflicted with public one, in this post I was using JFROG Cocoapods smart repository.

What is Podspec anyway?
Its describing your app as Pod Library including meta data of your app and where the source files, assets files also dependencies that required to run your app.

Let’s create a .podspec file (example name: MyApp.podspec) you can put it inside ios folder with content:

Pod::Spec.new do |s|
s.name = 'MyApp'
s.version = '0.1.0'
s.summary = 'My App Summary'
s.description = <<-DESC
My App Using React Native
DESC

s.homepage = 'YOUR_REPOSITORY_URL'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'YOUR_NAME' => 'YOUR_EMAIL' }
s.source = { :git => 'YOUR_REPOSITORY_GIT', :tag => s.version.to_s }
s.ios.deployment_target = '11.0' # example target iOS 11.0

s.dependency 'FBLazyVector'
s.dependency 'RCTRequired'
s.dependency 'RCTTypeSafety'
s.dependency 'React'
s.dependency 'React-CoreModules'

# add more dependency here if any
# ...

s.source_files = '**/*.{swift,h,mm,m,rb}'
s.resources = [
'YOUR_APP_NAME/Assets/index.jsbundle',
'YOUR_APP_NAME/Assets/**'
]

s.resource_bundles = {
'YOUR_APP_NAME' => ['YOUR_APP_NAME/Assets/**']
}
end

JFROG Cocoapods

*note: to use jfrog cocoapods permanently you need jfrog pro license.
*please tell me if any other free cocoapods repository that we can use privatelly.

First you need to setup your JFROG server. You can try with their trial period, so you have to choose which host do you want to use. For cloud host you have 14 days trial period and for self host / locally you have 30 days.

After JFROG settings was completed, then you can login and create new local repository with type of cocoapods (example name: react-native).

Before we are going to publish our React Native App to JFROG repository, we must bundling our javascript app together with all their required assets, so it will be available when you consume your React Native App. Run following command at your react native app directory:

react-native bundle --entry-file index.js --bundle-output ios/YOUR_APP_NAME/Assets/index.jsbundle --dev false --platform ios --assets-dest ios/YOUR_APP_NAME/Assets/

After that, we must archive our ios folder including our Podspec that already created to comply JFROG API publications. Run following command at your ios folder:

tar --no-mac-metadata -czf YOUR_APP_NAME.tar.gz *

Now you can try publish your React Native App to JFROG repository with following command:

curl -u YOUR_JFROG_USER:YOUR_JFROG_PASSWORD YOUR_JFROG_HOST/artifactory/YOUR_JFROG_REPOSITORY_NAME/YOUR_APP_NAME/YOUR_APP_VERSION/ -T YOUR_APP.tar.gz

So you have published your app, but is it ready to consume?
Unfortunately not ready yet. Again same as android before, if you only publish the library won’t make it ready to be consumed. We need to publish all of their required dependencies to resolve it. Here I’ve create ruby script to cover all of required dependencies and publish them to JFROG server:

Save above code with extension .rb (example name: publish_native_pods.rb) put it inside ios folder. Before you run that script you must make sure your project name at ./package.json is same with your .podspec file name and content, also with subfolder name of your ios project.

You want to publish it now? Wait! Basicaly if you publish it, you can resolve by pod install but React Native App has their own ruby script that need to be run after pod installed, so it should be called on your Native iOS project too. Here I made mini script from original React Native Library that only required to make your Native App running well, put this script on ios folder with name react_native_post_install.rb :

One more thing, commonly our Native iOS project using use_framework! to enable Dynamic Libraries right? Then we should tell our Native App to override any library that still need to be Static Library. Here I made a function helper that you can put on ios folder with name (YOUR_APP_LOWER_CASE)_post_install.rb (example: myapp_post_install.rb) :

Now you are ready to publish it, run following command at ios folder:

export JFROG_USER=YOUR_JFROG_USER
export JFROG_PASS=YOUR_JFROG_PASSWORD
export JFROG_HOST=YOUR_JFROG_HOST/artifactory/YOUR_JFROG_REPOSITORY_NAME
ruby publish_native_pods.rb

After all libraries published to JFROG, then you can consume it on your Podfile using plugin cocoapods-art, please follow the instruction on their documentation. Because if I posted here it will make this post even longer. *you can tell me on the comment if you want me to post it as well ;)

Last but not least, for making your React Native App running well you can call ruby script that we already create before on your post_install block at your Native App Podfile:

Conclussion

With this capabilities, we can have a Super App that consuming many Mini App from our currently running project React Native App without re-write it to native app. And it should work both android and iOS as well.

Alhamdulillah..
I am very grateful to Allah for the knowledge that I’ve got, then hope this knowledge will help you to achieve your big ideas.

That’s all from me, I am sorry for very long post :)
Please correct me if something is wrong and feel free to ask questions if you face any problem.
Wassalamu‘alaikum!

--

--