原生 Android 項目集成 React Native

Oui4366 8年前發布 | 19K 次閱讀 ReactNative 移動開發 React Native

本文主要介紹原生 Android 項目集成 React Native 并用于部分頁面開發的流程。開發環境為 macOS 10.12、Android Studio 2.2.1、 React Native 0.35.0 。而官方給出的 植入原生 Android 應用指南 只對應到 0.28 版本。最新版(當前為 0.35)的集成方案稍微有些變動。

1. 創建/修改 Android 項目

用 Android Studio 創建一個 Android 項目,注意 Minimum SDK 要設置為 API 16 或以上 ,因為 React Native 要求 Android 4.1 及以上的環境。

如果現有 Android 項目且 Minimum API 小于16則修改 Minimum SDK 到16,注意部分 API 變化。

2. 添加 package.json

在 Android 項目根目錄新建文件 package.json ,內容如下

{
  "name": "react-native-sample",
  "version": "0.0.1",
  "description": "sample of react native embedding android",
  "main": "index.android.js",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "author": "danke77",
  "license": "ISC",
  "dependencies": {
    "react": "^15.3.2",
    "react-native": "^0.35.0"
  },
  "devDependencies": {
  }
}

執行 npm install 就可以安裝 dependencies 下的 npm 組件了。

這個時候在 Android 項目根目錄就生成了 node_modules/ 文件夾,里面就是一些用到的組件。

在 .gitignore 中添加

# node.js
node_modules/
npm-debug.log

執行 react-native upgrade 可以更新已有組件。

3. 添加 index.android.js

在 Android 項目根目錄創建目錄 js/ ,js 相關的代碼就放在這個文件夾下。

在 js/ 下添加 App.js ,內容如下

import React, { Component } from 'react'
import { View, Text, StyleSheet } from 'react-native'

export default class extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.text}>
          Hello React Native!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#ffffff'
  },
  text: {
    fontSize: 20,
    color: '#333333'
  }
})

在 Android 項目根目錄新建文件 index.android.js ,內容如下

import { AppRegistry } from 'react-native'
import App from './js/App'

AppRegistry.registerComponent('navigation', () => App)

這里的 navigation 一般會根據模塊功能命名,后面還會用到。

當然也可以把 App.js 的內容寫在 index.android.js 里,但這樣寫更清晰一些,尤其是項目大了文件多的情況。

4. Android 項目添加依賴

4.1 project 級別的 build.gralde

Android 默認的依賴包的源 jcenter() 不包含最新版的 React Native,新版的 React Native 都只在 npm 里發布,因此要依賴 node_modules/ 下的東西。

在 Android 項目根目錄下的 build.gradle 文件添加如下內容

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

4.2 module 級別的 build.gradle

在 Android 項目 app 目錄下的 build.gradle 文件添加如下內容

// react native
compile 'com.非死book.react:react-native:0.35.0'  // From node_modules

這里版本號要和 package.json 里的一致。

5. React Native 相關的 Activity 和 Application

5.1 Activity

創建一個繼承自 com.非死book.react.ReactActivity 的 Activity

public class HelloReactActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "navigation";
    }
}

重寫 getMainComponentName() 方法,返回的字符串必須和前面的 AppRegistry.registerComponent('navigation', () => App) 里的 navigation 對應,表示該 Activity 會顯示對應組件里的內容。

5.2 Application

Application 需要實現 com.非死book.react.ReactApplication 接口,并實現其方法

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    protected boolean getUseDeveloperSupport() {
        return BuildConfig.DEBUG
    }

    @Override
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
                new MainReactPackage(),
                new OtherReactPackage()
                // ...
        );
    }
};

@Override
public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
}

getUseDeveloperSupport() 表示是否啟動開發者模式。

getPackages() 是引用的模塊列表,默認需要添加 MainReactPackage ,如果需要在 js 里調用原生 Java 模塊,需要添加自定義的模塊(如 OtherReactPackage )。

新版這兩個方法是寫在 Application 里的,舊版都是些在 Activity 里的。

5.3 AndroidManifest.xml

在 AndroidManifest.xml 里需要添加自己創建的 Activity 和 React Native 提供的 DevSettingsActivity ,還需要添加兩個權限。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application ... >
    ... 
    <activity android:name=".HelloReactActivity" />
    <activity android:name="com.非死book.react.devsupport.DevSettingsActivity" />
</application>

HelloReactActivity 是自己創建的頁面, DevSettingsActivity 是開發調試需要用到的設置頁面。

android.permission.INTERNET 用于開發調試, android.permission.SYSTEM_ALERT_WINDOW 用于顯示懸浮窗。

6. 啟動服務

debug 模式下需要在 package.json 所在目錄下執行 npm start ,它等效于 package.json 里的 node node_modules/react-native/local-cli/cli.js start ,相當于啟動一個本地服務。

Terminal 顯示如下表示服務已正常啟動

> react-native-module@0.0.1 start /Users/danke77/Projects/react-native/HelloReactNative
> node node_modules/react-native/local-cli/cli.js start

Scanning 581 folders for symlinks in /Users/danke77/Projects/react-native/HelloReactNative/node_modules (17ms)
 ┌────────────────────────────────────────────────────────────────────────────┐
 │  Running packager on port 8081.                                            │
 │                                                                            │
 │  Keep this packager running while developing on any JS projects. Feel      │
 │  free to close this tab and run your own packager instance if you          │
 │  prefer.                                                                   │
 │                                                                            │
 │  https://github.com/非死book/react-native                                  │
 │                                                                            │
 └────────────────────────────────────────────────────────────────────────────┘
Looking for JS files in
   /Users/danke77/Projects/react-native/HelloReactNative

[2016-10-17 17:06:48] <START> Building Dependency Graph
[2016-10-17 17:06:48] <START> Crawling File System
[Hot Module Replacement] Server listening on /hot

React packager ready.

[2016-10-17 17:06:49] <END>   Crawling File System (966ms)
[2016-10-17 17:06:49] <START> Building in-memory fs for JavaScript
[2016-10-17 17:06:49] <END>   Building in-memory fs for JavaScript (260ms)
[2016-10-17 17:06:49] <START> Building in-memory fs for Assets
[2016-10-17 17:06:50] <END>   Building in-memory fs for Assets (138ms)
[2016-10-17 17:06:50] <START> Building Haste Map
[2016-10-17 17:06:50] <START> Building (deprecated) Asset Map
[2016-10-17 17:06:50] <END>   Building (deprecated) Asset Map (104ms)
[2016-10-17 17:06:50] <END>   Building Haste Map (428ms)
[2016-10-17 17:06:50] <END>   Building Dependency Graph (1825ms)

7. 開發調試

構建 Android 項目,打開應用,切換到 HelloReactActivity 頁面,通過搖一搖開啟調試菜單,選擇 Dev Settings 進入 DevSettingsActivity

Dev Settings.png

設置 Debug server host & port for device 為本機 IP 地址,添加端口號

Debug server host & port for device.png

返回到 HelloReactActivity 頁面,搖一搖選擇 Reload ,接下來就可以開始調試了。

每次修改 js 代碼只需 Reload 即可,無需重新構建整個 Android 項目,修改 Java 代碼需要重新構建。

8. 發布正式包

8.1 js bundle

React Native 的開發版需要有啟動一個本地服務隨時發送更新后的 js bundle 文件。 如果要打正式包,需要把 js bundle 文件保存到 Android 項目的 assets/ 目錄下。 這樣,正式包就不需要本地服務支持了。

在 app/src/main/ 下創建 assets/ 文件夾,執行以下命令將 js bundle 保存到資源目錄下

$ react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/

在 app/src/main/assets/ 下就會生成 index.android.bundle 文件。

開發模式調試的時候 js 代碼會立即生效,無需執行以上命令,但每次正式打包的時候如果改了 js 代碼都必須先執行以上命令。

8.2 Proguard

集成 React Native 之后如果不加相關的混淆規則,打 release 包的時候就會報錯。

 

# React Native

# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.非死book.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.非死book.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface com.非死book.common.internal.DoNotStrip

# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.非死book.proguard.annotations.DoNotStrip class *
-keep @com.非死book.common.internal.DoNotStrip class *
-keepclassmembers class * {
    @com.非死book.proguard.annotations.DoNotStrip *;
    @com.非死book.common.internal.DoNotStrip *;
}

-keepclassmembers @com.非死book.proguard.annotations.KeepGettersAndSetters class * {
  void set*(***);
  *** get*();
}

-keep class * extends com.非死book.react.bridge.JavaScriptModule { *; }
-keep class * extends com.非死book.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class *  { @com.非死book.react.uimanager.UIProp <fields>; }
-keepclassmembers class *  { @com.非死book.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class *  { @com.非死book.react.uimanager.annotations.ReactPropGroup <methods>; }

-dontwarn com.非死book.react.**

# okhttp

-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**

# okio

-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**

完成以上兩步后就可以通過 ./gradlew assembleRelease 打正式包了。

 

 

來自:http://www.jianshu.com/p/fc29c86fc2b8

 

 本文由用戶 Oui4366 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!