背景
在成熟的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)
}