開發(fā)語言:ReactNative 0.59.5 Android
開發(fā)環(huán)境:VSCode Android Studio 3.4
1相叁、項(xiàng)目目錄
首先遵绰,我們按照建立一下目錄結(jié)構(gòu)辽幌,其中:
Code目錄放置所有公用的ReactNative腳本,包椿访,以及相關(guān)配置乌企。
Android目錄放置原Android項(xiàng)目。
Code (根目錄)
--Android(一級(jí)目錄)
2成玫、開發(fā)環(huán)境準(zhǔ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目錄下使用控制臺(tái)執(zhí)行以下語句來安裝React Native。
yarn add react-native
- 注意钦勘,執(zhí)行完以上命令后陋葡,可能會(huì)出現(xiàn)以下提示內(nèi)容,表示我們需要安裝指定版本的React(此例子中需要安裝版本為16.8.3的React)彻采。
warning " > react-native@0.59.5" has unmet peer dependency "react@16.8.3".
在Code目錄下使用控制臺(tái)執(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肛响、在項(xiàng)目的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(一級(jí)目錄虎囚,用于存放所有React Native的腳本)
然后我們可以在Scripts目錄下開始寫ReactNative的腳本了臼寄。
首先我們創(chuàng)建一個(gè)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)建了一個(gè)簡(jiǎn)單的組件,供其他腳本使用适揉。
然后我們?cè)賱?chuàng)建一個(gè)index.js留攒,然后寫入如下內(nèi)容
import {AppRegistry} from 'react-native'
import {FrameText} from 'FrameText'
// 整體js模塊的名稱
AppRegistry.registerComponent('Component-1', () => FrameText);
在index中,我們注冊(cè)了FrameText組件嫉嘀,供app使用炼邀,我們可以在index.js注冊(cè)很多不同的組件,app可以通過我們注冊(cè)的名字(本例中為Component-1)來創(chuàng)建這些組件剪侮,下面我們來看看怎么在app內(nèi)使用他們拭宁。
5、Android項(xiàng)目修改
本例中期望在app的一個(gè)controller內(nèi)瓣俯,同時(shí)使用原生語言與ReactNative腳本分別顯示2個(gè)View杰标,現(xiàn)在我們來看看是如果在原生app中加載ReactNative的View。
5.1彩匕、創(chuàng)建 MyReactNativeBridge
新建一個(gè)Java文件腔剂,創(chuàng)建MyReactNativeBridge類,顧名思義驼仪,此類負(fù)責(zé)橋接原生app與ReactNative掸犬,注意,一個(gè)app中最好只創(chuàng)建一個(gè)橋接實(shí)例绪爸,所以使用單利模式創(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)
//注冊(cè)彈出調(diào)試菜單的Activity,發(fā)布版可以無需注冊(cè)
.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)在我們?cè)谡鏅C(jī)上運(yùn)行模擬器仇味,并且命令開啟ReactNative服務(wù)器(yarn start)呻顽,就可以看到上面例子中的畫面了。
6丹墨、原生與ReactNative通信
6.1廊遍、原生向ReactNative傳遞數(shù)據(jù)
注意我們?cè)趕tartReactApplication時(shí)的語句的第三個(gè)參數(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>
);
}
}
...
重新編譯代碼后喉前,再次運(yùn)行App没酣,可以看到界面變成如下的樣子
ReactRootView還有一個(gè)方法setAppProperties,我們可以通過這個(gè)方法來對(duì)已經(jīng)創(chuàng)建的View傳遞參數(shù)卵迂。
- Java代碼:通過setAppProperties屬性向已創(chuàng)建的View傳遞參數(shù)
protected void onCreate(Bundle savedInstanceState) {
...
mockData.putString("content", "重加載");
mReactRootView.setAppProperties(mockData);
...
}
重新編譯代碼后裕便,再次運(yùn)行App,可以看到界面變成如下的樣子
6.2见咒、ReactNative向原生傳遞數(shù)據(jù)
我們使用ReactContextBaseJavaModule來定義一個(gè)ReactNative中的NativeModules類型偿衰。在ReactContextBaseJavaModule中,我們可以使用@ReactMethod注解來提供結(jié)構(gòu)供腳本回調(diào)改览。
首先我們創(chuàng)建一個(gè)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來注冊(cè)這個(gè)類下翎,否則腳本無法使用
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("我回來啦");
...
}
}
重新編譯代碼后宝当,再次運(yùn)行App视事,可以看到Android的輸出 “我回來啦”