背景
在成熟的Android原生项目基础,添加ReactNative模块
官方集成方式成本太高,它让新创建一个android的空目录,然后把已有的成熟项目复制过去,这改动太大坑特多,直接放弃
以下文章是在原生项目基础上,新建service_rn的module
配置ReactNative
1、在项目根目录,打开终端,通过yarn创建package.json文件,命令执行途中,会有相应的提示,输入对应的配置,最后就会在根目录生成一个package.json文件
yarn init
2、执行完后,根目录会多出一个node_modules目录,该目录存放react的依赖还有后续新增的第三方库依赖
//配置最新版的ReactNative
yarn add react react-native
//如果需要指定版本,则在后面通过@版本号
yarn add react react-native@18.2.0
3、打开package.json文件,添加一个scripts节点,配置ReactNative的启动脚本,其中dependence是后续新增的一些三方依赖,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 会添加上@react-native-community/cli-platform-android的依赖信息
yarn add @react-native-community/cli-platform-android
如上图中dependence出现的
"@react-native-community/cli-platform-android": "12.3.6",
5、打开根目录,新建一个react-native.config.js文件,配置原生项目的根路径,如果不配置默认寻找的是根路径的.android目录,但我们的项目结构并不是这样,所以需要进行配置,如果不配置,运行就会报错(非常关键!!!)
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')
至此,配置结束,除了在package.json中新增库依赖,其他报错最好不要乱动rn的配置,android的配置可以改例如compilesdk之类的这种。
我这边的环境是gradle7.3.3,gradle插件是7.1.2,jdk使用17
代码干货
1、在app目录下的Application实现ReactApplication,重写getReactNativeHost方法
override fun onCreate() {
super.onCreate()
、、、
RnManager().init(this,mReactNativeHost)
}
private val mReactNativeHost = object : ReactNativeHost(this) {
override fun getUseDeveloperSupport(): Boolean {
//是否开启开发者调试支持
return true
}
override fun getPackages(): MutableList<ReactPackage>? {
//返回原生模块列表
return PackageList(this).packages
}
// override fun getJSMainModuleName(): String {
// //返回要加载的JS入口文件名,不需要加.js后缀
// return "index"
// }
//这里就是拆分后的基础包,在assets目录下
override fun getBundleAssetName(): String {
return "common.android.bundle"
}
}
override fun getReactNativeHost(): ReactNativeHost {
return mReactNativeHost
}
2、在具体逻辑后跳转service_module下的页面
startActivity(Intent(this, MainActivity::class.java))
3、在service_module下新增RnManager类,它是在applicaition初始化的时候调用,加载拆包后的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、创建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")
//加载业务包
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)
}