美文网首页RN
ReactNative混合开发-3 Android混编配置

ReactNative混合开发-3 Android混编配置

作者: 肆点壹陆 | 来源:发表于2019-05-03 17:48 被阅读1次

    开发语言:ReactNative 0.59.5 Android
    开发环境:VSCode Android Studio 3.4

    1、项目目录

    参考文章:集成到现有原生应用

    首先,我们按照建立一下目录结构,其中:
    Code目录放置所有公用的ReactNative脚本,包,以及相关配置。
    Android目录放置原Android项目。

    Code (根目录)
    --Android(一级目录)

    2、开发环境准备

    2.1、package.json配置

    在Code目录下创建package.json文件,编辑文件输入以下内容。

    {
      "name": "AppName",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "yarn react-native start"
      }
    }
    

    2.2、React和React Native模块安装

    在Code目录下使用控制台执行以下语句来安装React Native。

    yarn add react-native
    
    • 注意,执行完以上命令后,可能会出现以下提示内容,表示我们需要安装指定版本的React(此例子中需要安装版本为16.8.3的React)。

    warning " > react-native@0.59.5" has unmet peer dependency "react@16.8.3".

    在Code目录下使用控制台执行以下语句来安装指定版本的React

    yarn add react@16.8.3
    

    3、配置maven

    3.1、在app的build.gradle文件中添加React Native依赖

    dependencies {
        ...
        implementation "com.facebook.react:react-native:+" // 新增React Native依赖
    }
    

    3.2、在项目的build.gradle文件中添加maven的依赖入口

    allprojects {
        repositories {
            ...
            maven { url "$rootDir/../../node_modules/react-native/android"} //注意url路径应该指向根目录code中的node_modules,
        }
    }
    

    3.3、在AndroidManifest.xml声明网络权限

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.reactnativedemo" >
        
        
        <uses-permission android:name="android.permission.INTERNET" /> //新增网络权限
         ...
    </manifest>
    

    3.4、在AndroidManifest.xml配置调试Activity

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.reactnativedemo" >
    
        <uses-permission android:name="android.permission.INTERNET" />
    
        <application
        
            ...
            //调试Activiy,使用摇一摇呼出
            <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
            
     
     
         </application>
    
    </manifest>
    

    4、脚本创建

    在Code根目录下创建Scprits文件夹,用于存放React Native的脚本文件

    Code (根目录)
    --Scprits(一级目录,用于存放所有React Native的脚本)

    然后我们可以在Scprits目录下开始写ReactNative的脚本了。
    首先我们创建一个FrameText.js,然后写入如下内容:

    import React, { Component } from 'react'
    import { View, Text } from 'react-native'
    
    
    export default class FrameText extends Component {
    
        render() {
            return (
                <View style={{
                    width:200,
                    height:100,
                    backgroundColor: '#CDDAF5'
                }}>
                <Text>{"我来自ReactNative,我是FrameText"}</Text>
                </View>
            );
        }
    }
    // 整体js模块的名称
    export { FrameText } 
    

    在FrameText中,我们创建了一个简单的组件,供其他脚本使用。

    然后我们再创建一个index.js,然后写入如下内容

    import {AppRegistry} from 'react-native'
    import {FrameText} from 'FrameText'
    
    
    // 整体js模块的名称
    AppRegistry.registerComponent('Component-1', () => FrameText);
    
    

    在index中,我们注册了FrameText组件,供app使用,我们可以在index.js注册很多不同的组件,app可以通过我们注册的名字(本例中为Component-1)来创建这些组件,下面我们来看看怎么在app内使用他们。

    5、Android项目修改

    本例中期望在app的一个controller内,同时使用原生语言与ReactNative脚本分别显示2个View,现在我们来看看是如果在原生app中加载ReactNative的View。

    5.1、创建 MyReactNativeBridge

    新建一个Java文件,创建MyReactNativeBridge类,顾名思义,此类负责桥接原生app与ReactNative,注意,一个app中最好只创建一个桥接实例,所以使用单利模式创建。

    package com.example.reactnativedemo;
    
    import com.facebook.react.ReactInstanceManager;
    import com.facebook.react.common.LifecycleState;
    import com.facebook.react.shell.MainReactPackage;
    
    public class MyReactNativeBridge {
    
        private static final ReactInstanceManager mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(MyApplication.getInstance())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("Scprits/index")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                //注册弹出调试菜单的Activity,发布版可以无需注册
                .setCurrentActivity(MyApplication.getInstance().getCurrentActivity())
                .build();
    
        private MyReactNativeBridge() {
        
        }
    
        public static ReactInstanceManager getInstance() {
            return mReactInstanceManager;
        }
    }
    
    
    

    5.2、创建并使用ReactRootView

    ReactRootView为ReactNative脚本描述的View,它继承FrameLayout,我们可以通过MyReactNativeBridge来创建ReactRootView。

    public class MainActivity extends AppCompatActivity {
    
        private ReactRootView mReactRootView;
        
        LinearLayout reactView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            reactView = findViewById(R.id.reactLayout);
            MyApplication.getInstance().setCurrentActivity(this);
            
    
            mReactRootView = new ReactRootView(this.getApplicationContext());
            mReactRootView.startReactApplication(MyReactNativeBridge.getInstance(), "Component-1", null);
    
            
            reactView.addView(mReactRootView);
        }
    
    }
    
    

    现在我们在真机上运行模拟器,并且命令开启ReactNative服务器(yarn start),就可以看到上面例子中的画面了。

    6、原生与ReactNative通信

    6.1、原生向ReactNative传递数据

    注意我们在startReactApplication时的语句的第三个参数initialProperties,代表由原生向ReactNative传递的参数。

    mReactRootView.startReactApplication(MyReactNativeBridge.getInstance(), "Component-1", null);
    

    现在修改创建语句和脚本

    • Java代码:通过initialProperties向JS传递参数
    public class MainActivity extends AppCompatActivity {
    
        private Bundle mockData = new Bundle();
    
        protected void onCreate(Bundle savedInstanceState) {
            
             ...
            mockData.putString("content", "初始化");
    
            mReactRootView = new ReactRootView(this.getApplicationContext());
            mReactRootView.startReactApplication(MyReactNativeBridge.getInstance(), "Component-1", mockData);
    
            reactView.addView(mReactRootView);
        }
    
    }
    
    • JS脚本:通过this.props["content"]使用原生App传递的参数(也可以使用this.props.content)
    ...
    
    export default class FrameText extends Component {
    
        render() {
            return (
                <View style={{
                    width:200,
                    height:100,
                    backgroundColor: '#CDDAF5'
                }}>
                <Text>{this.props["content"]}</Text>
                </View>
            );
        }
    }
    
    ...
    

    重新编译代码后,再次运行App,可以看到界面变成如下的样子

    ReactRootView还有一个方法setAppProperties,我们可以通过这个方法来对已经创建的View传递参数。

    • Java代码:通过setAppProperties属性向已创建的View传递参数
    protected void onCreate(Bundle savedInstanceState) {
        ...
        
        mockData.putString("content", "重加载");
        mReactRootView.setAppProperties(mockData);
        
        ...
    }
        
    

    重新编译代码后,再次运行App,可以看到界面变成如下的样子

    6.2、ReactNative向原生传递数据

    我们使用ReactContextBaseJavaModule来定义一个ReactNative中的NativeModules类型。在ReactContextBaseJavaModule中,我们可以使用@ReactMethod注解来提供结构供脚本回调。

    首先我们创建一个MyReactNativeBridge.swift文件

    package com.example.reactnativedemo;
    
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.bridge.ReactContextBaseJavaModule;
    import com.facebook.react.bridge.ReactMethod;
    
    public class MyReactNativeCommunication extends ReactContextBaseJavaModule {
    
    
        public MyReactNativeCommunication(ReactApplicationContext reactContext) {
            super(reactContext);
        }
    
    
        //提供Test方法
        @ReactMethod
        public void test(String str) {
            System.out.println(str);
        }
    
        //提供在NativeModules中该类的名字
        @Override
        public String getName() {
            return "MyReactNativeCommunication";
        }
    
    
    }
    
    
    

    然后我们使用MyReactNativePackage来注册这个类,否则脚本无法使用

    package com.example.reactnativedemo;
    
    import com.facebook.react.ReactPackage;
    import com.facebook.react.bridge.NativeModule;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.uimanager.ViewManager;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class MyReactNativePackage implements ReactPackage {
    
        @Override
        public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
        }
    
    
        @Override
        public List<NativeModule> createNativeModules(
                ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();
    
            modules.add(new MyReactNativeCommunication(reactContext));
    
            return modules;
        }
    
    }
    
    

    然后在MyReactNativeBridge将MyReactNativePackage添加到mReactInstanceManager中

    public class MyReactNativeBridge {
    
        private static final ReactInstanceManager mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(MyApplication.getInstance())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModulePath("Scprits/index")
                .addPackage(new MainReactPackage())
                .addPackage(new MyReactNativePackage())//新增MyReactNativePackage
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .setCurrentActivity(MyApplication.getInstance().getCurrentActivity())
                .build();
    }
    
    

    最后修改JS代码,调用test方法

    import { NativeModules } from 'react-native'
    
    
    export default class FrameText extends Component {
    
        render() {
            NativeModules.MyReactNativeCommunication.test("我回来啦");
            ...
        }
    }
    

    重新编译代码后,再次运行App,可以看到Android的输出 “我回来啦”

    相关文章

      网友评论

        本文标题:ReactNative混合开发-3 Android混编配置

        本文链接:https://www.haomeiwen.com/subject/nbmbgqtx.html