reactnative 橋接原生文件配置之獲取設(shè)備號組件

本文原創(chuàng)首發(fā)于公眾號:ReactNative開發(fā)圈友雳,轉(zhuǎn)載需注明出處稿湿。(有一些功能不一定能用调限,反正我用時undefined)

這次介紹的獲取移動設(shè)備信息的組件名叫:react-native-device-info窍仰,兼容IOS和安卓雙平臺,可以獲取設(shè)備ID干旧、設(shè)備品牌流礁、設(shè)備型號涕俗、IP以及APP版本號等信息。是一個應(yīng)用很廣泛的基礎(chǔ)組件崇棠。

安裝依賴

npm install --save react-native-device-info

注:如果React Naitve的版本大于0.47咽袜,那么需要使用>=0.11版本的react-native-device-info組件

自動連接原生項(xiàng)目

react-native link react-native-device-info

示例

參考官方文檔:https://github.com/rebeccahughes/react-native-device-info#getdeviceid
有一個方法比較特殊就是isPinOrFingerprintSet方法,需要使用回調(diào)調(diào)用枕稀。代碼如下:

import DeviceInfo from 'react-native-device-info';

DeviceInfo.isPinOrFingerprintSet()(isPinOrFingerprintSet => {
  if (!isPinOrFingerprintSet) {
    ...
  }
}

直接集成有些方法會返回undefined

為了解決上述功能不行询刹,那么怎么辦呢?

很簡單架設(shè)RN與原生的橋架來解決萎坷,以獲取設(shè)備信息為例

react-native的文檔的原生模塊中可以看到清晰的代碼 傳送門

iOS橋接文件:

在ios文件夾中凹联,添加一個nativeBridge文件夾(為了整理好文件,無實(shí)際作用)哆档,在該文件夾下添加橋接文件RNDeviceBridgeManager的.h和.m文件(這個文件名隨便起蔽挠,最好符合命名規(guī)范),前期工作就準(zhǔn)備完畢了瓜浸,現(xiàn)在開始文件配置澳淑,如下:

RNDeviceBridgeManager.h

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h> // 不能去掉,否則會報(bào)莫名錯誤

@interface RNDeviceBridgeManager : NSObject <RCTBridgeModule>

@end

RNDeviceBridgeManager.m

#import "RNDeviceBridgeManager.h"
#import "sys/utsname.h"
#import <CoreTelephony/CTCarrier.h> // 獲取運(yùn)營商信息
#import <CoreTelephony/CTTelephonyNetworkInfo.h>

@implementation RNDeviceBridgeManager

RCT_EXPORT_MODULE(AppDeviceInfo)
// 解決警告 - Module RNDeviceBridgeManager requires main queue setup since it overrides `constantsToExport` but doesn't implement `requiresMainQueueSetup`.
- (NSDictionary *)constantsToExport{
  NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
  NSString *appName = [info objectForKey:@"CFBundleDisplayName"];
  NSString *appVersion = [info objectForKey:@"CFBundleShortVersionString"];
  CGRect rect = [[UIScreen mainScreen] bounds];
  CGSize size = rect.size;
  CGFloat width = size.width;
  CGFloat height = size.height;
  NSArray *screenSize =@[@(width), @(height)];
  CGFloat scale_screen = [UIScreen mainScreen].scale;
  NSArray *screenScale = @[@(width*scale_screen), @(height*scale_screen)];
  CTTelephonyNetworkInfo *info_tel = [[CTTelephonyNetworkInfo alloc] init];
  CTCarrier *carrier = info_tel.subscriberCellularProvider;
  NSDictionary *deviceInfo = @{
                               @"sysVersion": [[UIDevice currentDevice] systemVersion], // 手機(jī)系統(tǒng)版本
                               @"deviceId": [[[UIDevice currentDevice] identifierForVendor] UUIDString], // 設(shè)備唯一標(biāo)識符
                               @"platformType": [[UIDevice currentDevice] systemName], // 設(shè)備名稱
                               @"phoneName": [[UIDevice currentDevice] name], // 手機(jī)別名: 用戶定義的名稱
                               @"phoneType": [self deviceVersion], // 手機(jī)型號
                               @"localPhoneModel": [[UIDevice currentDevice] localizedModel], // 地方型號  (國際化區(qū)域名稱)
                               @"size_screen": screenSize, // 物理尺寸
                               @"scale_screen": screenScale, // 分辨率
                               @"carrierName": carrier != nil ? carrier.carrierName : nil, // 運(yùn)營商 -- 模擬器無運(yùn)營商要特別處理插佛,不然會閃退杠巡,nil時返回值里不包含本條信息
                               @"appVersion": appVersion, // 當(dāng)前應(yīng)用軟件版本  比如:1.0.1
                               @"appBuild": [info objectForKey:@"CFBundleVersion"], // 當(dāng)前應(yīng)用版本Build值   int類型
                               @"appName": appName, // app名稱
                               };
  return deviceInfo;
}

- (NSString *)deviceVersion{
  // 需要#import "sys/utsname.h"
  struct utsname systemInfo;
  uname(&systemInfo);
  NSString * deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
  //iPhone
  if ([deviceString isEqualToString:@"iPhone3,1"])    return @"iPhone 4";
  if ([deviceString isEqualToString:@"iPhone3,2"])    return @"iPhone 4";
  if ([deviceString isEqualToString:@"iPhone3,3"])    return @"iPhone 4";
  if ([deviceString isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
  if ([deviceString isEqualToString:@"iPhone5,1"])    return @"iPhone 5";
  if ([deviceString isEqualToString:@"iPhone5,2"])    return @"iPhone 5 (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPhone5,3"])    return @"iPhone 5c (GSM)";
  if ([deviceString isEqualToString:@"iPhone5,4"])    return @"iPhone 5c (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPhone6,1"])    return @"iPhone 5s (GSM)";
  if ([deviceString isEqualToString:@"iPhone6,2"])    return @"iPhone 5s (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPhone7,1"])    return @"iPhone 6 Plus";
  if ([deviceString isEqualToString:@"iPhone7,2"])    return @"iPhone 6";
  if ([deviceString isEqualToString:@"iPhone8,1"])    return @"iPhone 6s";
  if ([deviceString isEqualToString:@"iPhone8,2"])    return @"iPhone 6s Plus";
  if ([deviceString isEqualToString:@"iPhone8,4"])    return @"iPhone SE";
  // 日行兩款手機(jī)型號均為日本獨(dú)占,可能使用索尼FeliCa支付方案而不是蘋果支付
  if ([deviceString isEqualToString:@"iPhone9,1"])    return @"國行雇寇、日版氢拥、港行iPhone 7";
  if ([deviceString isEqualToString:@"iPhone9,2"])    return @"港行、國行iPhone 7 Plus";
  if ([deviceString isEqualToString:@"iPhone9,3"])    return @"美版锨侯、臺版iPhone 7";
  if ([deviceString isEqualToString:@"iPhone9,4"])    return @"美版嫩海、臺版iPhone 7 Plus";
  if ([deviceString isEqualToString:@"iPhone10,1"])   return @"iPhone_8";
  if ([deviceString isEqualToString:@"iPhone10,4"])   return @"iPhone_8";
  if ([deviceString isEqualToString:@"iPhone10,2"])   return @"iPhone_8_Plus";
  if ([deviceString isEqualToString:@"iPhone10,5"])   return @"iPhone_8_Plus";
  if ([deviceString isEqualToString:@"iPhone10,3"])   return @"iPhone_X";
  if ([deviceString isEqualToString:@"iPhone10,6"])   return @"iPhone_X";
  if ([deviceString isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
  if ([deviceString isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
  if ([deviceString isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
  if ([deviceString isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
  if ([deviceString isEqualToString:@"iPod5,1"])      return @"iPod Touch (5 Gen)";
  if ([deviceString isEqualToString:@"iPad1,1"])      return @"iPad";
  if ([deviceString isEqualToString:@"iPad1,2"])      return @"iPad 3G";
  if ([deviceString isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
  if ([deviceString isEqualToString:@"iPad2,2"])      return @"iPad 2";
  if ([deviceString isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
  if ([deviceString isEqualToString:@"iPad2,4"])      return @"iPad 2";
  if ([deviceString isEqualToString:@"iPad2,5"])      return @"iPad Mini (WiFi)";
  if ([deviceString isEqualToString:@"iPad2,6"])      return @"iPad Mini";
  if ([deviceString isEqualToString:@"iPad2,7"])      return @"iPad Mini (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPad3,1"])      return @"iPad 3 (WiFi)";
  if ([deviceString isEqualToString:@"iPad3,2"])      return @"iPad 3 (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPad3,3"])      return @"iPad 3";
  if ([deviceString isEqualToString:@"iPad3,4"])      return @"iPad 4 (WiFi)";
  if ([deviceString isEqualToString:@"iPad3,5"])      return @"iPad 4";
  if ([deviceString isEqualToString:@"iPad3,6"])      return @"iPad 4 (GSM+CDMA)";
  if ([deviceString isEqualToString:@"iPad4,1"])      return @"iPad Air (WiFi)";
  if ([deviceString isEqualToString:@"iPad4,2"])      return @"iPad Air (Cellular)";
  if ([deviceString isEqualToString:@"iPad4,4"])      return @"iPad Mini 2 (WiFi)";
  if ([deviceString isEqualToString:@"iPad4,5"])      return @"iPad Mini 2 (Cellular)";
  if ([deviceString isEqualToString:@"iPad4,6"])      return @"iPad Mini 2";
  if ([deviceString isEqualToString:@"iPad4,7"])      return @"iPad Mini 3";
  if ([deviceString isEqualToString:@"iPad4,8"])      return @"iPad Mini 3";
  if ([deviceString isEqualToString:@"iPad4,9"])      return @"iPad Mini 3";
  if ([deviceString isEqualToString:@"iPad5,1"])      return @"iPad Mini 4 (WiFi)";
  if ([deviceString isEqualToString:@"iPad5,2"])      return @"iPad Mini 4 (LTE)";
  if ([deviceString isEqualToString:@"iPad5,3"])      return @"iPad Air 2";
  if ([deviceString isEqualToString:@"iPad5,4"])      return @"iPad Air 2";
  if ([deviceString isEqualToString:@"iPad6,3"])      return @"iPad Pro 9.7";
  if ([deviceString isEqualToString:@"iPad6,4"])      return @"iPad Pro 9.7";
  if ([deviceString isEqualToString:@"iPad6,7"])      return @"iPad Pro 12.9";
  if ([deviceString isEqualToString:@"iPad6,8"])      return @"iPad Pro 12.9";
  
  if ([deviceString isEqualToString:@"AppleTV2,1"])      return @"Apple TV 2";
  if ([deviceString isEqualToString:@"AppleTV3,1"])      return @"Apple TV 3";
  if ([deviceString isEqualToString:@"AppleTV3,2"])      return @"Apple TV 3";
  if ([deviceString isEqualToString:@"AppleTV5,3"])      return @"Apple TV 4";
  
  if ([deviceString isEqualToString:@"i386"])         return @"Simulator";
  if ([deviceString isEqualToString:@"x86_64"])       return @"Simulator";
  
  return deviceString;
}
@end

文件配置說明:

.h文件中#import <React/RCTBridgeModule.h>配置橋接文件必須導(dǎo)入這個RN橋接模塊依賴,并遵循“RCTBridgeModule”協(xié)議囚痴;在.m文件中實(shí)現(xiàn)“RCTBridgeModule”協(xié)議叁怪。
以示例中導(dǎo)出設(shè)備信息的方法為例,RCT_EXPORT_MODULE(AppDeviceInfo)為“RCTBridgeModule”協(xié)議提供方法深滚,即在RN中用AppDeviceInfo標(biāo)識導(dǎo)出方法奕谭;

為了實(shí)現(xiàn)RCTBridgeModule協(xié)議耳璧,你的類需要包含RCT_EXPORT_MODULE()宏。這個宏也可以添加一個參數(shù)用來指定在Javascript中訪問這個模塊的名字展箱。如果你不指定,默認(rèn)就會使用這個Objective-C類的名字蹬昌。其他宏的運(yùn)用本文就不做贅述混驰,要了解移步傳送門

RN中調(diào)用橋接文件模塊

import { NativeModules } from 'react-native'
/**
 * 獲取用戶設(shè)備碼
 */
export function fetchDeviceId() {
  const AppInfo = NativeModules.AppDeviceInfo
  console.log('橋接文件返回的值', AppInfo)
  return AppInfo.deviceId
}

以上iOS部分的橋接工作就算完成了,但是最新的react-native版本(0.56.0)皂贩,會報(bào)黃色Warning栖榨,強(qiáng)迫癥患者,解決辦法如下:

// 在程序入口(即路由配偶文件)
import {
  YellowBox,
} from 'react-native'
YellowBox.ignoreWarnings(['Module RNDeviceBridgeManager requires main queue setup since it overrides `constantsToExport` but doesn\'t implement `requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules on a background thread unless explicitly opted-out of.'])

注意:上述()中的即是黃色警告內(nèi)容了明刷,但是遇到有 ' 的情況就尷尬了婴栽,比如doesn't這樣會報(bào)錯,需要對 ' 進(jìn)行轉(zhuǎn)義辈末,在 ' 前加 \ 就好了愚争;

Android橋接文件:

本人對Android不太了解,所以不能提供同ios一樣詳細(xì)的解釋挤聘,步驟請照抄轰枝,如果你了解安卓特性可自由發(fā)揮;
在android文件夾下组去,路徑app/src/main/java/com/appname 文件夾下(appname為你的項(xiàng)目名)創(chuàng)建一個bridges文件夾鞍陨,在該文件夾下添加橋接文件RNDeviceBridgeManager.java,同時在app/src/main/java/com/appname 文件夾下創(chuàng)建 “注冊模塊”文件RNReactPackage.java,開始配置文件从隆,如下:

RNDeviceBridgeManager.java

// RNDeviceBridgeManager.java

package com.reactnative.bridges;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
// 導(dǎo)出方法用
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactMethod;

import java.util.Map;
import java.util.HashMap;

public class RNDeviceBridgeManager extends ReactContextBaseJavaModule {

  private static final String REACT_NAME = "AppDeviceInfo";
  // private static final String SYSTEM_VERSION = "sysVersion";
  private static final String DEVICE_ID = "deviceId";
  // private static final String PLATFORM_TYPE = "platformType";
  // private static final String PHONE_TYPE = "phoneType";
  // private static final String CARRIER_NAME = "carrierName";
  // private static final String PACKAGE_NAME = "packageName";
  // private static final String APP_VERSION = "appVersion";
  // private static final String APP_NAME = "appName";
  public RNDeviceBridgeManager(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  @Override
  public String getName() {
    return REACT_NAME;
  }

  @Override
  public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put(DEVICE_ID, "1234");
    return constants;
  }
}

RNReactPackage.java

// RNReactPackage.java

package com.reactnative;

import com.facebook.react.ReactPackage;
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;

public class RNReactPackage implements ReactPackage {

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Collections.emptyList();
  }

  @Override
  public List<NativeModule> createNativeModules(
                              ReactApplicationContext reactContext) {
    List<NativeModule> modules = new ArrayList<>();

    modules.add(new RNDeviceBridgeManager(reactContext));

    return modules;
  }

}

然后可以在RN項(xiàng)目文件中調(diào)用Android橋接文件里的東西诚撵,測試上述'AppDeviceInfo'信息是否有打印,如有打印則可根據(jù)具體業(yè)務(wù)將上述注釋掉的代碼補(bǔ)齊键闺,測試方式如下:

import {
  View,
  NativeModules,
} from 'react-native
class home extends React.Component {
  constructor(props) {
    super(props)
    this.state = {

    }
  }

  render() {
    console.log(NativeModules.AppDeviceInfo)
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'white' }}>
      </View>
    )
  }
}

module.exports = home

綜述寿烟,RN項(xiàng)目橋接調(diào)用iOS和Android原生方法的配置方法講述完畢,謝謝觀看艾杏;荊軻刺秦王韧衣!

另附:

獲取Android設(shè)備唯一標(biāo)識碼:http://www.reibang.com/p/2ceda3690a52
獲取系統(tǒng)版本:

//需導(dǎo)入系統(tǒng)架包 import android.os.Build;
constants.put(SYSTEM_VERSION, Build.VERSION.RELEASE);
// 下面是拼接信息(可以不這樣,看個人)
constants.put(SYSTEM_VERSION, Build.MODEL+" Android "+Build.VERSION.RELEASE+" "+Build.VERSION.SDK_INT);

獲取packageName包名:

// 需導(dǎo)入系統(tǒng)架包 import com.facebook.react.bridge.ReactApplicationContext;
constants.put(PACKAGE_NAME,getReactApplicationContext().getPackageName());

獲取app版本號:

// 需導(dǎo)入系統(tǒng)架包 import android.content.pm.PackageInfo;
// import android.content.pm.PackageManager;
  PackageInfo info = getPackageInfo();
  if(info != null){
    constants.put(APP_VERSION,info.versionName);
  }
  private PackageInfo getPackageInfo(){
    PackageManager manager = getReactApplicationContext().getPackageManager();
    PackageInfo info = null;
    try{
        info = manager.getPackageInfo(getReactApplicationContext().getPackageName(),0);
        return info;
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        return info;
    }
  }

手機(jī)型號:

constants.put(PHONE_TYPE,Build.MODEL);

平臺和應(yīng)用名稱自己寫固定的购桑;
運(yùn)營商信息畅铭,網(wǎng)上查找的資料全部不能用,不是缺少所需架包勃蜘,就是一些方法未定義硕噩,尚未找到方法,所以直接不設(shè)置了缭贡;(吐槽一下:抄襲都不驗(yàn)證的一大堆炉擅,百度上全是這種辉懒,還排名置頂,害人不淺谍失!)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眶俩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子快鱼,更是在濱河造成了極大的恐慌颠印,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抹竹,死亡現(xiàn)場離奇詭異线罕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窃判,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門钞楼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袄琳,你說我怎么就攤上這事询件。” “怎么了唆樊?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵雳殊,是天一觀的道長。 經(jīng)常有香客問我窗轩,道長夯秃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任痢艺,我火速辦了婚禮仓洼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堤舒。我一直安慰自己色建,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布舌缤。 她就那樣靜靜地躺著箕戳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪国撵。 梳的紋絲不亂的頭發(fā)上陵吸,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音介牙,去河邊找鬼壮虫。 笑死,一個胖子當(dāng)著我的面吹牛环础,可吹牛的內(nèi)容都是我干的囚似。 我是一名探鬼主播剩拢,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饶唤!你這毒婦竟也來了徐伐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤募狂,失蹤者是張志新(化名)和其女友劉穎呵晨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熬尺,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年谓罗,在試婚紗的時候發(fā)現(xiàn)自己被綠了粱哼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡檩咱,死狀恐怖揭措,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刻蚯,我是刑警寧澤绊含,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站炊汹,受9級特大地震影響躬充,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讨便,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一充甚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霸褒,春花似錦伴找、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至殊轴,卻和暖如春衰倦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旁理。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工耿币, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人韧拒。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓淹接,卻偏偏與公主長得像十性,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子塑悼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344