iOS--React Native 系統(tǒng)藍牙插件

一:介紹

React Native (簡稱RN)是Facebook于2015年4月開源的跨平臺移動應(yīng)用開發(fā)框架,是Facebook早先開源的JS框架 React 在原生移動應(yīng)用平臺的衍生產(chǎn)物,目前支持iOS和安卓兩大平臺。RN使用Javascript語言,類似于HTML的JSX,以及CSS來開發(fā)移動應(yīng)用,因此熟悉Web前端開發(fā)的技術(shù)人員只需很少的學習就可以進入移動應(yīng)用開發(fā)領(lǐng)域。

在React Native移動平臺項目開發(fā)中,除了React Native 提供的封裝好的部分插件和原聲組建外,在實際的項目中還需要使用到很多其他的插件,比如網(wǎng)絡(luò)請求、數(shù)據(jù)庫、相機、相冊、通訊錄、視頻播放器、瀏覽器、藍牙連接、圖片處理、消息推送、地圖、統(tǒng)計、埋點等等APP開發(fā)中需要用到的功能,都為IDE開發(fā)平臺提供封裝好的插件,以便項目開發(fā)使用。

另外,這些博文都是來源于我日常開發(fā)中的技術(shù)總結(jié),在時間允許的情況下,我會針對技術(shù)點分別分享iOS、Android兩個版本,如果有其他技術(shù)點需要,可在文章后留言,我會盡全力幫助大家。這篇文章重點介紹系統(tǒng)藍牙插件的開發(fā)與使用

二:實現(xiàn)思路分析

系統(tǒng)藍牙插件是通過調(diào)用系統(tǒng) CoreBluetooth 藍牙庫實現(xiàn)藍牙掃描、連接、發(fā)送數(shù)據(jù)等功能。并通過 BlueToothPlugin 類開放 BlueToothPlugin 接口提供給 H5頁面端調(diào)用。

具體的實現(xiàn)思路如下:

  1. 新建 BlueToothPlugin 類,實現(xiàn) RCTBridgeModule 協(xié)議

  2. 添加 RCT_EXPORT_MODULE() 宏

  3. 添加 React Native 跟控制器

  4. 聲明被 JavaScript 調(diào)用的藍牙初始化方法

  5. 聲明被 JavaScript 調(diào)用的發(fā)送藍牙數(shù)據(jù)方法

  6. 聲明被 JavaScript 調(diào)用的斷開藍牙連接方法

  7. 實現(xiàn)判斷藍牙狀態(tài)代理方法

  8. 實現(xiàn)藍牙外設(shè)發(fā)現(xiàn)代理方法

  9. 實現(xiàn)外設(shè)服務(wù)特征的代理方法

  10. 實現(xiàn)寫入藍牙數(shù)據(jù)后回調(diào)的代理方法

  11. Javascript調(diào)用瀏覽器方法

三:實現(xiàn)源碼分析

實現(xiàn)源碼分析是根據(jù)上面列出的具體實現(xiàn)思路來為大家解刨內(nèi)部的實現(xiàn)流程及核心代碼分析。

1. 新建 BlueToothPlugin 類,實現(xiàn) RCTBridgeModule 協(xié)議

新建繼承 NSObject 的 BlueToothPlugin 類,并實現(xiàn) RCTBridgeModule 協(xié)議

// BlueToothPlugin.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import "RCTEventEmitter.h"
#import <CoreBluetooth/CoreBluetooth.h>
@interface BlueToothPlugin : RCTEventEmitter<RCTBridgeModule,CBCentralManagerDelegate, CBPeripheralDelegate>
@end

2. 添加 RCT_EXPORT_MODULE() 宏

為了實現(xiàn) RCTBridgeModule 協(xié)議,BlueToothPlugin 的類需要包含RCT_EXPORT_MODULE() 宏。
并在這個宏里面添加一個參數(shù)“ BlueToothPlugin”用來指定在 JavaScript 中訪問這個模塊的名字。
如果你不指定,默認就會使用這個 Objective-C 類的名字。
如果類名以 RCT 開頭,則 JavaScript 端引入的模塊名會自動移除這個前綴。

// BlueToothPlugin.m
#import "BlueToothPlugin.h"
@implementation BlueToothPlugin
RCT_EXPORT_MODULE(BlueToothPlugin);
@end

3. 添加React Native跟控制器

如果不添加React Native跟控制器,view將不能正常顯示出來,實現(xiàn)方法如下:

// BlueToothPlugin.m
#import <React/RCTUtils.h>

引入<React/RCTUtils.h>之后,在視圖初始化或者顯示的時候,按照如下方法調(diào)用即可

UIViewController *vc = RCTPresentedViewController();

4. 聲明被 JavaScript 調(diào)用的藍牙初始化方法

藍牙初始化方法是對 CBCentralManager 的初始化以及代理調(diào)用線程設(shè)置,React Native需要明確的聲明要給 JavaScript 導(dǎo)出的方法,否則 React Native 不會導(dǎo)出任何方法。下面通過舉例來展示聲明的方法,通過RCT_EXPORT_METHOD()宏來實現(xiàn):

// ScanPlugin.m
#import "ScanPlugin.h"
#import <React/RCTUtils.h>
@implementation ScanPlugin
RCT_EXPORT_MODULE(ScanPlugin);

RCT_EXPORT_METHOD(initPeripheral:(NSDictionary *)arguments
                  withCompletionHandler:(RCTResponseSenderBlock)completion
                  failureHandler:(RCTResponseSenderBlock)failure)
{
    NSLog(@"調(diào)起藍牙初始化方法");
    self.cMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
@end

5. 聲明被 JavaScript 調(diào)用的發(fā)送藍牙數(shù)據(jù)方法

發(fā)送藍牙數(shù)據(jù)方法是在獲取外設(shè)并連接成功之后調(diào)用,需要獲取寫入特征 characteristic,需要發(fā)送的數(shù)據(jù),數(shù)據(jù)為 NSData 類型。

核心源碼如下:

RCT_EXPORT_METHOD(sendData:(NSDictionary *)arguments
                  withCompletionHandler:(RCTResponseSenderBlock)completion
                  failureHandler:(RCTResponseSenderBlock)failure)
{
      NSLog(@"調(diào)起藍牙發(fā)送數(shù)據(jù)方法");
      NSData *data = [self p_dataWithString:arguments[@"data"]];
    if (self.characteristic) {
        [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
    }
}

6. 聲明被 JavaScript 調(diào)用的斷開藍牙連接方法

當連接的設(shè)備藍牙連接成功后如果想主動斷開連接,需要調(diào)用 cancelPeripheralConnection 方法來實現(xiàn),傳參需要斷開設(shè)備的 peripheral 。
React Native需要明確的聲明要給 JavaScript 導(dǎo)出的方法,否則 React Native 不會導(dǎo)出任何方法。代碼如下:

RCT_EXPORT_METHOD(disconnectBlueTooth:(RCTResponseSenderBlock)completion
                  failureHandler:(RCTResponseSenderBlock)failure)
{
      NSLog(@"調(diào)起斷開藍牙連接方法");
      [self.cMgr cancelPeripheralConnection:self.peripheral];
}
7. 實現(xiàn)判斷藍牙狀態(tài)代理方法

藍牙狀態(tài)獲取需要通過實現(xiàn)代理,在 CBCentralManager 初始化時會觸發(fā)代理方法,并且只有獲取到藍牙的狀態(tài)才可以進行藍牙連接,否則提前連接無效。
源碼如下:

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    switch (central.state) {
        case CBManagerStateUnknown:{
            NSLog(@"未知狀態(tài)");
        }
            break;
        case CBManagerStateResetting:
        {
            NSLog(@"重置狀態(tài)");
        }
            break;
        case CBManagerStateUnsupported:
        {
            NSLog(@"不支持的狀態(tài)");
        }
            break;
        case CBManagerStateUnauthorized:
        {
            NSLog(@"未授權(quán)的狀態(tài)");
        }
            break;
        case CBManagerStatePoweredOff:
        {
            NSLog(@"關(guān)閉狀態(tài)");
        }
            break;
        case CBManagerStatePoweredOn:
        {
            NSLog(@"開啟狀態(tài)-可用狀態(tài)");
            [self.centralManager scanForPeripheralsWithServices:nil options:nil];
        }
            break;
        default:
            break;
    }
}
8. 實現(xiàn)藍牙外設(shè)發(fā)現(xiàn)代理方法

在發(fā)起藍牙掃面之后,如果掃面到設(shè)備會在 didDiscoverPeripheral 代理方法中回調(diào)相關(guān)設(shè)備數(shù)據(jù),其中包括,中心管理者 central、外設(shè) peripheral、設(shè)備自定義數(shù)據(jù) advertisementData、RSSI 信號強度。

核心源碼如下:

- (void)centralManager:(CBCentralManager *)central // 中心管理者
 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外設(shè)
     advertisementData:(NSDictionary *)advertisementData // 外設(shè)攜帶的數(shù)據(jù)
                  RSSI:(NSNumber *)RSSI // 外設(shè)發(fā)出的藍牙信號強度
{
}
  1. 實現(xiàn)外設(shè)服務(wù)特征的代理方法

實現(xiàn)外設(shè)服務(wù)特征,這個是比較重要的方法,你在這里可以通過事先知道UUID找到你需要的特征,訂閱特征,或者這里寫入數(shù)據(jù)給特征也可以。源碼如下:

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
        // 遍歷所有的特征
    for (CBCharacteristic *characteristic in service.characteristics)
    {
        NSLog(@"特征值:%@",characteristic.UUID.UUIDString);
         }
}
  1. 實現(xiàn)寫入藍牙數(shù)據(jù)后回調(diào)的代理方法

在寫入數(shù)據(jù)成功之后,會通過 didWriteValueForCharacteristic 方法回調(diào)告訴我們數(shù)據(jù)發(fā)送成功,可以在該方法中進行下一步操作。源碼如下:

- (void)peripheral:(CBPeripheral*)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
}
11. Javascript調(diào)用瀏覽器方法

現(xiàn)在從 Javascript 里可以這樣調(diào)用這個方法:

import { NativeModules } from "react-native";
const BlueToothPlugin = NativeModules.BlueToothPlugin;
BlueToothPlugin.initPeripheral({"peripheralName": "", "peripheralServiceID": "", "peripheralCharacteristicID": ""}, (msg) => {
                                         Alert.alert(JSON.stringify(msg));

                                         },(err) => {
                                         Alert.alert(JSON.stringify(err));
                                         });
BlueToothPlugin.sendData({"data": ""}, (msg) => {
                                         Alert.alert(JSON.stringify(msg));

                                         },(err) => {
                                         Alert.alert(JSON.stringify(err));
                                         });
BlueToothPlugin.disconnectBlueTooth((msg) => {
                                         Alert.alert(JSON.stringify(msg));

                                         },(err) => {
                                         Alert.alert(JSON.stringify(err));
                                         });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容