Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 如何把React Native嵌入到原生android應用中

如何把React Native嵌入到原生android應用中

編輯:關於Android編程

原生應用不僅可以跳轉到RN頁面,也可以吧RN的組件放到原生應用中,作為原生應用的一部分。

首先介紹如何把react native嵌入到android中,然後再介紹如何把RN嵌入到ios中;

第一部分:將RN嵌入到android中的步驟如下

一、用Android Studio 創建一個程序,我的是RnInAndroid;

二、打開命令行終端,進入RnInAndroid,

2.1、輸入以下命令:

npm init

然後會創建一個package.json的文件,搞過RN的我們知道,這是RN的配置文件,下面需要我們輸入一些信息:

\

2.2、輸入yes,創建好package.json文件,然後輸入:

npm install--save react react-native

會自動聯網下載rn的組件庫node_modules,

2.3、接著輸入:

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

2.4、進入項目下面,打開剛才創建的package.json,在"scripts"--》 "test"的這一行後面添加個逗號,要不然報錯的,這是json的格式,然後在test的下一行,添加一行代碼:

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

\

2.5、然後在項目目錄下穿件一個index.android.js的文件,然後把下面的代碼拷貝到文件中,下面的代碼是RN的代碼,現實的是一個頁面,裡面有一個Text的組件,相當於android中的textview:

'use strict';

import React from 'react';

import{

AppRegistry,

StyleSheet,

Text,

View} from 'react-native';

classHelloWorld extends React.Component{

render(){

return(

這就是RN的頁面哦

我是劉成

 

)

}

}

var styles = StyleSheet.create({

container:{

flex:1,

justifyContent:'center',

},

hello:{

fontSize:20,

textAlign:'center',

margin:10,

},

});

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

2.6、把你的項目下面的app(我的是 RnInAndroid/app)下的build.gradle文件打開,

在 dependencies 的代碼塊內,添加如下代碼:

compile"com.facebook.react:react-native:+"

2.7、在項目根目錄的build.gradle(我的是:RnInAndroid/build.gradle)中添加react native 路徑,這個文件和上面的那個build.gradle文件不一樣哦:找到 allprojects代碼塊,找到repositories,在這個代碼塊內添加如下的代碼:

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

如:\

2.8、打開項目名/app/src/main/AndroidManifest.xml,在manifest標簽內,和application同一級,添加聯網權限:

三、添加原生代碼

3.1、在項目名/app/src/main/java/com/項目名.../rninandroid/,在這個目錄下面創建一個java文件,文件名為:MyReactActivity.java,

然後復制下面的代碼:

package com.example.vittorio.rninandroid;

import android.app.Activity;
import android.os.Bundle;

import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;

/**
 * Created by vittorio on 2016/10/14.
 */
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();
    }
}

 

注意:

3.1.1、如果你用的是android studio的話,點擊最上面的build菜單,clean project,然後會提示你有些包沒有導入,按 alt + enter,一個一個的導入包;

3.1.2、上面代碼的第一行:package是你自己的包名,在AndroidManifest.xml裡面的package屬性值裡面有;

3.1.3、如果你的index.android.js的 AppRegistry.registerComponent('Liucheng', () => Liucheng),那就把上面代碼中的"HelloWorld"改成“Liucheng”,我這裡是Liucheng舉個例子,

 

mReactRootView.startReactApplication(mReactInstanceManager, "Liucheng", null);點擊
3.1.4、如果出現下面的錯誤:
Error:Conflict with dependency 'com.google.code.findbugs:jsr305'. Resolved versions for app (3.0.0) and test app (2.0.1) differ. See
http://g.co/androidstudio/app-test-app-conflictfor details

\
解決辦法:需要在你的根目錄的build.gradle中的android代碼快內,添加如下的代碼:

configurations.all { resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0' }
如下圖所示:

\
3.1.5、重新編譯:在android studio(簡稱:AS)中點擊上邊的build菜單,選擇rebuild project;
3.2、在AndroidManifest.xml文件中,注冊剛才新建的activity(MyReactActivity),並為它指定一個主題:

 
3.3、在 MyReactActivity.java文件中添加生命周期函數:

@Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onPause(); } } @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onResume(this, this); } } @Override protected void onDestroy() { super.onDestroy(); if (mReactInstanceManager != null) { mReactInstanceManager.onDestroy(); } } // We also need to pass back button events to React Native: @Override public void onBackPressed() { if (mReactInstanceManager != null) { mReactInstanceManager.onBackPressed(); } else { super.onBackPressed(); } }
3.4、添加按鍵的響應,默認的意思是搖動設備出來菜單,但是在模擬器中不好使,所以我們需要添加相應的代碼來處理物理按鍵,用as的模擬器按下ctrl+M會觸發響應的按鍵:下面的代碼也是在MyReactActivity.java文件中添加的哦:

@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { mReactInstanceManager.showDevOptionsDialog(); return true; } return super.onKeyUp(keyCode, event); }
3.5、在MainActivity.java的布局中(activity_main.xml中)添加一個按鍵,並在MAinActivity中添加這個按鍵的作用,作用是按下這個按鍵,就跳轉到RN的界面,也就是跳轉到MyReactActivtiy,具體代碼如下:

\
3.6、現在命令行中啟動nodejs服務器:
	 npm start
3.7、打開模擬器(我用的是Genymotion,你也可以用as自帶的模擬器或者真機測試),然後在AS運行點擊Run:
四、坑爹了,原生的代碼能正常顯示,但是點擊跳轉RN的界面,就退出了,
4.1、報錯如下:
E/AndroidRuntime: FATAL EXCEPTION: main
         Process: com.example.vittorio.rninandroid, PID: 13885
         android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@d6bfdbd -- permission denied for window type 2003
           at android.view.ViewRootImpl.setView(ViewRootImpl.java:702)
           at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342)
           at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
           at android.app.Dialog.show(Dialog.java:316)
           at com.facebook.react.devsupport.DevSupportManagerImpl.handleReloadJS(DevSupportManagerImpl.java:538)
           at com.facebook.react.ReactInstanceManagerImpl$3$1.run(ReactInstanceManagerImpl.java:386)
           at android.os.Handler.handleCallback(Handler.java:751)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:154)
           at android.app.ActivityThread.main(ActivityThread.java:6077)
           at java.lang.reflect.Method.invoke(Native Method)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
解決辦法:增加權限:

  
4.2、但是依舊報錯,在activit的點擊事件裡面添加:

\
4.3、依舊報錯:
java.lang.IllegalAccessError: Method 'void android.support.v4.net.ConnectivityManagerCompat.()' is inaccessible to class 'com.f
acebook.react.modules.netinfo.NetInfoModule' (declaration of 'com.facebook.react.modules.netinfo.NetInfoModule' appears in
/data/app/package.name-2/base.apk)
解決辦法:(老外也遇到了這樣的問題https://github.com/facebook/react-native/issues/6152#issuecomment-200759453)
在項目下修改以下的文件內容:

  • .gitignore(在該文件裡添加排除項,node_modules/ 和 npm-debug.log)

  • app/build.gradle (將 'com.android.support:appcompat-v7:24.2.1' 改為 'com.android.support:appcompat-v7:23.0.1')

  • gradle.properties (在文件末尾添加,android.useDeprecatedNdk=true)

4.4、編譯依舊報錯:
undefined is not a function (evaluating 'remoteModules.forEach')

\
解決辦法:
在項目下面的build.gradle為把

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

maven { // All of React Native (JS, Android binaries) is installed from npm url "$rootDir/node_modules/react-native/android" }
,因為$rootDir就是你的項目目錄,如果用../的話,找不到這個目錄就會報錯的
4.5.依舊報錯啊,報錯啊:
Error:(52, 34) 錯誤: 找不到符號
符號:  方法 onPause()
位置: 類型為ReactInstanceManager的變量 mReactInstanceManager
Error:(61, 34) 錯誤: 找不到符號
符號:  方法 onResume(MyReactActivity,MyReactActivity)
位置: 類型為ReactInstanceManager的變量 mReactInstanceManager
Error:(70, 34) 錯誤: 找不到符號
符號:  方法 onDestroy()
位置: 類型為ReactInstanceManager的變量 mReactInstanceManager
解決原因:找了好長時間的答案,也沒有找到原因在哪兒,只能先把onpause、onResume、onDestroy這三個方法注釋掉,
編譯成功啦!!!真高興啊真高興;

\
4.6、但是進入RN的頁面後按下Ctrl+M,沒反應,不能調出調試菜單:
在AndroidMenifest.xml文件中添加:

就可以了
五、將RN作為組件嵌入到android中作為一個控件使用:
5.1、我們注意到在MyReactActivtiy.java文件中,我們發現其實這個activity加載頁面也用的是
setContentView(mReactRootView);

只要我們新建一個xml的布局文件,布局中添加一個linearlayout或者relativelayout布局,然後在代碼中把這個RN的布局添加進去就行了,或者是在xml中直接添加RN布局代碼:

下面就兩種凡是貼出代碼,供大家參考使用:

第一種種新建一個myreactactivity.xml布局文件:

 



    
    

在MyReactActivtiy.java中修改代碼,紅色部分為增加的內容:

 

 

package com.example.vittorio.rninandroid;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.LinearLayout;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
/**
 * Created by liucheng on 2016/10/14.
 */
public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
    private ReactInstanceManager mReactInstanceManager;
    private LinearLayout ll;

    @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(R.layout.myreactactivity);
        initView();
    }

    。。。
    private void initView() {
        ll = (LinearLayout) findViewById(R.id.ll);
        ll.addView(mReactRootView);
    }
}
第二種方法直接在布局中引用ReactRootView控件:

 

 



    
    
        
        
        

     

 

代碼文件為:

 

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

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

//        mReactRootView = new ReactRootView(this);注釋掉這一行,不新建一個RN的view了,因為我們已經引用了,不需要重新創建了
        mReactRootView = (ReactRootView)findViewById(R.id.rnview);
        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);

//        initView();
    }

    ...   //記得把上面新建的的initView()方法給刪除其他的和上面類似
}
\

 

六、今天到此為止吧,本來還想把IOS端的搞一下,明天再發一篇文章吧,各種坑各種坑!!!我在修路我在補坑,讓你們踏著我們的肩膀跑的更高看的更遠;

留個小問題:RN頁面如何返回到原生頁面上,如何處理android的物理返回按鍵,等我後天處理教大家哦!

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