Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> React Native 集成到已有項目

React Native 集成到已有項目

編輯:關於Android編程

前言

React Native已經出現很久了,有很多應用也在進行嘗試,前面我們也講述了怎麼創建React Native工程以及怎麼搭建原生語言與js的開發環境。

但是在實際應用中,很多項目都不是從零開始的,而是在已有項目中進行嘗試,這就需要將React Native集成到已有項目,這裡我們就來講講怎麼集成到已有項目。

需求

這裡我們會用Android Studio創建一個工程,改工程包含有一個主頁面,裡面裡有一個跳轉按鈕,能夠跳轉到用React Native實現的頁面。

創建Android工程

這裡由於React Native是從Android 4.1開始支持的,因此我們直接創建最小版本號為16的工程。

Supported operating systems are >= Android 4.1 (API 16) and >= iOS 7.0.

創建工程很容易就完成了,現在我們加一個跳轉按鈕不過當前還不能跳轉。最終展示界面如下:
這裡寫圖片描述

Activity中處理代碼如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setViewListener();
    }

    private void setViewListener() {
        findViewById(R.id.to_react).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "go  to  React", Toast.LENGTH_LONG).show();
            }
        });
    }
}

目前這裡彈出Toast 提示,之後改為跳轉到React Native界面。

集成

這裡我們安裝官方指定的步驟來進行集成,官方集成的鏈接為:查看鏈接,在集成之前希望你已經配置好了React Native 環境,比如Node.js, watchman等。下面我們來分步驟集成。

初始化

首先在命令行進入到你所創建的工程下,第一步輸入如下命令:

npm init

這一步主要在工程下創建package.json文件,輸入命令後界面輸出如下內容:

這裡寫圖片描述

這裡需要輸入name,這裡name就是JS中AppRegistry.registerComponent(‘RNDemo’, () => xxxx)中的RNDemo,也就是項目名。不過這裡目前只能輸入小寫。之後會輸入version等信息,可以跳過某些內容直接回車。需要輸入的內容展現如下:

Press ^C at any time to quit.
name: (RNDemo1) rndeme1
version: (1.0.0) 1.0.0
description: deme
entry point: (index.js) index.android.js
test command: test
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/doc/ReactNative/RNDemo1/package.json:

{
  "name": "rndeme1",
  "version": "1.0.0",
  "description": "deme",
  "main": "index.android.js",
  "scripts": {
    "test": "test"
  },
  "author": "",
  "license": "ISC"
}

Is this ok? (yes) 

這裡輸入yes就好了。最終這些內容都會生成在package.json中。我們打開package.json看看最終生成的內容:

{
  "name": "rndeme1",
  "version": "1.0.0",
  "description": "deme",
  "main": "index.android.js",
  "scripts": {
    "test": "test"
  },
  "author": "",
  "license": "ISC"
}

這裡可以看到與我們上面輸入的內容一致,只不過name這個單詞拼寫錯了。。。

創建node module

在上面的命令執行完成後,輸入如下命令:

npm install –save react react-native

等待一段時間,我們可以在項目的根目錄發現生成了一個node module的文件夾,這一步也可以省略,直接從已有項目中拷貝過來。

創建.flowconfig

flowconfig是給flow用的,flow的作用前面已經講過了,主要用來做靜態代碼檢查。我們可以輸入如下命令在生成.flowconfig文件。

curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig

運行完成後,你可以在文件夾下看到創建了一個.flowconfig,不過這個文件是影藏的,可以Mac下你可以ls -al來查看。

修改package.json

上面的文件創建完成後,我們需要修改package.json 文件,在scripts節點下添加如下的語句:

“start”: “node node_modules/react-native/local-cli/cli.js start”

最終修改後的package.json如下:

{
  "name": "rndeme1",
  "version": "1.0.0",
  "description": "deme",
  "main": "index.android.js",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "test"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^15.3.2",
    "react-native": "^0.35.0"
  }
}

可以看到在創建node module時,已經修改了json文件,添加了react的依賴。

創建index.androd.js

在工程的跟目錄下創建index.android.js,代碼如下:

'use strict';

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

class HelloWorld extends React.Component {
  render() {
    return (
      
        Hello, World
      
    )
  }
}
var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  },
  hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

AppRegistry.registerComponent('rndeme1', () => HelloWorld);

這代碼直接從官方拷貝的,只需要主要registerComponent的第一個參數,改為我們上面輸入的內容。

修改gradle

因為我們將react集成到已有項目,而android項目是靠gradle來進行構建編譯的,因此這裡我們需要對應修改相應的內容。

1:添加react-native依賴

dependencies {
    ...
    compile "com.facebook.react:react-native:+" // From node_modules.
}

這裡需要注意的是,這裡修改是app目錄下的build.gradle文件

2:添加maven

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

這裡修改的是跟目錄下的build.gradle,放置在allprojects節點下。

添加權限

React Native是需要網絡權限的,因為他是從遠程服務器拉取的jsBundle。因此我們在AndroidManifest.xml下添加網絡權限。

添加native code

前面我們已經創建好js文件了,也配置好了其他的一些內容,這裡我們需要添加一個activity來展示React Native,這裡我們創建一個MyReactActivity的頁面。代碼從網絡拷貝:

public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                .setJSMainModuleName("index.android")
                .addPackage(new MainReactPackage())
                .setUseDeveloperSupport(BuildConfig.DEBUG)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                //.setUseOldBridge(true) // uncomment this line if your app crashes
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);

        setContentView(mReactRootView);
    }

    @Override
    public void invokeDefaultOnBackPressed() {
        super.onBackPressed();
    }
}

我們這裡就不在處理其他比如onResume等回調了。手動將所有的import導入,最後對該Activity設置theme。設置的主題為:android:theme=”@style/Theme.AppCompat.Light.NoActionBar”,因為有些組件是依賴這個主題的。

運行

到這一步我們按照官方的內容就算已經集成完成了,是不是可以開始運行了,我們來試著運行一下,首先啟動server,輸入如下命令:

npm start

 [email protected] start /Users/doc/ReactNative/RNDemo1
> node node_modules/react-native/local-cli/cli.js start

Scanning 582 folders for symlinks in /Users/doc/ReactNative/RNDemo1/node_modules (15ms)
 ┌────────────────────────────────────────────────────────────────────────────┐ 
 │  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/facebook/react-native                                  │ 
 │                                                                            │ 
 └────────────────────────────────────────────────────────────────────────────┘ 
Looking for JS files in
   /Users/doc/ReactNative/RNDemo1 

[2016-10-20 15:50:07]  Building Dependency Graph
[2016-10-20 15:50:08]  Crawling File System
[Hot Module Replacement] Server listening on /hot

React packager ready.

[2016-10-20 15:50:08]    Crawling File System (402ms)
[2016-10-20 15:50:08]  Building in-memory fs for JavaScript
[2016-10-20 15:50:08]    Building in-memory fs for JavaScript (175ms)
[2016-10-20 15:50:08]  Building in-memory fs for Assets
[2016-10-20 15:50:08]    Building in-memory fs for Assets (120ms)
[2016-10-20 15:50:08]  Building Haste Map
[2016-10-20 15:50:08]  Building (deprecated) Asset Map
[2016-10-20 15:50:08]    Building (deprecated) Asset Map (67ms)
[2016-10-20 15:50:09]    Building Haste Map (355ms)
[2016-10-20 15:50:09]    Building Dependency Graph (1061ms)

輸出如下內容,表示啟動成功了。我們是不是就可以運行了,首先我們用react-native run android來運行,這裡需要重新打一個命令窗口。運行命令後直接輸出了:

Android project not found. Maybe run react-native android first?

這裡是因為默認創建是有三年級目錄的,外層目錄,之後Android目錄,之後才是代碼,那我們采用Andriod Studio來運行。不過我們還需要改一個地方,就是之前我們的點擊事件還是彈出一個Toast,我們需要改成打開新的Activity,打開代碼如下:

Intent intent = new Intent();
intent.setClass(MainActivity.this, MyReactActivity.class);
startActivity(intent);

我們再一次運行,成功了? no,成的失敗了!~

填坑

上面我們已經運行了該工程,不過不出所料,成功的失敗了,之後還連續出現了一系列的失敗,這裡就一個一個的解決:

java.lang.UnsatisfiedLinkError

運行後出現了如下的異常:

FATAL EXCEPTION: AsyncTask #1
Process: im.yixin.rndemo2, PID: 18294
java.lang.RuntimeException: An error occured while executing doInBackground()
  at android.os.AsyncTask$3.done(AsyncTask.java:304)
  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
  at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
  at java.util.concurrent.FutureTask.run(FutureTask.java:242)
  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so
  at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:213)
  at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:178)
  at com.facebook.react.bridge.JSCJavaScriptExecutor.(JSCJavaScriptExecutor.java:25)
  at com.facebook.react.bridge.JSCJavaScriptExecutor$Factory.create(JSCJavaScriptExecutor.java:20)
  at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:183)
  at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:169)
  at android.os.AsyncTask$2.call(AsyncTask.java:292)
  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
  at java.lang.Thread.run(Thread.java:818) 

從日志可以看出是一個so鏈接錯誤,這種錯誤網絡是對應的abi不正確。

解決方案:修改app裡的build.gradle,defaultConfig節點下添加ndk節點:

ndk {
    abiFilters "armeabi-v7a", "x86"
}

來我們再一次運行:

NDK integration is deprecated in the current plugin.

運行後發現NDK重復集成了,錯誤日志如下:

Error:(13, 0) NDK integration is deprecated in the current plugin.
Consider trying the new experimental plugin
Set "android.http://blog.csdn.net/xueshanhaizi/article/details/useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration

解決方案:方案1,可以在gradle.properties下添加android.http://blog.csdn.net/xueshanhaizi/article/details/useDeprecatedNdk=true,方案2,降低gradle的版本,我們任意選擇一種方式都可以,之後在一次運行:

java.lang.IllegalAccessError,Method ‘void android.support.v4.net.ConnectivityManagerCompat

我們繼續掙扎在沒有成功的道路上,錯誤如下:

FATAL EXCEPTION: AsyncTask #1
Process: im.yixin.rndemo2, PID: 25424
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalAccessError: Method 'void android.support.v4.net.ConnectivityManagerCompat.()' is inaccessible to class 'com.facebook.react.modules.netinfo.NetInfoModule' (declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' appears in /data/data/im.yixin.rndemo2/files/instant-run/dex/slice-com.facebook.react-react-native-0.20.1_76f14c344d869afc092625e7670a68a34348b199-classes.dex)
at com.facebook.react.modules.netinfo.NetInfoModule.(NetInfoModule.java:55)
at com.facebook.react.shell.MainReactPackage.createNativeModules(MainReactPackage.java:67)
at com.facebook.react.ReactInstanceManagerImpl.processPackage(ReactInstanceManagerImpl.java:793)
at com.facebook.react.ReactInstanceManagerImpl.createReactContext(ReactInstanceManagerImpl.java:730)
at com.facebook.react.ReactInstanceManagerImpl.access$600(ReactInstanceManagerImpl.java:91)
at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:184)
at com.facebook.react.ReactInstanceManagerImpl$ReactContextInitAsyncTask.doInBackground(ReactInstanceManagerImpl.java:169)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
at java.lang.Thread.run(Thread.java:818)            

從日志可以看出是ConnectivityManagerCompat的實現獲取錯誤。

解決方案:這裡我們主要修改如下的代碼,只代碼查找的實現錯誤,之前我們添加了maven,這裡我將:

 "$rootDir/.../node_modules/react-native/android" 改成如下
 "$rootDir/node_modules/react-native/android"

改了之後,需要重新import某些路徑,因為加載的路徑變化了。在一起運行:

Application HelloWorld has not been registered

運行後,沒有錯誤log,不過展示頁面出現了錯誤,頁面如下:
這裡寫圖片描述
其實這個不算錯誤,是因為剛才我們寫Activity是沒有是拷貝的,沒有改動,這裡需要改動如下:

 mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);//將HelloWorld改成rndeme1

注意:package.json, index.android.js, activity這三處名稱需要一致

我們修改後再一次運行,到此我們就成功了運行了界面。

這裡寫圖片描述

這樣我們就成功的運行了。這裡我們將Hello World改變一下,改成其他的內容,比如Native Hello World,之後搖動手機點reload,可以發現界面已經變化了。
這裡寫圖片描述

附錄

這裡還有一些其他情況,我們分別來說一下:

彈窗不顯示

有的人搖動手機後,不能彈窗,可能是系統禁止了彈窗,需要手動開啟

網絡連接失敗

可能是情況是手機與電腦用的網絡不是同一個,需要設置為統一個網絡

Dev Setting

點擊dev Setting崩潰,這裡需要在AndroidManifest中配置如下節點:

activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

總結

到這裡,我們已經成功的將React Native集成進已有的項目,中途會碰到這樣那樣的坑,這裡遇到的坑,已經很全了,希望大家工具探討,學習。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved