ReactNative混合開發(fā)-3 Android混編配置

開發(fā)語言:ReactNative 0.59.5 Android
開發(fā)環(huán)境:VSCode Android Studio 3.4

1、項目目錄

參考文章:集成到現(xiàn)有原生應(yīng)用

首先,我們按照建立一下目錄結(jié)構(gòu),其中:
Code目錄放置所有公用的ReactNative腳本,包,以及相關(guān)配置。
Android目錄放置原Android項目。

Code (根目錄)
--Android(一級目錄)

2、開發(fā)環(huán)境準備

2.1、package.json配置

在Code目錄下創(chuàng)建package.json文件,編輯文件輸入以下內(nèi)容。

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

2.2、React和React Native模塊安裝

在Code目錄下使用控制臺執(zhí)行以下語句來安裝React Native。

yarn add react-native
  • 注意,執(zhí)行完以上命令后,可能會出現(xiàn)以下提示內(nèi)容,表示我們需要安裝指定版本的React(此例子中需要安裝版本為16.8.3的React)。

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

在Code目錄下使用控制臺執(zhí)行以下語句來安裝指定版本的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路徑應(yīng)該指向根目錄code中的node_modules,
    }
}

3.3、在AndroidManifest.xml聲明網(wǎng)絡(luò)權(quán)限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.reactnativedemo" >
    
    
    <uses-permission android:name="android.permission.INTERNET" /> //新增網(wǎng)絡(luò)權(quán)限
     ...
</manifest>

3.4、在AndroidManifest.xml配置調(diào)試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
    
        ...
        //調(diào)試Activiy,使用搖一搖呼出
        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
        
 
 
     </application>

</manifest>

4、腳本創(chuàng)建

在Code根目錄下創(chuàng)建Scripts文件夾,用于存放React Native的腳本文件

Code (根目錄)
--Scripts(一級目錄,用于存放所有React Native的腳本)

然后我們可以在Scripts目錄下開始寫ReactNative的腳本了。
首先我們創(chuàng)建一個FrameText.js,然后寫入如下內(nèi)容:

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中,我們創(chuàng)建了一個簡單的組件,供其他腳本使用。

然后我們再創(chuàng)建一個index.js,然后寫入如下內(nèi)容

import {AppRegistry} from 'react-native'
import {FrameText} from 'FrameText'


// 整體js模塊的名稱
AppRegistry.registerComponent('Component-1', () => FrameText);

在index中,我們注冊了FrameText組件,供app使用,我們可以在index.js注冊很多不同的組件,app可以通過我們注冊的名字(本例中為Component-1)來創(chuàng)建這些組件,下面我們來看看怎么在app內(nèi)使用他們。

5、Android項目修改

本例中期望在app的一個controller內(nèi),同時使用原生語言與ReactNative腳本分別顯示2個View,現(xiàn)在我們來看看是如果在原生app中加載ReactNative的View。

5.1、創(chuàng)建 MyReactNativeBridge

新建一個Java文件,創(chuàng)建MyReactNativeBridge類,顧名思義,此類負責(zé)橋接原生app與ReactNative,注意,一個app中最好只創(chuàng)建一個橋接實例,所以使用單利模式創(chuàng)建。

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("Scripts/index")
            .addPackage(new MainReactPackage())
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            //注冊彈出調(diào)試菜單的Activity,發(fā)布版可以無需注冊
            .setCurrentActivity(MyApplication.getInstance().getCurrentActivity())
            .build();

    private MyReactNativeBridge() {
    
    }

    public static ReactInstanceManager getInstance() {
        return mReactInstanceManager;
    }
}


5.2、創(chuàng)建并使用ReactRootView

ReactRootView為ReactNative腳本描述的View,它繼承FrameLayout,我們可以通過MyReactNativeBridge來創(chuàng)建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);
    }

}

現(xiàn)在我們在真機上運行模擬器,并且命令開啟ReactNative服務(wù)器(yarn start),就可以看到上面例子中的畫面了。

6、原生與ReactNative通信

6.1、原生向ReactNative傳遞數(shù)據(jù)

注意我們在startReactApplication時的語句的第三個參數(shù)initialProperties,代表由原生向ReactNative傳遞的參數(shù)。

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

現(xiàn)在修改創(chuàng)建語句和腳本

  • Java代碼:通過initialProperties向JS傳遞參數(shù)
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傳遞的參數(shù)(也可以使用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,我們可以通過這個方法來對已經(jīng)創(chuàng)建的View傳遞參數(shù)。

  • Java代碼:通過setAppProperties屬性向已創(chuàng)建的View傳遞參數(shù)
protected void onCreate(Bundle savedInstanceState) {
    ...
    
    mockData.putString("content", "重加載");
    mReactRootView.setAppProperties(mockData);
    
    ...
}
    

重新編譯代碼后,再次運行App,可以看到界面變成如下的樣子

6.2、ReactNative向原生傳遞數(shù)據(jù)

我們使用ReactContextBaseJavaModule來定義一個ReactNative中的NativeModules類型。在ReactContextBaseJavaModule中,我們可以使用@ReactMethod注解來提供結(jié)構(gòu)供腳本回調(diào)。

首先我們創(chuàng)建一個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("Scripts/index")
            .addPackage(new MainReactPackage())
            .addPackage(new MyReactNativePackage())//新增MyReactNativePackage
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .setCurrentActivity(MyApplication.getInstance().getCurrentActivity())
            .build();
}

最后修改JS代碼,調(diào)用test方法

import { NativeModules } from 'react-native'


export default class FrameText extends Component {

    render() {
        NativeModules.MyReactNativeCommunication.test("我回來啦");
        ...
    }
}

重新編譯代碼后,再次運行App,可以看到Android的輸出 “我回來啦”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容