1. 程式人生 > >React Native 之Android混合開發,及遇到的各種坑

React Native 之Android混合開發,及遇到的各種坑

最近自己也是剛在學習React Native的知識,在學習到React Native 嵌入到原生應用的時候,感覺遇到了各種坑,這裡做一下記錄。若有說得不對的地方,謝謝大家糾正。

React Native嵌入到原生應用的教程在其官方指導文件裡也有,但是感覺很多注意點沒講到,現在,我們就一步步來,我們這裡的前提是開發環境已經搭配好。

第一步,在 Android Studio 上新建一個工程,這一步沒什麼好說的,然後在main目錄下面建立一個assets 的資料夾。

第二步,開啟下面的終端 Terminal,分別執行以下三條語句:

npm init
npm install --save react react-native
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig

先輸入 npm init ,然後會出現下面的情況,劃紅線的都是需要自己輸入的,看著我的隨便寫點就行


執行第二條命令

npm install --save react react-native
,執行完之後你會發覺多了一個叫node_modules的資料夾,接著執行第三條命令
curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig
執行完,第三條命令之後又會生成一個.flowconfig的檔案


第三步,將

"start": "node node_modules/react-native
/local-cli/cli.js start"
這條語句copy到 data.json中的scripts中,如下圖

第四步,專案根目錄中建立index.android.js檔案,然後將下面的程式碼複製貼上進來:

'use strict';

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

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

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

第五步,給工程新增React Native依賴包,如果你想下載一個隨意版本的依賴包【建議下載最新版本的React Native依賴包】,就在你APP module下面的build.gradile檔案中  的 dependencies中新增 compile "com.facebook.react:react-native:+" // From node_modules.

dependencies {
     ...
     compile "com.facebook.react:react-native:+" // From node_modules.
 }
如果你不想下載一個隨意的版本的React Native依賴包,你可以指定下你要下載的React Native依賴包的版本,首先查詢下當前最新的React Native依賴包版本,執行下面這段話,(reactnativenpm包的地址為:https://www.npmjs.com/package/react-native),或者採用命令npm info react-native進行檢視:



發覺當前最新的版本是0.39.2,那你就將 compile "com.facebook.react:react-native:+"改成 compile "com.facebook.react:react-native:0.39.2"即可


若發覺報錯,說找不到當前的依賴包,如下面的錯誤:


說明你下載的依賴包版本 與當前APP  的build.gradile中dependiences 中過的依賴包的版本不一致,這時你可以執行如下的如句,下載特定的依賴包,

npm install  --save [email protected]版本號  //我這裡就輸入:npm install  --save [email protected]


第六步,向你的工程隨對應的build.gradile檔案中新增如下這段

allprojects {
    repositories {
        ...
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
          //  url "$rootDir/../node_modules/react-///native/android" 官方給的是這一句,但是用這一句有時有問題
        url "$rootDir/node_modules/react-native/android"
        }
    }
    ...
}
然後, 因為修改了build.guild檔案,所以要async 一下工程,


不出意外,可能就會報下面的錯誤:

不要慌,在你的應用程式build.gradle新增內的下列Android { }:

configurations.all {
    resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
}

新增完成之後,再重新Async Now  一下,就行了

第七步,新增

<uses-permission android:name="android.permission.INTERNET" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
到AndroidManifest.xml中

檢查下剛才下載的React native依賴包版本是否正確,展開 External Libraries,發覺當前React native依賴包版本是0.39.2【也可以輸入命令:react-native  --version  檢視當前react native的版本號,若不一致,則可執行

npm install  --save [email protected]版本號
下載特定的版本】,正確,執行下一步,新增原生程式碼

第八步,新增原生程式碼

建立一個類,繼承ReactActivity,然後必須要重寫 getMainComponentName方法,將你index.android.js中註冊的元件的名字作為返回值,即預設為HelloWorld

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

以下是我建立的ReactActivity子類:

package com.example.administrator.reactejp;

import android.os.Bundle;
import android.view.KeyEvent;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.shell.MainReactPackage;

/**
 * Created by Administrator on 2017/1/8.
 */

public class MyReactActivity extends ReactActivity {
    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)
                .build();
        mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);

        setContentView(mReactRootView);
    }

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

    @Override
    protected void onPause() {
        super.onPause();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostResume(this, this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mReactInstanceManager != null) {
            mReactInstanceManager.onHostDestroy();
        }
    }

    @Override
    public void onBackPressed() {
        if (mReactInstanceManager != null) {
            mReactInstanceManager.onBackPressed();
        } else {
            super.onBackPressed();
        }
    }

    //該方法與彈出Reload的dialog相關,不重寫,可能不能彈出dialog
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }
}

除此之外,我們還需要定義一個ReactApplication的子類,不然執行時時會報錯的,以下是我的重寫的

package com.example.administrator.reactnativedemo;

import android.app.Application;
import android.support.v4.*;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;

import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2016/12/23.
 */

public class MyReactApplication extends Application implements 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()
            );
        }
    };

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

這裡有一點需要注意:

這兩個類中的BuildConfig並沒有導包,而是用了自動生成的一個BuildConfig.java的檔案,如下


我們修改一下當前程式的入口,修改AndroidMainfaist.xml清單檔案,將MyReactActivity作為程式的入口,開啟Genymotion模擬器,然後在Terminal 視窗,執行 npm start  命令【如果出錯可以多試幾次】,最後像正常的程式一樣啟動即可,發覺程式直接崩了,報了這樣的錯:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.administrator.reactnativedemo/com.example.administrator.reactnativedemo.MyReactActivity}: java.lang.ClassCastException: android.app.Application cannot be cast to com.facebook.react.ReactApplication

我一直不知道為什麼會報型別轉換異常的錯誤,找了好久才知道,已經要在AndroidMainfaist.xml清單檔案中指明當前Application的name屬性值為你定義的那個ReactApplication子類的名字,這裡即為MyReactApplication


檢查一下剛才執行的npm start 命令是否異常,若異常了重寫執行一下該命令即可,然後再重新執行一下程式,發覺還是報錯了,但錯誤發生了變化,如下所示:

以下方法來自百度。

方法一:【推薦使用方法】

進入專案,在android/app/src/main下新建assets目錄,關閉掉原來的npm,分別執行以下命令:

react-native start
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/
在assets資料夾下會生成index.android.bundle檔案

方法二:

進入專案,在android/app/src/main下新建assets目錄
在package.json中配置下面程式碼

"scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "bundle-android": "react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --sourcemap-output app/src/main/assets/index.android.map --assets-dest android/app/src/main/res/"
  },


再重新執行下程式,若還是有錯,再重新執行試兩次,一般都可以,到此為止,你就會看到下面的畫面:【注:要確定模擬器連線網路了】


在確保npm沒掛的情況下,執行結果如下:


到這裡為止,終於成功了!

補充:若出現Could not connect to development server,一般是npm報異常了,如果是的話,就執行 npm start 命令即可,如果不是,很有可能就是網路問題,這裡提供種方法解決網路問題:

第一種:最常見的方式,點選上圖紅框區域,彈出一個dialog,選擇Dev Setting,以下幾張圖片來自:http://www.jianshu.com/users/e630681e7001/latest_articles

將localHost換成,你的電腦的IP地址

最後,感謝http://www.jianshu.com/users/e630681e7001/latest_articles

相關推薦

React Native Android混合開發遇到的各種

最近自己也是剛在學習React Native的知識,在學習到React Native 嵌入到原生應用的時候,感覺遇到了各種坑,這裡做一下記錄。若有說得不對的地方,謝謝大家糾正。 React Native嵌入到原生應用的教程在其官方指導文件裡也有,但是感覺很多注意點沒講到,現

React-Native Android應用開發紀 (一)————windows環境下配置

歡迎轉載,轉載註明出處: 我不只是看客 自從在公司中被老大安利了移動開發的未來 React-Native之後開始關注相關,想嘗試相關app開發。正好畢業準備畢設,腦子一熱就選擇了RN來開發一款app……題目上交就不能改了,現在好後悔。。。但硬著頭皮上吧 ,廢

react nativeAndroid混合開發

想要進行混合開發你需要一定的android基礎,廢話不多說,直接上圖: 在index.android.js 中註冊3個元件,分別為A、B、C,其中程式碼基本相同: 點選text控制元件調到下一個activity,跳轉activity需要原生的支援,我

Android混合開發html5自己主動更新爬過的

script loadurl 處理 必須 ack 功能 是個 code ppt 如今使用混合開發的公司越來越多,盡管出現了一些新技術,比方Facebook的react native、阿裏的weex,但依舊阻擋不了一些公司採用h5的決心。當然,這也是從多方

windows下配置React-NativeAndroid開發環境總結

首先配置環境我們需要用到以下工具: node.js react-native-cli Android Studio JDK(1.8以上) SDK python 1.安裝node.js和react-native-cli命令列工具

React Native在Ubuntu16下開發環境安裝期間遇到的問題

最近去了一家公司,採用的是React Native開發App。公司是在windows環境下開發的,環境也有人配好了。自己回家準備在linux下搞開發,裝環境才知道坑一大堆。下面是我遇到的一系列問題: 1.react-native run-android throw new TypeErr

React Native macOS Android 搭建開發環境

這個講的是React Native完整的原生開發環境。 這個環境的搭配,會根據你使用的作業系統、針對的目標平臺不同,具體的搭配步驟就會有所不同;如果想同時開發iOS和Android也是沒有問題的,你需要先選一個平臺開始,對於另一個平臺的環境搭建只是稍有不同。 開發平臺:macOS、Windows

React Native macOS Android 搭建開發環境

這個講的是React Native完整的原生開發環境。 這個環境的搭配,會根據你使用的作業系統、針對的目標平臺不同,具體的搭配步驟就會有所不同;如果想同時開發iOS和Android也是沒有問題的,你需要先選一個平臺開始,對於另一個平臺的環境搭建只是稍有不同。 開發平臺:macOS

React NativeAndroid原生通過DeviceEventEmitter傳送訊息給js

1 問題 Android原生向js發訊息,並且可以攜帶資料 2 實現原理 Android原生可以使用RCTEventEmitter來註冊事件,然後這裡需要指定事件的名字,然後在js那端進行監聽同樣事件的名字監聽,就可以收到訊息得到資料 Android註冊關

react-native android 配置gif圖片的使用----------小白的天堂

React-native顯示動態圖片(gif)的配置 突然心血來潮,想把專案中的loading效果換成動態圖片的樣式,這樣會好看一些不會那麼單調。然後開始了我的踩坑之路。。。。 首先,檢視官方網站(react-native中文網),然後選擇對應自己的版本號的文件 我的是0.50

React Native 元件化開發

前言 學習本系列內容需要具備一定 HTML 開發基礎,沒有基礎的朋友可以先轉至 HTML快速入門(一) 學習 本人接觸 React Native 時間並不是特別長,所以對其中的內容和性質瞭解可能會有所偏差,在學習中如果有錯會及時修改內容,也歡迎萬能的朋友們批

React NativeAndroid 和 iOS在點選觸發事件時的相容性處理

最近,我在專案中遇到了一個bug,bug的情況描述大致如下: 當點選按鈕A時,彈出彈層,彈層有一個按鈕B,邏輯是:當點選按鈕B時,首先彈層消失,緊接著開始調取C介面流程。在Android上正確顯示,但是iOS中只是彈層消失,並沒有調取C介面事件。 對於這種情況,我之前開發過

Android混合開發html5自動更新爬過的

現在使用混合開發的公司越來越多,雖然出現了一些新技術,比如Facebook的react native、阿里的weex,但依然阻擋不了一些公司採用h5的決心,當然,這也是從多方面考慮的選擇。 在三年前就使用過html5混合開發,當時做的是一款貴金屬軟體,漲跌五線

React-NativeAndroid:原生介面與React介面的相互呼叫

這裡原生介面是指用佈局檔案實現或Java程式碼實現view的Activity,React介面是指用ReactJS實現的介面的Activity。 從某種角度看,React只是充當了Android裡的view層,因此原生介面與React介面的相互呼叫及資料傳遞同原生介面之間的互

React NativeAndroid 5.0以下系統WebView訪問https頁面變成空白頁

在我們的React Native專案中,需要開發一個tab頁面專門配置三方h5連結,供使用者瀏覽。自動化測試:Android 5.0以下系統此tab頁面為空白頁面。看效果: 而我們去檢視這個三方的

React native android的圖示和啟動圖片

哎哎呀呀,上篇說到了react native的IOS的圖示和啟動圖片的設定,其實最主要的是尺寸!相應的尺寸設定好了以後就不會報錯了!ok~這篇說的是React native的android的圖示和啟動頁面!!!!!1.圖示:其實android的圖示設定很簡單,一般情況下只需要替換就可以了(當然你也可以不去替換

es6+require混合開發兼容es6 moduleimport,export 加載css公用date-main

plugins symbol 默認參數 安裝插件 alt 路徑 目的 編譯參數 row 大家好!上篇文章已經介紹了搭建文件夾,以及加載js文件。現在講一下加載css ,以及對baseUrl的理解 1.對項目結構的認知 一個項目的結構是根據項目的架構來決定的,當然也可以做到更

React-Native開發react-navigationAndroid的打包與釋出

1前言 RN的開發中正式釋出前需要打包與簽名,然後才能上架各家應用市場。打包需要將js與圖片資原始檔打包進apk檔案中,生成index.android.bundle與index.android.bundle.meta檔案。下面介紹RN開發中打包APK的主要步驟,IOS沒研究過,不再本

React Native Android混合開發實用教程

期待已久的新課上線啦!解鎖React Native開發新姿勢,一網打盡React Native最新與最熱技術,點我Get!!! 在React Native的應用場景中,有時候一個APP只有部分頁面是由React Native實現的,比如:我們常用的攜程App,它的首頁下

混合開發的大趨勢之一React Native簡單的登入介面

這些天都在學習RN這部分吧,然後寫了個簡單的登陸業務,從“實戰”中講解吧 先上下效果圖 效果很簡單就是2個<Text/> 2個<TextInput/>1個<Button/> 按鈕控制元件是第三方的,就是為了演示下如何在