[Building A Super App] How To Build An SDK Embed React-Native (iOS & Android)?

[English below] Việc đóng gói một SDK cho iOS và Android không hề khó. Vấn đề là phải đóng gói cả React-Native vào trong SDK. Vậy giải pháp là gì? Câu trả lời có trong bài viết dưới đây.
Packaging an SDK for iOS and Android is not difficult. However, if it’s compulsory to package React-Native into the SDK, what’s the solution? The answer is in the article below.


Lời mở đầu

Công việc hiện tại của tôi là phát triển Tini App — Một sản phẩm về Mini Program của Tiki. Mục tiêu của tôi là tìm kiếm giải pháp để chạy Tini App trên kì ứng dụng nào, nhằm biến ứng dụng đó trở thành một Super App, bao gồm: Kho ứng dụng Tini App và cung cấp giải pháp để phát triển Tini App của ứng dụng đó.

Để làm sản phẩm Tini App, chúng tôi phải xây dựng rất nhiều công cụ khác nhau như: Tini App Studio — Một IDE để phát triển ứng dụng Tini App, Tini Console — Công cụ quản lý và phát hành ứng dụng Tini App và nhiều hơn nữa. Chi tiết truy cập developers.tiki.vn hoặc đặt câu hỏi cho chúng tôi tại community.tiki.vn.

Một trong những thành phần rất quan trọng của Tini App chính là Tini App Core. Tini App Core là một kiến trúc phức tạp, gồm native code để xử lý logic và render một ứng dụng Tini App. Để tăng tốc độ phát triển Tini App, chúng tôi sử dụng React-Native như là một giải pháp cross-platform để xây dựng các thành phần native của Tini App Core (Với kiến trúc hiện tại của chúng tôi, hoàn toàn có thể thay đổi React-Native bằng bất kì cross-platform framework hay native code trong tương lai).

Việc đóng gói một SDK cho iOS và Android không hề khó. Vấn đề của chúng tôi là phải đóng gói cả React-Native vào trong SDK. Tôi đã tìm kiếm nhiều giải khác nhau nhưng không có giải pháp nào thuyết phục. Cuối cùng, dựa vào nghiên cứu của tôi, tôi đã tìm ra được giải pháp cho riêng mình, dựa trên mục tiêu ít các bước tích hợp nhất và thân thiện với iOS/Android developer. Ở nội dung bài viết này, tôi sẽ chia sẻ giải pháp của mình và tôi chưa chắc đây là giải pháp tốt nhất nên tôi mong nhận được sự góp and chia sẻ khác từ các bạn.

Lưu ý: Vì đây là một bài hướng dẫn lập trình nên đoạn sau tôi xin phép được viết bằng tiếng Anh

Introduction

Mycurrent job is developing the Tini App — A Mini Program product of Tiki corporation. The goal is finding a solution to run the Tini App on any application, to turn that application into a Super App, including the Tini App store, and provide solutions to develop the Tini App of that application.

To make the Tini App product, we have built many different tools such as Tini App Studio — An IDE for Tini App development, Tini Console — Tini App publishing and management tool, etc. For more details, visit developers.tiki.vn or ask us questions at community.tiki.vn.

One of the crucial components of the Tini App is Tini App Core. Tini App Core is a complex architecture, consisting of native code to handle logic and render a Tini App application. To speed up Tini App development, we use React-Native as a cross-platform solution to build Tini App Core native components. With the current architecture, we can completely change React-Native with any cross-platform framework or native code in the future.

Packing an SDK for iOS and Android is not challenging. Our problem was to package React-Native into the SDK. I have searched for many different solutions, but there is no persuasive one. Eventually, based on my study, I found my answer, based on the goal of the most minor integration steps and iOS/Android developer friendly. In the content of this article, I will share my solution but not sure this is the best solution, so I hope to receive other contributions and shares from you.

Requirements

This is my current environment, you can customize it to suilt your version.

  • Node.js 16
  • Xcode 14
  • Android Studio 2021.3.1
  • React-Native 0.61.5

I. Create a React-Native 0.61.5 project

1. Create a React-Native project

Run the following command to create a React-Native 0.61.5 using Typescript

react-native init RNSDKExample --template react-native-template-typescript@6.3

2. Fix issue: Xcode ≥ 12.5

Add the following code at the end of the Podfile file

Run the following command to add patch-package dependency

yarn add patch-package --dev

Create a file with name react-native+0.61.5.patch in patches folder

3. Fix issue: Android Studio 2021.3.1

Update the gradle-wrapper.properties file

4. Fix issue: React Native: Unexpected token ‘:’. Expected a ‘)’ or a ‘,’ after a parameter declaration

5. Add some React-Native dependency

I use additional react-native-fast-image library to package into the SDK

yarn add react-native-fast-image

6. Edit the App.tsx file

7. Run the RN project

yarn ios --simulator="iPhone 14 Pro"
# or
yarn android

II. Build the SDK for iOS

The goal of building the SDK is to package it into a single pod library. I will build all React-Native libraries and my native code into universal frameworks.

1. Create an SDKOutput folder

Create an SDKOutput folder in the ios folder containing all the SDK’s resources

${rootDir}/ios/SDKOutput

Create a package.json file in the SDKOutput folder

Create an RNSDK.podspec file in the SDKOutput folder

2. Create an SDK build command

Create a scripts folder

${rootDir}/scripts

Create a bundle-ios.sh file in the scripts folder to generate jsbundle for iOS, it will be saved in the SDKOutput/Rescources folder with name rnsdk.jsbundle .

Create a bundle-fw-ios.sh file in the scripts folder to generate universal frameworks, it will be saved in SDKOutput/Frameworks folder.

Note: FRAMEWORK_NAME=RNSDK will be created in step 4.

Add a build-sdk-ios script to the package.json file at the root project

"build-sdk-ios": "sh scripts/bundle-ios.sh && sh scripts/build-fw-ios.sh"

3. Update the .gitignore file

Ignore Rescources and Frameworks folders just created. Add the following content to the .gitignore file.

*/SDKOutput/Rescources/
*/SDKOutput/Frameworks/

4. Create an RNSDK framework

Open the ios/RNSDKExample.xcworkspace file and create an iOS framework target with the name RNSDK

Update the Podfile file: Build pod libraries as frameworks, upgrade platform to 11.0, create react_native_modules function.

Run the following command to update the RNSDKExample.xcworkspace

pod install

Create an RNSDKViewController.swift file in the RNSDK framework

Edit Build Settings → Build Libraries for Distribution to Yes to add swift files to the SDK.

5. Build the SDK

Run the following command to build the SDK

yarn build-sdk-ios

6. Publish the SDK

Publish all resources in the ios/SDKOutput folder to CDN. For example:

https://github.com/lamvd0101/react-native-sdk-ios

7. Build an example

  • Create an iOS project with the interface is Storyboard
  • Create a Podfile file and add the RNSDK in step 6
pod 'RNSDK', :git => 'https://github.com/lamvd0101/react-native-sdk-ios.git', :tag => 'v1.1.0'
  • Add the UIViewControllerBasedStatusBarAppearance property into Info.plistfile
  • Extends the ViewController from the RNSDKViewController
  • Build the project

III. Build the SDK for Android

The goal of building the SDK for Android is similar to that of iOS. I will create a single Android module and use jitpack.io as the CDN.

1. Create an SDKOutput folder

Create an SDKOutput folder in the android folder containing all the SDK’s resources

${rootDir}/android/SDKOutput

2. Create an SDK build command

Create a bundle-android.sh file in the scripts folder to generate jsbundle for Android, it will be saved in the android/RNSDK/… with name rnsdk.jsbundle.

Note: RNSDK and libs.txt will be created in step 4.

Create a bundle-fw-android.sh file in the scripts folder to generate aar files, it will be saved in the SDKOutput/libs folder. In addition, I will create a libs.txt file to include the Android dependencies that the RN dependencies are using.

Add a build-sdk-android script to the package.json file at the root project

"build-sdk-android": "sh scripts/bundle-android.sh && sh scripts/build-fw-android.sh"

3. Update the .gitignore file

Ignore libs, libs.txt, RNSDK/…/assets and RNSDK/…/res just created. Add the following content to the .gitignore file.

*/SDKOutput/libs/
*/SDKOutput/libs.txt
android/RNSDK/src/main/assets
android/RNSDK/src/main/res

4. Create an RNSDK module

Create a file with name @react-native-community+cli-platform-android+3.1.4.patch in patches folder

Open the android project and create an Android module with the name RNSDK

Update the build.gradle file at the RNSDK module

Update the build.gradle file at the root project

Add the package=”com.company.rnsdk” attribute to the AndroidManifest.xml of the RNSDK module

Create an RNSDKActivity.java file in the RNSDK module

5. Build the SDK

Run the following command to build the SDK

yarn build-sdk-android

6. Publish the SDK

I use jitpack.io to do CDN for SDK. Since the RN libraries I build as aar files, to fix the issue direct local .aar file dependencies are not supported, I use 2 github repos:

  • react-native-sdk-android-libs: Contains aar files
  • react-native-sdk-android: Android module implements the above repo

6.1. react-native-sdk-android-libs repo

Copy the android/SDKOutput/libs folder to react-native-sdk-android-libs repo. Create a jitpack.yml file with the following content:

Tag the release, e.g. v1.1.0. Then go to jitpack.io and click Get it for that tag.

6.2. react-native-sdk-android repo

Create an Android project with Empty Activity with the name RNExample

Create an Android module with the name RNSDKAndroid

Update the settings.gradle file

Add the following code at the end of the gradle.properties file

android.enableJetifier=true

Update the build.gradle file at the root project

Update the build.gradle file of the RNSDKAndroid module

Copy the android/SDKOutput/libs.txt file to the RNSDKAndroid module folder. And add the package=”com.company.rnsdkandroid” attribute to the AndroidManifest.xml of the RNSDKAndroid module.

Update the build.gradle file of the app project

Update the MainActivity.kt file of the app project

Delete the res/layout folder, values-night folder and values/themes.xml file. Update the AndroidManifest.xml of the app project.

Create a jitpack.yml file with the following content:

Tag the release, e.g. v1.1.0. Then go to jitpack.io and click Get it for that tag.

7. Build an example

  • Create an Android project with Empty Activity
  • Add maven { url “ https://jitpack.io" } to settings.gradle
  • Add android.enableJetifier=true to gradle.properties
  • Add the library implementation just built above
implementation('com.github.lamvd0101:react-native-sdk-android:v1.1.0') {
    exclude group: "androidx.lifecycle"
}
  • Extends MainActivity from RNSDKActivity
  • Build the project

Git repos

  1. GitHub - lamvd0101/react-native-sdk-example
  2. GitHub - lamvd0101/react-native-sdk-ios
  3. GitHub - lamvd0101/react-native-sdk-android
  4. https://github.com/lamvd0101/react-native-sdk-android-libs

References

  1. Tini App, Tini App Community
  2. MiniApp Standardization White Paper version 2
  3. Building React Native 0.61.5 SDK to be used by native IOS applications (Swift)
4 Likes

Bravo anh @lam.vuong, hóng mãi qua giờ luôn ấy :innocent: :innocent:

3 Likes