ReactNative從零到完整項(xiàng)目-嵌入到安卓原生應(yīng)用(方式二)

項(xiàng)目連接: RNHelloWorld
ReactNative使用手冊

重要說明:

本文和ReactNative從零到完整項(xiàng)目-嵌入到安卓原生應(yīng)用(方式一)步驟上從第八步開始不一樣其它都一樣五慈,之所以分開成兩篇俏拱,一是我自己本來就是兩個(gè)項(xiàng)目按兩種方式完成的,二是為了看起來更清晰衩茸,如果看過上一篇,那么這一篇可以直接跳到第八步開始看慢叨,文章結(jié)尾給出參考博客鏈接

把React Native組件植入到Android應(yīng)用

第一步:引入react-native

在androidstudio的Terminal窗口中輸入 npm init,接著會提示你輸入一些東西(除了項(xiàng)目名字其他都可直接回車使用默認(rèn)值)
當(dāng)我們輸完的時(shí)候?qū)⒐こ糖袚Q到project模式下寺渗,可以看到工程多了一個(gè)package.json的文件

{
"name": "rnhello",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
},
"author": "賴天兵",
"license": "ISC"
}

看到這個(gè)文件有一種很熟悉但又陌生的感覺,但是它的作用都應(yīng)該猜到了扭倾,這個(gè)和我們build.gradle中的配置是一樣的作用,其實(shí)就是配置工程的一些屬性

第二步:添加react和react_native模塊

在Terminal窗口中輸入:npm install --save react react-native并執(zhí)行挽绩,然后就是靜靜的等待膛壹,如果有報(bào)錯(cuò),自己手動(dòng)敲"--"這個(gè)符號唉堪,因?yàn)樵诓煌南到y(tǒng)下“--”可能是不一樣的,完成后就可以看到工程多了一個(gè)node_modules模塊

node_modules

第三步:在命令行中運(yùn)行curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig(這步對Windows來說真的坑)

直接運(yùn)行會提示你:'curl' 不是內(nèi)部或外部命令模聋,也不是可運(yùn)行的程序

所以看來我的首先處理Windows運(yùn)行curl命令的問題了

curl是利用URL語法在命令行方式下工作的開源文件傳輸工具。它被廣泛應(yīng)用在Unix唠亚、多種Linux發(fā)行版中链方,并且有DOS和Win32、Win64下的移植版本灶搜。
所以首先要解決Windows下支持curl命令的問題Windows下安裝使用curl命令
提示有可能你找不到| curl-7.33.0-win64-ssl-sspi.zip

提示

再提示一下當(dāng)你按照上面Windows下安裝使用curl命令走到了下圖步驟時(shí)

命令行步驟

這時(shí)候應(yīng)該在命令窗口中輸入curl -v -X OPTIONS https://www.baidu.com/祟蚀,這是文檔沒有說的,而是直接輸入到命令行里了割卖,第一次看如果不知道這個(gè)前酿,那會很懵逼的
不過遺憾的是我按照上門的連接文檔一步步走下來還是無法在任何地方使用curl命令(我的電腦win10 64位)

所以我用了最簡單的方法,直接復(fù)制我們下載的curl.exe到工程根目錄鹏溯,這樣在本工程的根目錄就能運(yùn)行curl命令了

但是:真想爆粗口罢维,還是生成不了.flowconfig文件,

所以真正最直接的解決方式來了:自己在項(xiàng)目的根目錄下創(chuàng)建.flowconfig文本文件丙挽,然后打開.flowconfig連接復(fù)制文本到剛剛創(chuàng)建的文件中即可
image.png

走到這里突然想感嘆一句言津,我饒了一大圈到底是為了啥

第三步:在package.json文件中的scripts里面配置啟動(dòng)腳本"start": "node node_modules/react-native/local-cli/cli.js start",

{
  "name": "rnhello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "bundle-android": "react-native bundle --platform android --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --dev false"
  },
  "author": "賴天兵",
  "license": "ISC",
  "dependencies": {
    "react": "^16.2.0",
    "react-native": "^0.53.3"
  }
}

其實(shí)在官方文檔中第三步已經(jīng)完了攻人,但是畢竟我是踏過了很多巨坑的,看了很多篇博客的我告訴你這步還沒完悬槽,照常理這里還應(yīng)該配置打包用index.android.js生成index.andriod.bundle的配置(你也可以嘗試不做,絕對會出現(xiàn)一些經(jīng)典的bug瞬浓,這里就不提了初婆,我會有一篇專門的文章記錄這些bug)

配置生成發(fā)布、打包時(shí)所需要bundle文件的配置

在很多博客中會這樣解決這個(gè)問題猿棉,像上面完整package.json中的scripts代碼一樣添加
, "bundle-android": "react-native bundle --platform android --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --dev false"
這一句在官方文檔中沒有說明磅叛,但是最好加上(雖然我加上后,至少我這里沒有卵用萨赁,據(jù)說是新版本的RN不支持自動(dòng)生成打包所需的bundle文件了)弊琴,但是這里需要修改一下,很多博客都直接是
"bundle-android": "react-native bundle –platform android –dev false –entry-file index.android.js –bundle-output android/app/src/main/assets/index.android.bundle –sourcemap-output android/app/src/main/assets/index.android.map –assets-dest android/app/src/main/res/"
但是這是錯(cuò)的杖爽,打包的時(shí)候我們都要根據(jù)自己項(xiàng)目目錄的結(jié)果做一些調(diào)整敲董,不過在上面package.json中我已經(jīng)做過調(diào)整了,但是還是無法自動(dòng)完成打包bundle
解決:我們先在main下面創(chuàng)建asserts文件夾慰安,然后進(jìn)入工程根目錄打開cmd輸入
react-native bundle --platform android --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --dev false(注意-output后面的參數(shù)根據(jù)自己的項(xiàng)目目錄結(jié)構(gòu)來寫)

生成打包bundle文件

成功后的項(xiàng)目
image.png

你或許看過很多在安卓原始項(xiàng)目中嵌套RN腋寨,并按照他們步驟一步步完成了,但是最后就是看不到效果化焕,這里就是其中一個(gè)重要的原因

如果這步完成了萄窜,那么恭喜你,你基本上能看到效果了撒桨,后面可能還要出bug查刻,但是都是些容易解決的固定的了

第四步:在項(xiàng)目根目錄中創(chuàng)建index.android.js文件

index.android.js

在index.android.js中編寫我們的代碼

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

class HelloWorldApp extends React.Component {
  render() {
return (
  <View style={styles.container}>
<Text style={styles.hello}>Hello world! I am from ReactNattive!!</Text>
  </View>
)
  }
}
var styles = StyleSheet.create({
  container: {
flex: 1,
justifyContent: 'center',
  },
  hello: {
fontSize: 20,
textAlign: 'center',
margin: 10,
  },
});
//這里的第一個(gè)參熟名字要和我們創(chuàng)建的這個(gè)工程項(xiàng)目名一樣
AppRegistry.registerComponent('RNHelloWorld', () => HelloWorldApp);

提示:在本系列RN博客的第二篇?jiǎng)?chuàng)建HelloWorld的時(shí)候說過,registerComponent()注冊時(shí)名字必須和項(xiàng)目名字保持一致

第五步:添加ReactNative依賴

首先在APP的build.gradle中添加
dependencies { ... compile "com.facebook.react:react-native:+" // From node_modules. }

其次在工程的build.gradle中添加進(jìn)入本地ReactNative倉庫的路徑凤类,但是官方源文檔寫的路徑是
$rootDir/../node_modules/react-native/android
如果你直接復(fù)制使用穗泵,恭喜你你又入坑了
因?yàn)槲覀兺ㄟ^之前第二步添加的添加react和react_native模塊,默認(rèn)是項(xiàng)目的根目錄下踱蠢,而官方文檔給出的路徑其實(shí)是多了“../”所以這就是一個(gè)坑(說到這里提一句火欧,網(wǎng)上很多文章都是直接用的官方路徑,但是項(xiàng)目結(jié)構(gòu)又和我的一樣茎截,我真懷疑他們寫那個(gè)文章的時(shí)候只是copy別人文章苇侵,自己根本沒有成功,這也是很多人按照別人文章一步步到最后還是報(bào)錯(cuò)的又一個(gè)原因)企锌,這里路徑應(yīng)該對應(yīng)自己工程中module的路徑
我的工程目錄

image.png

所以我的路徑應(yīng)該是

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

添加完成后記得同步以下哦榆浓,不過等待的時(shí)間過于漫長(最好開VPN,我是開了VPN才同步完成的)撕攒,可以先往后繼續(xù)看文章

第六步:在清單文件中添加網(wǎng)絡(luò)請求權(quán)限,必須添加的

官方原話Next, make sure you have the Internet permission in your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
以及調(diào)試需要用到的權(quán)限

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

第七步:在清單文件中注冊DevSettingsActivity,此步驟可以省略,功能就是重載JavaScript

如果您需要訪問DevSettingsActivity添加到您的AndroidManifest.xml:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
這只在開發(fā)服務(wù)器重新加載JavaScript時(shí)才真正用于開發(fā)模式陡鹃,因此烘浦,如果需要,可以在發(fā)布版本中將其剝離萍鲸。

第八步:新建一個(gè) ReactNativeActivity 闷叉,并在清單文件中設(shè)置成啟動(dòng)頁面,用來展示 React Native 的頁面:

public class ReactNativeActivity extends ReactActivity {

    @Override
    protected String getMainComponentName() {
        return "RNHelloWorld";
    }
}

看過上一篇的人脊阴,再回頭看看上一篇握侧,應(yīng)該覺得很吃驚,原來可以這么簡潔嘿期,而且成功的避開了RN版本不同可能找不到.setJSMainModuleName("index.android")這個(gè)方法的坑品擎。
接下來(這個(gè)步驟是可以跳過的),我們需要將一些活動(dòng)生命周期回調(diào)傳遞給ReactInstanceManager:

 @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();
        }
    }

注意:如果你直接copy官網(wǎng)中代碼的話备徐,是會出錯(cuò)的萄传,因?yàn)镽eactNative版本更新了,方法名字更改和安卓更加同步了

也是可跳過的)我們還需要將按鈕事件傳遞給React Native:

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

作用:這允許JavaScript控制用戶按下硬件后退按鈕時(shí)發(fā)生的情況(例如蜜猾,實(shí)現(xiàn)導(dǎo)航)秀菱。當(dāng)JavaScript不處理背按時(shí),您的invokeDefaultOnBackPressed方法將被調(diào)用瓣铣。默認(rèn)情況下答朋,這只是完成你的Activity。

最后(這個(gè)步驟也是可以跳過的)棠笑,我們需要連接開發(fā)菜單梦碗。默認(rèn)情況下,這是通過(憤怒)激發(fā)設(shè)備來激活的蓖救,但這在模擬器中并不是很有用洪规。所以我們在按下硬件菜單按鈕時(shí)顯示它(Ctrl + M如果您使用的是Android Studio模擬器,請使用它):

 @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
            mReactInstanceManager.showDevOptionsDialog();
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }

第九步(此步驟可以跳過):配置權(quán)限以便開發(fā)中的紅屏錯(cuò)誤能正確顯示

如果您的應(yīng)用定位到Android API level 23或更高版本循捺,請確保您已overlay為開發(fā)版本啟用權(quán)限斩例。你可以檢查它Settings.canDrawOverlays(this);。這在開發(fā)版本中是必需的从橘,因?yàn)楸仨氃谒衅渌翱谥巷@示原始開發(fā)錯(cuò)誤念赶。由于在API級別23中引入了新的權(quán)限系統(tǒng),用戶需要批準(zhǔn)它恰力。這可以通過將以下代碼添加到onCreate()方法中的Activity文件中來實(shí)現(xiàn)叉谜。OVERLAY_PERMISSION_REQ_CODE是將負(fù)責(zé)將結(jié)果傳遞回活動(dòng)的類的字段。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (!Settings.canDrawOverlays(this)) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                   Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
    }
}

最后踩萎,onActivityResult()必須重寫該方法(如下面的代碼所示)以處理一致UX的權(quán)限Accepted或Denied停局。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                // SYSTEM_ALERT_WINDOW permission not granted...
            }
        }
    }
}

最后在明確下index.android.js和mReactRootView.startReactApplication(mReactInstanceManager, "HelloRN", null)和package.json及項(xiàng)目名字,到底那幾個(gè)保持一致(我也是集成了5次以上,總結(jié)出來的董栽,如果有不對請留言指出)

必須一樣的:工程名字(RNHelloWorld)和AppRegistry.registerComponent('RNHelloWorld', () => HelloWorldApp);以及protected String getMainComponentName()返回的名字三者必須一樣码倦。
當(dāng)你出現(xiàn)以下錯(cuò)誤,基本就是這個(gè)原因了

image.png

運(yùn)行應(yīng)用

  • 首先運(yùn)行服務(wù)
    在項(xiàng)目的根文件夾下锭碳,命令行運(yùn)行如下命令袁稽,啟動(dòng)測試服務(wù)器(可以直接在Androidstudio的Termin中輸入,但是注意當(dāng)前所在位置)工禾。
npm start
或者:
react-native start
  • 接下來像開發(fā)安卓項(xiàng)目一樣直接運(yùn)行項(xiàng)目

效果(這里使用的上一篇的效果圖和真實(shí)的只是title不一樣)

效圖

有了上一篇的經(jīng)驗(yàn)运提,這次我一次就完成了將RN嵌入原生項(xiàng)目,真順暢

如果報(bào)錯(cuò)
image.png

或是


image.png
解決:在app的build.gradle 中添加
|
|
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }```

參考鏈接:

其實(shí)我已經(jīng)在坑了爬了三天了闻葵,看了幾十篇博客,以及一些問題解決的網(wǎng)頁癣丧,下面就指出我覺得最有用的槽畔,和影響最深刻的
官方文檔嵌入到現(xiàn)有原生應(yīng)用
Android項(xiàng)目中集成React Native
React Native 學(xué)習(xí)筆記十二(嵌入原生應(yīng)用 甚是坑啊)

印象最深刻就是:現(xiàn)有Android項(xiàng)目引入ReactNative--九步大法,因?yàn)槭区櫻蟠笊裢扑]的所以也是我首選看的資料胁编,我還結(jié)合了官網(wǎng)資料一起看厢钧,沒想到就入坑了,作者文章的工程目錄結(jié)構(gòu)和我一樣嬉橙,但是在在填寫本地倉庫的路徑卻和官網(wǎng)一樣(猜想:如果作者的項(xiàng)目能運(yùn)行早直,再看看作者的目錄圖片應(yīng)該是蘋果,我用的Windows市框,可能系統(tǒng)不一樣所以路徑可能存在一點(diǎn)差異)

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

這也就是我入坑的第一步了霞扬,原因我在文章第五步已經(jīng)說明,以至于"一入坑難起來啊"枫振,當(dāng)然說這個(gè)不是為了針對作者喻圃,只是給更多的人提個(gè)醒,以免再次入坑

喜歡請點(diǎn)贊粪滤,或是關(guān)注斧拍,后續(xù)將完善發(fā)布更多的文章,你的鼓勵(lì)就是我的動(dòng)力(程序員最大的動(dòng)力莫過于同行的鼓勵(lì))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杖小,一起剝皮案震驚了整個(gè)濱河市肆汹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌予权,老刑警劉巖昂勉,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伟件,居然都是意外死亡硼啤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谴返,“玉大人煞肾,你說我怎么就攤上這事∩じぃ” “怎么了籍救?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渠抹。 經(jīng)常有香客問我蝙昙,道長,這世上最難降的妖魔是什么梧却? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任奇颠,我火速辦了婚禮,結(jié)果婚禮上放航,老公的妹妹穿的比我還像新娘烈拒。我一直安慰自己,他們只是感情好广鳍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布荆几。 她就那樣靜靜地躺著,像睡著了一般赊时。 火紅的嫁衣襯著肌膚如雪吨铸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天祖秒,我揣著相機(jī)與錄音诞吱,去河邊找鬼。 笑死狈涮,一個(gè)胖子當(dāng)著我的面吹牛狐胎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播歌馍,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼握巢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了松却?” 一聲冷哼從身側(cè)響起暴浦,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晓锻,沒想到半個(gè)月后歌焦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砚哆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年独撇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纷铣,死狀恐怖卵史,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搜立,我是刑警寧澤以躯,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站啄踊,受9級特大地震影響忧设,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颠通,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一址晕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顿锰,春花似錦斩箫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狐血。三九已至淀歇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匈织,已是汗流浹背浪默。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缀匕,地道東北人纳决。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像乡小,于是被迫代替她去往敵國和親阔加。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容