1.接入流程

1.1 支持环境

环境

兼容范围

备注

软件系统

目标版本:IOS 11.0

支持BLE功能

固件SDK

AC693NSDK, AC695NSDK,AC697NSDK等

建议咨询SDK负责人

开发工具

Xcode 13.0以上

建议使用最新版本

1.2 库导入

1.2.1 依赖库

1.2.2 导入库

  1. JL_BLEKit.framework : 蓝牙功能库

  2. JL_OTALib.framework : OTA升级业务库

  3. JL_AdvParse.framework : 杰理蓝牙设备广播包解析业务库

  4. JL_HashPair.framework : 设备认证业务库

  5. JLLogHelper.framework :日志打印管理库

可选配置库:

  1. JLPackageResKit.framework: 设备提示音/资源打包替换业务库

  2. JLBmpConvertKit.framework : PNG/GIF图片转换库

  3. JLDialUnit.framework :屏幕/表盘操作库

1.2.3 必要权限

//使用蓝牙权限
    Privacy - Bluetooth Peripheral Usage Description
Privacy - Bluetooth Always Usage Description

1.2.4 Xcode 配置

由于库里包含了扩展类的属性,需要在使用时配置 Other linker Flags

需要在工程的 Build Settings 中的 Other Linker Flags 添加 -ObjC

../_images/otherlinkerflags.jpg

1.3 SDK内部蓝牙管理

1.3.1 蓝牙初始化

 1//1、外部的引用
 2@property(strong,nonatomic) JL_BLEMultiple  *mBleMultiple;
 3@property(weak  ,nonatomic) JL_EntityM      *mBleEntityM;    //需要Weak引用,断开设备重新搜索,SDK需释放。(作为当前正在操作的设备使用)
 4@property(strong,nonatomic) NSString        *mBleUUID;
 5@property(weak  ,nonatomic) NSArray         *mFoundArray; //需要Weak引用,扫描到的设备。
 6@property(weak  ,nonatomic) NSArray         *mConnectedArray;//需要Weak引用,已连接的设备。
 7
 8//2、实例化SDK
 9self.mBleMultiple = [[JL_BLEMultiple alloc] init];
10self.mBleMultiple.BLE_FILTER_ENABLE = YES;    //过滤设备使能
11self.mBleMultiple.BLE_PAIR_ENABLE = YES;      //配对使能
12self.mBleMultiple.BLE_TIMEOUT = 7;            //连接超时时间
13
14//3、选择需要搜索设备类型
15self.mBleMultiple.bleDeviceTypeArr = @[@(JL_DeviceTypeWatch)];//只选Watch
16
17//4、SDK搜索到的设备,点击连接后,会加入bleConnectedArr数组中。
18//5、调用[self.mBleMultiple scanStart]会释放掉blePeripheralArr的JL_EntityM。
19self.mFoundArray = self.mBleMultiple.blePeripheralArr;
20
21//6、SDk已连接上的设备,断开连接后,会加入blePeripheralArr数组中。
22self.mConnectedArray = self.mBleMultiple.bleConnectedArr;
23
24//7、用mBleEntityM弱引用mConnectedArray中已连接的一个JL_EntityM设备,此后会用mBleEntity到内的【JL_ManagerM】发命令。

1.3.2 连接设备

 1//从已发现的设备列表里连接一个。
 2JL_EntityM *entity = self.mFoundArray[indexPath.row];
 3/**
 4连接设备
 5@param entity 蓝牙设备类
 6*/
 7[self.mBleMultiple connectEntity:entity
 8                        Result:^(JL_EntityM_Status status) {
 9    [JL_Tools mainTask:^{
10    /*【status】错误码与错误原因
11    JL_EntityM_StatusBleOFF         = 0,    //BLE蓝牙未开启
12    JL_EntityM_StatusConnectFail    = 1,    //BLE连接失败
13    JL_EntityM_StatusConnecting     = 2,    //BLE正在连接
14    JL_EntityM_StatusConnectRepeat  = 3,    //BLE重复连接
15    JL_EntityM_StatusConnectTimeout = 4,    //BLE连接超时
16    JL_EntityM_StatusConnectRefuse  = 5,    //BLE被拒绝
17    JL_EntityM_StatusPairFail       = 6,    //配对失败
18    JL_EntityM_StatusPairTimeout    = 7,    //配对超时
19    JL_EntityM_StatusPaired         = 8,    //已配对
20    JL_EntityM_StatusMasterChanging = 9,    //正在主从切换
21    JL_EntityM_StatusDisconnectOk   = 10,   //已断开成功
22    JL_EntityM_StatusNull           = 11,   //Entity为空 */
23
24    if (status == JL_EntityM_StatusPaired) {
25        NSString *txt = [NSString stringWithFormat:@"连接成功:%@",deviceName];
26    }else{
27        NSString *txt = [NSString stringWithFormat:@"连接失败:%@",deviceName];
28    }
29    }];
30}];
31
32/*--- 注意事项
33//mBleEntityM在文档1.3.1里有介绍;
34//连接成功后必须先获取设备信息;
35[self.mBleEntityM.mCmdManager cmdTargetFeatureResult:^(NSArray *array) {
36    JL_CMDStatus st = [array[0] intValue];
37    if (st == JL_CMDStatusSuccess) {
38        /*--- 设备信息的model ---*/
39    JLModel_Device *model = [self.mBleEntityM.mCmdManager outputDeviceModel];
40        NSLog(@"获取成功。");
41    }else{
42        NSLog(@"获取失败。");
43    }
44}];

1.3.3 断开设备

 1/**
 2连接设备
 3@param entity 蓝牙设备类
 4*/
 5[self.mBleMultiple disconnectEntity:entity Result:^(JL_EntityM_Status status) {
 6    [JL_Tools mainTask:^{
 7        if (status == JL_EntityM_StatusDisconnectOk) {
 8            NSString *txt = [NSString stringWithFormat:@"已断开:%@",deviceName];
 9        }
10    }];
11}];

1.3.4 MAC地址回连设备

1[self.mBleMultiple connectEntityForMac:@"Mac地址" Result:^(JL_EntityM_Status status) {
2    [JL_Tools mainTask:^{
3        if (status == JL_EntityM_StatusPaired) {
4            NSLog(@"----> 回连设备成功。");
5        }else{
6            NSLog(@"----> 回连设备成功失败。");
7            }
8        }];
9}];

1.3.5 UUID回连设备

 1//根据UUID找到对应的JL_EntityM连接。
 2JL_EntityM *entity = [bleMp makeEntityWithUUID:@"UUID-xxxx-xxxx-xxxx-xxxx"];
 3
 4/*--- 1、直接UUID连接设备 ---*/
 5[self.mBleMultiple connectEntity:entity Result:^(JL_EntityM_Status status){
 6    [JL_Tools mainTask:^{
 7        if (status == JL_EntityM_StatusPaired) {
 8            NSLog(@"----> UUID回连设备成功。");
 9        }else{
10            NSLog(@"----> 回连设备成功失败。");
11        }
12    }];
13}];

1.3.6 蓝牙连接成功后的初始化

 1//收到kJL_BLE_M_ENTITY_CONNECTED通知,做以下处理:
 2/*--- 关闭耳机信息推送 ---*/
 3[self.mBleEntityM.mCmdManager.mTwsManager cmdHeadsetAdvEnable:NO];
 4
 5/*--- 同步时间戳 ---*/
 6NSDate *date = [NSDate new];
 7JL_SystemTime *systemTime = self.mBleEntityM.mCmdManager.mSystemTime;
 8[systemTime cmdSetSystemTime:date];
 9
10/*--- 清理设备音乐缓存 ---*/
11[self.mBleEntityM.mCmdManager.mFileManager cmdCleanCacheType:JL_CardTypeUSB];
12[self.mBleEntityM.mCmdManager.mFileManager cmdCleanCacheType:JL_CardTypeSD_0];
13[self.mBleEntityM.mCmdManager.mFileManager cmdCleanCacheType:JL_CardTypeSD_1];
14
15__weak typeof(self) wSelf = self;
16/*--- 获取设备信息 ---*/
17[self.mBleEntityM.mCmdManager cmdTargetFeatureResult:^(JL_CMDStatus status,uint8_t sn,NSData *_Nullable data){
18        JL_CMDStatus st = status;
19        if(st == JL_CMDStatusSuccess){
20            [wSelf startTimeout];
21
22        JLModel_Device *model = [wSelf.mBleEntityM.mCmdManager outputDeviceModel];
23        JL_OtaStatus upSt = model.otaStatus;
24        if(upSt == JL_OtaStatusForce){
25            wSelf.mBleEntityM.mBLE_NEED_OTA = YES;
26            return;
27}else{
28    if(model.otaHeadset == JL_OtaHeadsetYES){
29        wSelf.mBleEntityM.mBLE_NEED_OTA = YES;
30        return;
31    }
32}
33wSelf.mBleEntityM.mBLE_NEED_OTA = NO;
34
35/*--- 共有信息 ---*/
36        [wSelf.mBleEntityM.mCmdManager cmdGetSystemInfo:JL_FunctionCodeCOMMON Result:^(JL_CMDStatus status,uint8_t sn,NSData *_Nullable data){
37            [wSelf.mBleEntityM.mCmdManager cmdGetSystemInfo:JL_FunctionCodeBT Result:^(JL_CMDStatus status,uint8_t sn,NSData *_Nullable data){
38
39            }];
40        }];
41    }
42}];

1.3.7 监听发现、连接、断开、蓝牙状态等通知回调

 1extern NSString *kJL_BLE_M_FOUND;               //1、发现设备
 2extern NSString *kJL_BLE_M_FOUND_SINGLE;        //2、发现单个设备
 3extern NSString *kJL_BLE_M_ENTITY_CONNECTED;    //3、设备连接
 4extern NSString *kJL_BLE_M_ENTITY_DISCONNECTED; //4、设备断开
 5extern NSString *kJL_BLE_M_ON;                  //5、BLE开启
 6extern NSString *kJL_BLE_M_OFF;                 //6、BLE关闭
 7extern NSString *kJL_BLE_M_EDR_CHANGE;          //7、经典蓝牙输出通道变化
 8//监听第1、3、4点通知,查看mBleMultiple.blePeripheralArr数组元素变化,更新UI界面。
 9//监听第5点通知,则知道当前经典蓝牙连接的变化,回调经典蓝牙信息:
10            @{@"ADDRESS":@"7c9a1da7330e",      //经典蓝牙地址
11            @"TYPE"   :@"BluetoothA2DPOutput", //类型
12            @"NAME"   :@"earphone"}            //名字

1.4 SDK外部蓝牙管理

外部蓝牙管理,在使用JL_BLEKit.framework的同时,在蓝牙管理部分交由 外边(开发者自定义蓝牙)统筹管理 ,可保障使用时的多样化。

参考Demo:「 JL_OTA项目的 BleByAssist文件夹」 支持的功能

  • BLE设备握手连接;

  • 获取设备信息;

  • OTA升级能实现;

  • 注意:所有BLE操作都需自行实现;

会用到的类

  • JL_Assist :部署SDK类;(必须)

  • JL_ManagerM :命令处理中心,所有的命令操作都集中于此;(必须)

  • JLModel_Device :设备信息存储的数据模型;(必须)

BLE参数

  • 【服务号】 :AE00

  • 【写】特征值 :AE01

  • 【读 】特征值 :AE02

1.4.1 初始化SDK

 1    /*--- JLSDK ADD ---*/
 2    _mAssist = [[JL_Assist alloc] init];
 3    _mAssist.mNeedPaired = _isPaired;             //是否需要握手配对
 4    /*--- 自定义配对码(16个字节配对码) ---*/
 5    //char pairkey[16] = {0x01,0x02,0x03,0x04,
 6    //                    0x01,0x02,0x03,0x04,
 7    //                    0x01,0x02,0x03,0x04,
 8    //                    0x01,0x02,0x03,0x04};
 9    //NSData *pairData = [NSData dataWithBytes:pairkey length:16];
10    _mAssist.mPairKey    = nil;             //配对秘钥(或者自定义配对码pairData)
11    _mAssist.mService    = FLT_BLE_SERVICE; //服务号
12    _mAssist.mRcsp_W     = FLT_BLE_RCSP_W;  //特征「写」
13    _mAssist.mRcsp_R     = FLT_BLE_RCSP_R;  //特征「读」

1.4.2 BLE设备特征回调

1#pragma mark - 设备特征回调
2- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service
3            error:(nullable NSError *)error
4{
5    if (error) { NSLog(@"Err: Discovered Characteristics fail."); return; }
6
7    /*--- JLSDK ADD ---*/
8    [self.mAssist assistDiscoverCharacteristicsForService:service Peripheral:peripheral];
9}

1.4.3 BLE更新通知特征的状态

 1#pragma mark - 更新通知特征的状态
 2- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic
 3            error:(nullable NSError *)error
 4{
 5    if (error) { NSLog(@"Err: Update NotificationState For Characteristic fail."); return; }
 6
 7    /*--- JLSDK ADD ---*/
 8    __weak typeof(self) weakSelf = self;
 9    [self.mAssist assistUpdateCharacteristic:characteristic Peripheral:peripheral Result:^(BOOL isPaired) {
10        if (isPaired == YES) {
11            weakSelf.lastUUID = peripheral.identifier.UUIDString;
12            weakSelf.lastBleMacAddress = nil;
13
14            weakSelf.mBlePeripheral = peripheral;
15            /*--- UI配对成功 ---*/
16            [JL_Tools post:kFLT_BLE_PAIRED Object:peripheral];
17        } else {
18            [weakSelf.bleManager cancelPeripheralConnection:peripheral];
19        }
20    }];
21}

1.4.4 BLE设备返回的数据

1#pragma mark - 设备返回的数据 GET
2- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
3            error:(NSError *)error
4{
5    if (error) { NSLog(@"Err: receive data fail."); return; }
6
7    /*--- JLSDK ADD ---*/
8    [self.mAssist assistUpdateValueForCharacteristic:characteristic];
9}

1.4.5 BLE设备断开连接

 1#pragma mark - 设备断开连接
 2- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral
 3                error:(nullable NSError *)error
 4{
 5    NSLog(@"BLE Disconnect ---> Device %@ error:%d", peripheral.name, (int)error.code);
 6    self.mBlePeripheral = nil;
 7
 8    /*--- JLSDK ADD ---*/
 9    [self.mAssist assistDisconnectPeripheral:peripheral];
10
11    /*--- UI刷新,设备断开 ---*/
12    [JL_Tools post:kFLT_BLE_DISCONNECTED Object:peripheral];
13}

1.4.6 手机蓝牙状态更新

 1//外部蓝牙,手机蓝牙状态回调处,实现以下:
 2#pragma mark - 蓝牙初始化 Callback
 3- (void)centralManagerDidUpdateState:(CBCentralManager *)central
 4{
 5    _mBleManagerState = central.state;
 6
 7    /*--- JLSDK ADD ---*/
 8    [self.mAssist assistUpdateState:central.state];
 9
10    if (_mBleManagerState != CBManagerStatePoweredOn) {
11        self.mBlePeripheral = nil;
12        self.blePeripheralArr = [NSMutableArray array];
13    }
14}

1.4.7 获取设备信息

BLE连接且配对后必须执行一次

 1    [self.mAssist.mCmdManager cmdTargetFeatureResult:^(NSArray * _Nullable array) {
 2    JL_CMDStatus st = [array[0] intValue];
 3    if (st == JL_CMDStatusSuccess) {
 4        JLModel_Device *model = [weakSelf.mAssist.mCmdManager outputDeviceModel];
 5        JL_OtaStatus upSt = model.otaStatus;
 6        if (upSt == JL_OtaStatusForce) {
 7            NSLog(@"---> 进入强制升级.");
 8            if (weakSelf.selectedOtaFilePath) {
 9                [weakSelf otaFuncWithFilePath:weakSelf.selectedOtaFilePath];
10            } else {
11                callback(true);
12            }
13            return;
14        } else {
15            if (model.otaHeadset == JL_OtaHeadsetYES) {
16                NSLog(@"---> 进入强制升级: OTA另一只耳机.");
17                if (weakSelf.selectedOtaFilePath) {
18                    [weakSelf otaFuncWithFilePath:weakSelf.selectedOtaFilePath];
19                } else {
20                    callback(true);
21                }
22                return;
23            }
24        }
25        NSLog(@"---> 设备正常使用...");
26        [JL_Tools mainTask:^{
27            /*--- 获取公共信息 ---*/
28            [weakSelf.mAssist.mCmdManager cmdGetSystemInfo:JL_FunctionCodeCOMMON Result:nil];
29        }];
30    } else {
31        NSLog(@"---> ERROR:设备信息获取错误!");
32    }
33}];

1.4.8 固件OTA升级

 1//升级流程:连接设备-->获取设备信息-->是否强制升级-->(是)则必须调用该API去OTA升级;
 2 // (否)则可以正常使用APP;
 3
 4 NSLog(@"current otaFilePath ---> %@", otaFilePath);
 5self.selectedOtaFilePath = otaFilePath;
 6NSData *otaData = [[NSData alloc] initWithContentsOfFile:otaFilePath];
 7
 8JL_OTAManager *otaManager = self.mAssist.mCmdManager.mOTAManager;
 9
10[otaManager cmdOTAData:otaData Result:^(JL_OTAResult result, float progress) {
11
12    if (result == JL_OTAResultUpgrading || result == JL_OTAResultPreparing) {
13        if (result == JL_OTAResultPreparing) NSLog(@"---> 校验文件中");;
14        if (result == JL_OTAResultUpgrading) NSLog(@"---> 正在升级");
15    } else if (result == JL_OTAResultPrepared) {
16        NSLog(@"---> 检验文件【完成】");
17    } else if (result == JL_OTAResultReconnect) {
18
19        NSLog(@"---> OTA正在回连设备... %@", self.mAssist.mCmdManager);
20
21        //TODO: 这里需要开发者自行操作回连设备的UUIDString
22
23        [self otaTimeClose];//关闭超时检测
24    } else if (result == JL_OTAResultReconnectWithMacAddr) {
25
26        NSLog(@"---> OTA正在通过Mac Addr方式回连设备... %@", [JLBleManager sharedInstance].mBlePeripheral.name);
27        JLModel_Device *model = [self.mAssist.mCmdManager outputDeviceModel];
28
29        //TODO: 开发者需要利用这里的model.bleAddr地址去搜索回连已经升级了一半的设备,然后继续发起查询,再完成升级
30
31        [self otaTimeClose];//关闭超时检测
32    } else if (result == JL_OTAResultSuccess) {
33        NSLog(@"--->升级成功.");
34    } else if (result == JL_OTAResultReboot) {
35        NSLog(@"--->设备重启.");
36    } else {
37        // 其余错误码详细 Command+点击JL_OTAResult 查看说明
38        NSLog(@"ota update result: %d", result);
39    }
40}];