IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    最新版Android原生集成RN

    似水流年发表于 2022-12-21 13:44:29
    love 0

    前言

    现在不少应用都是采用了混合开发模式,不论是原生加RN,或是原生加Flutter,或是原生加H5。原生实现主业务线,其他部分可以借助跨平台方案开发,提高开发效率,或者实现热更新,调高业务迭代效率。

    下面简单介绍一下Android原生集成最新RN版本的过程。

    添加package.json文件

    首先在一个正常编译运行的原生APP根目录下执行yarn init命令,按提示填写基本信息后会在项目根目录下,创建一个package.json文件。

    添加JavaScript依赖,生成node_modules

    然后,使用如下命令添加React和React Native运行环境的支持脚本。

    yarn add react react-native

    命令执行完成后,所有JavaScript依赖模块都会被安装到项目根目录下的node_modules/目录中。

    注意:node_modules这个目录我们原则上不复制、不移动、不修改、不上传,随用随装,同时把node_modules/目录记录到.gitignore文件中(即不上传到版本控制系统,只保留在本地)。

    接下来,在package.json文件中配置启动RN Metro服务的脚本,即script脚本,文件全部内容如下。
    项目根目录package.json文件

    {
      "name": "AndroidDemo",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "dependencies": {
        "react": "^18.2.0",
        "react-native": "^0.70.6"
      },
      "scripts": {
        "start": "yarn react-native start"
      }
    }

    原生端添加React Native依赖

    在app中build.gradle文件中添加React Native和JSC引擎依赖:

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

    在项目的build.gradle文件中为React Native和JSC引擎添加maven源的路径,必须写在 "allprojects" 代码块中。

    allprojects {
        repositories {
            maven {
                // All of React Native (JS, Android binaries) is installed from npm
                url "$rootDir/../node_modules/react-native/android"
            }
            maven {
                // Android JSC is installed from npm
                url("$rootDir/../node_modules/jsc-android/dist")
            }
        }
    }

    !!!注意这里有个问题,点击同步后,会报如下错误:

    Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by build file 'build.gradle'

    原因是gradle7.0后,以前位于根项目build.gradle文件中的代码库设置现在迁移到了settings.gradle文件中,根目录build.gradle文件不做更改。
    settings.gradle文件配置

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
            maven {
                url "$rootDir/node_modules/react-native/android"
            }
            maven {
                url("$rootDir/node_modules/jsc-android/dist")
            }
        }
    }
    相关说明:https://developer.android.com...

    配置原生项目网络权限及开发者菜单页面

    在原生AndroidManifest.xml文件进行添加,对应示例如下
    如果需要访问http请求,需要application中添加usesCleartextTraffic

    // 网络权限
     <uses-permission android:name="android.permission.INTERNET" />
    
        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:usesCleartextTraffic="true" // 访问http请求
            android:theme="@style/Theme.AndroidStudy"
            tools:targetApi="31">
    
            <activity
                android:name=".MainActivity"
                android:exported="true">
    <!--            <intent-filter>-->
    <!--                <action android:name="android.intent.action.MAIN" />-->
    
    <!--                <category android:name="android.intent.category.LAUNCHER" />-->
    <!--            </intent-filter>-->
            </activity>
    
            <activity
                android:name=".MyActivity"
                android:theme="@style/Theme.AppCompat.Light.NoActionBar"
                android:exported="true" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            //开发者调试菜单
            <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
        </application>

    创建一个RN入口文件index.js

    index.js是 React Native 应用在 Android 上的入口文件。而且它是不可或缺的!它可以是个很简单的文件,简单到可以只包含一行require/import导入语句,示例代码如下。

    import React from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native';
    
    class HelloWorld extends React.Component {
      render() {
        return (
          <View style={styles.container}>
            <Text style={styles.hello}>Hello, World</Text>
          </View>
        );
      }
    }
    var styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        backgroundColor: '#f9c2ff',
      },
      hello: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
        color: 'red'
      }
    });
    
    AppRegistry.registerComponent(
      'MyReactNativeApp',
      () => HelloWorld
    );

    创建一个页面用来承载RN页面

    需要在一个Activity中创建一个ReactRootView对象,然后在这个对象之中启动React Native应用,并将它设为界面的主视图,这里创建了一个MyActivity页面

    import android.app.Activity;
    import android.os.Bundle;
    import android.view.KeyEvent;
    
    import com.facebook.react.ReactInstanceManager;
    import com.facebook.react.ReactRootView;
    import com.facebook.react.common.LifecycleState;
    import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
    import com.facebook.react.shell.MainReactPackage;
    import com.facebook.soloader.SoLoader;
    
    public class MyActivity extends Activity implements DefaultHardwareBackBtnHandler {
        private ReactRootView mReactRootView;
        private ReactInstanceManager mReactInstanceManager;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SoLoader.init(this, false);
            mReactRootView = new ReactRootView(this);
            mReactInstanceManager = ReactInstanceManager.builder()
                    .setApplication(getApplication())
                    .setCurrentActivity(this)
                    .setBundleAssetName("index.android.bundle")
                    .setJSMainModulePath("index")
                    .addPackage(new MainReactPackage())
                    .setUseDeveloperSupport(BuildConfig.DEBUG)
                    .setInitialLifecycleState(LifecycleState.RESUMED)
                    .build();
                    // 注意这里的MyReactNativeApp 必须对应"index.js"中的
            // "AppRegistry.registerComponent()"的第一个参数
            mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
            setContentView(mReactRootView);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
    
            if (mReactInstanceManager != null) {
                mReactInstanceManager.onHostPause(this);
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            if (mReactInstanceManager != null) {
                mReactInstanceManager.onHostResume(this, this);
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            if (mReactInstanceManager != null) {
                mReactInstanceManager.onHostDestroy(this);
            }
            if (mReactRootView != null) {
                mReactRootView.unmountReactApplication();
            }
        }
    // 显示开发调试菜单弹框
        @Override
        public boolean onKeyUp(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
                mReactInstanceManager.showDevOptionsDialog();
                return true;
            }
            return super.onKeyUp(keyCode, event);
        }
    
        @Override
        public void invokeDefaultOnBackPressed() {
            super.onBackPressed();
        }
    // 后退按钮事件传递给 React Native
        @Override
        public void onBackPressed() {
            if (mReactInstanceManager != null) {
                mReactInstanceManager.onBackPressed();
            } else {
                super.onBackPressed();
            }
        }
    }

    自此原生端集成RN完成。

    测试集成效果。

    首先,需要启动开发服务器(Metro)。你只需在项目根目录中执行以下命令:

    yarn start

    然后,点击Android Studio运行按钮,正常运行项目即可。

    加载完bundle文件之后,可以看到如下页面了。



沪ICP备19023445号-2号
友情链接