ReactNative集成到Android原生项目

背景

在成熟的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)
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。