ReactNative集成到Android原生項(xiàng)目

背景

在成熟的Android原生項(xiàng)目基礎(chǔ),添加ReactNative模塊
官方集成方式成本太高,它讓新創(chuàng)建一個(gè)android的空目錄,然后把已有的成熟項(xiàng)目復(fù)制過去,這改動(dòng)太大坑特多,直接放棄
以下文章是在原生項(xiàng)目基礎(chǔ)上,新建service_rn的module

配置ReactNative

1、在項(xiàng)目根目錄,打開終端,通過yarn創(chuàng)建package.json文件,命令執(zhí)行途中,會(huì)有相應(yīng)的提示,輸入對(duì)應(yīng)的配置,最后就會(huì)在根目錄生成一個(gè)package.json文件

yarn init

2、執(zhí)行完后,根目錄會(huì)多出一個(gè)node_modules目錄,該目錄存放react的依賴還有后續(xù)新增的第三方庫依賴

//配置最新版的ReactNative
yarn add react react-native

//如果需要指定版本,則在后面通過@版本號(hào)
yarn add react react-native@18.2.0

3、打開package.json文件,添加一個(gè)scripts節(jié)點(diǎn),配置ReactNative的啟動(dòng)腳本,其中dependence是后續(xù)新增的一些三方依賴,repository是依賴的rn倉庫地址

{
  "name": "service_rn",
  "version": "1.0.0",
  "description": "rn",
  "main": "index.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/facebook/react-native.git",
    "directory": "packages/react-native-gradle-plugin"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@react-native-community/cli-platform-android": "12.3.6",
    "@react-navigation/native": "6.1.14",
    "@react-navigation/native-stack": "6.9.22",
    "react": "18.2.0",
    "react-native": "0.73.6",
    "react-native-safe-area-context": "4.9.0",
    "react-native-screens": "3.29.0"
  },
  "scripts": {
    "start": "yarn react-native start"
  }
}

4、配置ReactNative-CLI依賴,命令行輸入以下命令,安裝完畢后,package.json的dependencies 會(huì)添加上@react-native-community/cli-platform-android的依賴信息

yarn add @react-native-community/cli-platform-android

如上圖中dependence出現(xiàn)的

    "@react-native-community/cli-platform-android": "12.3.6",

5、打開根目錄,新建一個(gè)react-native.config.js文件,配置原生項(xiàng)目的根路徑,如果不配置默認(rèn)尋找的是根路徑的.android目錄,但我們的項(xiàng)目結(jié)構(gòu)并不是這樣,所以需要進(jìn)行配置,如果不配置,運(yùn)行就會(huì)報(bào)錯(cuò)(非常關(guān)鍵!?。。?/p>

module.exports = {
  project: {
    android: {
      sourceDir: './',
    },
  },
};

配置android studio

1、根目錄下的setting.gradle添加

include ':service_rn'
apply from: file("./node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
applyNativeModulesSettingsGradle(settings)

2、根目錄下的build.gradle中,repositories下添加

maven {
            url "$rootDir/node_modules/react-native/android"
        }
        maven {
            url("$rootDir/node_modules/jsc-android/dist")
        }

3、service_rn下的build.gradle中的dependence添加

implementation "com.facebook.react:react-native:+"
    implementation "org.webkit:android-jsc:+"

最下面添加

apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
applyNativeModulesAppBuildGradle(project)

4、在app.build下的dependence添加

implementation "com.facebook.react:react-native:+"
    implementation "org.webkit:android-jsc:+"
    implementation project(':service_rn')

至此,配置結(jié)束,除了在package.json中新增庫依賴,其他報(bào)錯(cuò)最好不要亂動(dòng)rn的配置,android的配置可以改例如compilesdk之類的這種。
我這邊的環(huán)境是gradle7.3.3,gradle插件是7.1.2,jdk使用17

代碼干貨

1、在app目錄下的Application實(shí)現(xiàn)ReactApplication,重寫getReactNativeHost方法

override fun onCreate() {
        super.onCreate()
        、、、
        RnManager().init(this,mReactNativeHost)
    }
private val mReactNativeHost = object : ReactNativeHost(this) {
        override fun getUseDeveloperSupport(): Boolean {
            //是否開啟開發(fā)者調(diào)試支持
            return true
        }

        override fun getPackages(): MutableList<ReactPackage>? {
            //返回原生模塊列表
            return PackageList(this).packages
        }

//        override fun getJSMainModuleName(): String {
//            //返回要加載的JS入口文件名,不需要加.js后綴
//            return "index"
//        }

        //這里就是拆分后的基礎(chǔ)包,在assets目錄下
        override fun getBundleAssetName(): String {
            return "common.android.bundle"
        }
    }

    override fun getReactNativeHost(): ReactNativeHost {
        return mReactNativeHost
    }

2、在具體邏輯后跳轉(zhuǎn)service_module下的頁面

            startActivity(Intent(this, MainActivity::class.java))

3、在service_module下新增RnManager類,它是在applicaition初始化的時(shí)候調(diào)用,加載拆包后的common包

class RnManager {
    private lateinit var mContext:Application
    companion object {
        private lateinit var cacheReactInstanceManager: ReactInstanceManager

        fun getRcInstanceManager():ReactInstanceManager{
            return cacheReactInstanceManager
        }
    }

    private fun initializeFlipper(
        context: Context, reactInstanceManager: ReactInstanceManager
    ) {
        if (BuildConfig.DEBUG) {
            try {
                /**
                 * We use reflection here to pick up the class that initializes Flipper,
                 * since Flipper library is not available in release mode
                 */
                val aClass = Class.forName("com.awesomeproject.ReactNativeFlipper")
                aClass.getMethod(
                    "initializeFlipper",
                    Context::class.java,
                    ReactInstanceManager::class.java
                ).invoke(null, context, reactInstanceManager)
            } catch (e: ClassNotFoundException) {
                e.printStackTrace()
            } catch (e: NoSuchMethodException) {
                e.printStackTrace()
            } catch (e: IllegalAccessException) {
                e.printStackTrace()
            } catch (e: InvocationTargetException) {
                e.printStackTrace()
            }
        }
    }

    fun init(context: Application,mReactNativeHost:ReactNativeHost) {
        mContext = context
        var packages = PackageList(mContext).packages
        SoLoader.init(context, /* native exopackage */ false)

        initializeFlipper(mContext, mReactNativeHost.reactInstanceManager)

        cacheReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(mContext)
            .addPackages(packages)
            .setJSBundleFile("assets://common.android.bundle")
            .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
            .build()
    }
}

4、創(chuàng)建rn的activity

class MainActivity : ReactActivity() {
    var time:Long = 0

    private var mReactRootView: ReactRootView? = null
    private var mReactInstanceManager: ReactInstanceManager? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mReactRootView = ReactRootView(this)
        SoLoader.init(this, false)

        mReactInstanceManager = RnManager.getRcInstanceManager()
        mReactInstanceManager?.onHostResume(this, this)
        Log.e("111111111", ("--------"))

        mReactInstanceManager?.addReactInstanceEventListener(object :ReactInstanceEventListener{
            override fun onReactContextInitialized(p0: ReactContext?) {
                Log.e("111111111", (p0 == null).toString())
                Log.e("111111111", "22222222222222")
                //加載業(yè)務(wù)包
                val context = mReactInstanceManager?.currentReactContext
                val instanceImpl = context?.catalystInstance
                instanceImpl?.loadScriptFromAssets(context?.assets,"assets://buz.android.bundle",false)
                mReactRootView?.startReactApplication(mReactInstanceManager,"AwesomeProject",null)
                setContentView(mReactRootView)
                mReactInstanceManager?.removeReactInstanceEventListener(this)
            }
        })

        setContentView(mReactRootView);

        mReactInstanceManager?.createReactContextInBackground()
        return
    }

    override fun invokeDefaultOnBackPressed() {
        super.onBackPressed()
    }

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  override fun getMainComponentName(): String = "project_pad_base"

  /**
   * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
   * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
   */
  override fun createReactActivityDelegate(): ReactActivityDelegate =
      DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容