在使用 ReactNative 開發(fā)過程中氏淑,由于開發(fā)中用到的語(yǔ)言是 JS,而如果需要實(shí)現(xiàn)百度定位或者微博分享等第三方 SDK 時(shí),往往會(huì)先去找有沒有支持 React Native 的三方庫(kù)翠拣。
盡管大部分常用功能已經(jīng)被民間藝人或官方團(tuán)隊(duì)實(shí)現(xiàn)按摘,但是一旦遇到未被 RN 開發(fā)的就只能擼起袖子自己干了朗徊。ReactNative 官方文檔也介紹了 Native Modules(下稱‘原生模塊’)的使用方法,它能用于訪問原生平臺(tái)的 API娜庇。
本文主要提供 Android 平臺(tái)的原生模塊打包教程拇泛。
原生模塊的使用方法:
以官網(wǎng)文檔列舉的 Toast 模塊使用方法為例滨巴,其主要步驟為:
第一步:
使用 Android Studio 打開 RN 項(xiàng)目的?android?文件,新建?Android Library?命名為 react-native-toast
圖1 新建Android Library
第二步:
在 react-native-toast 的build.gradlew?中添加RN依賴
dependencies {
....
compile
"com.facebook.react:react-native:+"?????? ? //here
}
在 app 的?build.gradlew?中引入這個(gè)庫(kù)
dependencies {
....
compile project(
':react-native-toast')//here
}
第三步:
前面的環(huán)境都配置好后就開始新建2個(gè) java 文件:
繼承 ReactContextBaseJavaModule 的 java 類Module.java?
和注冊(cè)模塊用的Package.java俺叭。
具體代碼在官網(wǎng)有詳細(xì)提供恭取,本文不重點(diǎn)闡述
思考:
如果按照 RN 文檔方法,在項(xiàng)目的 android 根文件夾下添加原生模塊熄守,會(huì)出現(xiàn)兩個(gè)問題:一是蜈垮,如果要實(shí)現(xiàn)的原生模塊多了,Android Library 也會(huì)遞增裕照,目錄容易混亂難以管理攒发;二是,這樣的原生模塊不容易復(fù)用晋南,其它項(xiàng)目沒法直接使用這個(gè)原生模塊惠猿。
通行的做法是,將實(shí)現(xiàn)后原生模塊打包好负间,然后存放在項(xiàng)目的 node_modules 的文件內(nèi)偶妖,供 APP 調(diào)用。
本文重點(diǎn):
本文將以百度定位的 Android SDK 為例政溃,介紹如何將其打包為一個(gè)名為 “react-native-baidu-location” 的原生模塊庫(kù)(library)趾访,供 RN APP 調(diào)用。
這個(gè)例子相比一般的原生模塊開發(fā)(RN文檔示例)會(huì)多一項(xiàng)工作董虱,即引入 SDK扼鞋,流程大致如下:
·創(chuàng)建一個(gè) RN 項(xiàng)目 Demo,用于調(diào)試愤诱。
·初始化 react-native-baidu-location 包云头。
·根據(jù)官網(wǎng)文檔對(duì) Android 平臺(tái)配置、引入 SDK淫半、寫代碼溃槐。
?初始化原生模塊庫(kù)
先創(chuàng)建一個(gè) RN 項(xiàng)目 Demo
安裝?react-native-create-library(類似的工具還有react-native-create-bridge)
?npm install -g ?react-native-create-library
在 node_modules 文件夾下創(chuàng)建你的三方庫(kù)
?react-native-create-library ?react-native-baidu-location
之后進(jìn)行本文之前的第三步,第一步和第二步已經(jīng)幫我們實(shí)現(xiàn)撮慨,只需要根據(jù)自己需求修改構(gòu)建工具的版本 ?.grandle?和?buildToolsVersion竿痰。
打包 Android 部分(重難點(diǎn))
因?yàn)橐园俣榷ㄎ粸槔嘀啵孕枰暾?qǐng)為百度開發(fā)者砌溺,下載基礎(chǔ)定位 SDK,具體步驟請(qǐng)使用 baidu变隔,本文不必闡述规伐,主要使用下載后解壓包內(nèi)叫?libs?的文件夾。
使用 Android Studio 打開 react-native-baidu-location 內(nèi)的 android 文件和 RN 項(xiàng)目Demo 下的 android 文件匣缘,因?yàn)檫@里是 android 打包教程猖闪,所以其他平臺(tái)教程請(qǐng)期待下篇《React-Native 如何自己擼第三方庫(kù)之 ios 篇》
?1.React-native-baidu-location - android
將?libs?文件復(fù)制到 android 文件下
?build.gradle?加入如下代碼
android ?{
???? ....
?? sourceSets {
??????? main {
??????????? jniLibs.srcDirs = ['libs']
??????? }
??? }
}
2.Demo - android
根據(jù)百度文檔鲜棠,配置相關(guān)服務(wù),ak 秘鑰和權(quán)限
AndroidManifest.xml?加入如下代碼
??????????? ?android:name="com.baidu.location.f"
??????????? android:enabled="true"
??????????? ?android:process=":remote">
??????????? ?android:name="com.baidu.lbsapi.API_KEY"
??????????? ?android:value="GN1lCG*************4I&&s" />
添加權(quán)限
```
```
3.?編寫 Native 模塊
和前文的第三步一樣使用固定寫法:
1.?????建一個(gè)中間訪問對(duì)象,
2.?????建一個(gè) ReactPackage 對(duì)象.
3.? ? ?將 ReactPackage 對(duì)象加載到 MainApplication 中.
LocationActivity
package ?com.location;
import ?android.util.Log;
import ?com.baidu.location.BDLocation;
import ?com.baidu.location.BDLocationListener;
import ?com.baidu.location.LocationClient;
import ?com.baidu.location.LocationClientOption;
import ?com.baidu.location.Poi;
import ?com.facebook.react.bridge.Callback;
import ?com.facebook.react.bridge.ReactApplicationContext;
import ?com.facebook.react.bridge.ReactContextBaseJavaModule;
import ?com.facebook.react.bridge.ReactMethod;
import ?java.util.List;
/**
?* Created by luokun on 2018/1/31.
?*/
public ?class LocationActivity extends ReactContextBaseJavaModule {
??? public LocationClient mLocationClient = ?null;
??? private Callback locationCallback;
??? public ?LocationActivity(ReactApplicationContext reactContext) {
??????? super(reactContext);
??? }
??? @ReactMethod
??? public void startLocation( Callback ?locationCallback) {
??????? this.locationCallback = ?locationCallback;
??????? mLocationClient = new ?LocationClient(getReactApplicationContext());???? //聲明LocationClient類
??????? ?mLocationClient.registerLocationListener(myListener);??? //注冊(cè)監(jiān)聽函數(shù)
??????? LocationClientOption option = new ?LocationClientOption();
??????? option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy
??????? );//可選培慌,默認(rèn)高精度豁陆,設(shè)置定位模式,高精度吵护,低功耗盒音,僅設(shè)備
??????? ?option.setCoorType("bd09ll");//可選,默認(rèn)gcj02馅而,設(shè)置返回的定位結(jié)果坐標(biāo)系
??????? int span = 0;
??????? option.setScanSpan(span);//可選祥诽,默認(rèn)0,即僅定位一次瓮恭,設(shè)置發(fā)起定位請(qǐng)求的間隔需要大于等于1000ms才是有效的
??????? option.setIsNeedAddress(true);//可選雄坪,設(shè)置是否需要地址信息,默認(rèn)不需要
??????? option.setOpenGps(true);//可選屯蹦,默認(rèn)false,設(shè)置是否使用gps
??????? option.setLocationNotify(true);//可選维哈,默認(rèn)false,設(shè)置是否當(dāng)gps有效時(shí)按照1S1次頻率輸出GPS結(jié)果
??????? ?option.setIsNeedLocationDescribe(true);//可選颇玷,默認(rèn)false笨农,設(shè)置是否需要位置語(yǔ)義化結(jié)果,可以在BDLocation.getLocationDescribe里得到帖渠,結(jié)果類似于“在北京天安門附近”
??????? ?option.setIsNeedLocationPoiList(true);//可選谒亦,默認(rèn)false,設(shè)置是否需要POI結(jié)果空郊,可以在BDLocation.getPoiList里得到
??????? option.setIgnoreKillProcess(false);//可選份招,默認(rèn)true,定位SDK內(nèi)部是一個(gè)SERVICE狞甚,并放到了獨(dú)立進(jìn)程锁摔,設(shè)置是否在stop的時(shí)候殺死這個(gè)進(jìn)程,默認(rèn)不殺死
??????? ?option.SetIgnoreCacheException(false);//可選哼审,默認(rèn)false谐腰,設(shè)置是否收集CRASH信息,默認(rèn)收集
??????? option.setEnableSimulateGps(false);//可選涩盾,默認(rèn)false十气,設(shè)置是否需要過濾gps仿真結(jié)果,默認(rèn)需要
??????? mLocationClient.setLocOption(option);
??????? mLocationClient.start();
??????? ?Log.e("tag","ok");
??? }
??? /**
???? * 定位回掉
???? */
??? public BDLocationListener myListener = ?new BDLocationListener() {
??????? @Override
??????? public void onReceiveLocation(final ?BDLocation bdLocation) {
??? ????????Log.e("TGA", "回掉+1");
??????????? //Receive Location
??????????? final StringBuffer sb = new ?StringBuffer(256);
??????????? sb.append("time : ");
??????????? sb.append(bdLocation.getTime());
??????????? sb.append("\nerror code : ?");
??????????? sb.append(bdLocation.getLocType());
??????????? sb.append("\nlatitude : ?");
??????????? ?sb.append(bdLocation.getLatitude());
??????????? sb.append("\nlontitude : ?");
??????????? ?sb.append(bdLocation.getLongitude());
??????????? sb.append("\nradius : ?");
???? ???????sb.append(bdLocation.getRadius());
??????????? if (bdLocation.getLocType() == ?BDLocation.TypeGpsLocation) {// GPS定位結(jié)果
??????????????? sb.append("\nspeed : ?");
??????????????? ?sb.append(bdLocation.getSpeed());// 單位:公里每小時(shí)
??????????????? sb.append("\nsatellite : ?");
??????????????? ?sb.append(bdLocation.getSatelliteNumber());
??????????????? sb.append("\nheight : ?");
??????????????? ?sb.append(bdLocation.getAltitude());// 單位:米
??????????????? sb.append("\ndirection : ?");
??????????????? ?sb.append(bdLocation.getDirection());// 單位度
??????????????? sb.append("\naddr : ?");
??????????????? ?sb.append(bdLocation.getAddrStr());
??????????????? sb.append("\ndescribe : ?");
??????????????? sb.append("gps定位成功");
??????????? } else if ?(bdLocation.getLocType() == BDLocation.TypeNetWorkLocation) {// 網(wǎng)絡(luò)定位結(jié)果
??????????????? sb.append("\naddr : ?");
??????????????? ?sb.append(bdLocation.getAddrStr());
??????????????? //運(yùn)營(yíng)商信息
??????????????? ?sb.append("\noperationers : ");
??????????????? sb.append(bdLocation.getOperators());
??????????????? sb.append("\ndescribe : ?");
??????????????? sb.append("網(wǎng)絡(luò)定位成功");
??????????? } else if ?(bdLocation.getLocType() == BDLocation.TypeOffLineLocation) {// 離線定位結(jié)果
??????????????? sb.append("\ndescribe : ?");
??? ????????????sb.append("離線定位成功春霍,離線定位結(jié)果也是有效的");
??????????? } else if ?(bdLocation.getLocType() == BDLocation.TypeServerError) {
??????????????? sb.append("\ndescribe : ?");
??????????????? sb.append("服務(wù)端網(wǎng)絡(luò)定位失敗砸西,可以反饋IMEI號(hào)和大體定位時(shí)間到loc-bugs@baidu.com,會(huì)有人追查原因");
?? ?????????} else if (bdLocation.getLocType() ?== BDLocation.TypeNetWorkException) {
??????????????? sb.append("\ndescribe : ?");
??????????????? sb.append("網(wǎng)絡(luò)不同導(dǎo)致定位失敗,請(qǐng)檢查網(wǎng)絡(luò)是否通暢");
??????????? } else if ?(bdLocation.getLocType() == BDLocation.TypeCriteriaException) {
??????????????? sb.append("\ndescribe : ?");
??????????????? sb.append("無法獲取有效定位依據(jù)導(dǎo)致定位失敗芹枷,一般是由于手機(jī)的原因衅疙,處于飛行模式下一般會(huì)造成這種結(jié)果,可以試著重啟手機(jī)");
??????????? }
??????????? ?sb.append("\nlocationdescribe : ");
??????????? ?sb.append(bdLocation.getLocationDescribe());// 位置語(yǔ)義化信息
??????????? List list = ?bdLocation.getPoiList();// POI數(shù)據(jù)
??????????? if (list != null) {
??????????????? sb.append("\npoilist ?size = : ");
??????????????? sb.append(list.size());
???? ???????????for (Poi p : list) {
??????????????????? sb.append("\npoi= : ?");
??????????????????? sb.append(p.getId() + ?" " + p.getName() + " " + p.getRank());
??????????????? }
??????????? }
??????????? ?locationCallback.invoke(sb.toString());
??????? }
??? };
??? @Override
??? public String getName() {
??????? return "Location";
??? }
}
LocationPackage
package ?com.location;
import ?com.facebook.react.ReactPackage;
import ?com.facebook.react.bridge.JavaScriptModule;
import ?com.facebook.react.bridge.NativeModule;
import ?com.facebook.react.bridge.ReactApplicationContext;
import ?com.facebook.react.uimanager.ViewManager;
import ?java.util.ArrayList;
import ?java.util.Collections;
import ?java.util.List;
/**
?* Created by luokun on 2018/1/31.
?*/
public ?class LocationPackage implements ReactPackage {
??? @Override
??? public List ?createViewManagers(ReactApplicationContext reactContext) {
??????? return Collections.emptyList();
??? }
??? @Override
??? public List ?createNativeModules(
??????????? ReactApplicationContext ?reactContext) {
??????? List modules = ?new ArrayList<>();
??????? modules.add(new ?LocationActivity(reactContext));??? //
??????? return modules;
??? }
}
Index.js文件
'use ?strict';
import ?{ NativeModules } from 'react-native';
export ?default NativeModules.Location;
恭喜完成鸳慈!
至于怎么使用饱溢,最好寫一個(gè) README.md,要‘裝逼’咱們就來全套走芋。寫個(gè)使用文檔理朋,讓我們搬運(yùn)工們用得順手。(笑笑就好:))
使用方法:
自動(dòng) link
React-native-baidu-location ?link
或者手動(dòng) link
/android/settings.gradle
include ?':react-native-baidu-location'
project(':react-native-baidu-location').projectDir ?= new File(rootProject.projectDir, ?'../node_modules/react-native-baidu-ocr/android')
/android/app/build.gradle
dependencies ?{
?? ...
??? compile ?project(':react-native-baidu-ocr'') // 加入
?? ...
}
js 使用方法
Import ?Location from ‘react-native-baidu-location’
...
...
?componentDidMount() {
??????? ?Location.startLocation((location)=> {
??????????? console.log(location)???????
});
??? }
當(dāng)你看到這里的時(shí)候并且自己照著寫了一遍绿聘,那么恭喜你成功開發(fā)出第三方 rn 庫(kù)了嗽上,甚至可以上傳到 npm 上開源。
上傳成功后熄攘,其它項(xiàng)目就可以通過 npminstall 來使用這個(gè)庫(kù)兽愤。
總結(jié):
要打包 React Native 的原生模塊,你最好有以下知識(shí)儲(chǔ)備:
有 RN 開發(fā)經(jīng)驗(yàn)挪圾。如 RN 文檔所說浅萧,原生模塊是該框架的高級(jí)特性,當(dāng)然是有一定的經(jīng)驗(yàn)更易理解哲思。
了解 Java 和 Objective-C洼畅, 至少能看懂這兩種代碼。和官網(wǎng)教程對(duì)比上述代碼雖然多但是很多都是固定寫法棚赔。
基本實(shí)現(xiàn)原理是通過回調(diào)使 JavaScript 能夠訪問到 java 返回值帝簇。
更多特性敬請(qǐng)期待。
-END-?