iOS 作为蓝牙外设广播信息

苹果蓝牙后台的限制,原本广播会有两个段分别是localName和serviceUUID这两块,但现在后台广播时,是不发送在这两段的

手机app可以作为一个蓝牙外设端来模拟外设硬件,但广播包里的数据只能包含localName和serviceUUID,相对于外设硬件来说还是有一些不足之处。

一个128位的蓝牙UUID来标示

32个 x 是 0-9 或 a-f 范围内的一个十六进制的数字(0x00),X是字符串格式

把数据按uuid的格式加进去

self.peripheralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:serviceUUIDs,CBAdvertisementDataNameKey:localName}];

对应的值是数组

key: kCBAdvDataIsConnectable, value: 1

key: kCBAdvDataLocalName, value: SimpleBLEPeripheral

key: kCBAdvDataServiceUUIDs    //数据就在这里

       uuid(0): FF F0

key: kCBAdvDataTxPowerLevel, value: 0

Manufacturer Specific Data

NSArray *keys = [advertisementData allKeys];

    NSData *dataAmb, *dataObj;

//获取所有的key

    for (int i = 0; i < [keys count]; ++i) {

        id key = [keys objectAtIndex: i];

        NSString *keyName = (NSString *) key;

        NSObject *value = [advertisementData objectForKey: key];

//处理所有的value

        if ([value isKindOfClass: [NSArray class]]) {

            printf("   key: %s ", [keyName cStringUsingEncoding: NSUTF8StringEncoding]);

            NSArray *values = (NSArray *) value;

//处理每个value里面的值

            for (int j = 0; j < [values count]; ++j) {

                if ([[values objectAtIndex: j] isKindOfClass: [CBUUID class]]) {

                    CBUUID *uuid = [values objectAtIndex: j];

                    NSData *data = uuid.data;  //获取到  uuid.data

                  if (j == 0) {

                        dataObj = uuid.data;

                    } else {

                        dataAmb = uuid.data;

                    }

                    printf("      uuid(%d):", j);

                    for (int j = 0; j < data.length; ++j)

                        printf(" %02X", ((UInt8 *) data.bytes)[j]);

                    printf(" ");

                } else {

                    const char *valueString = [[value description] cStringUsingEncoding: NSUTF8StringEncoding];

                    printf("      value(%d): %s ", j, valueString);

                }

            }

        } else {

            const char *valueString = [[value description] cStringUsingEncoding: NSUTF8StringEncoding];

            printf("   key: %s, value: %s ", [keyName cStringUsingEncoding: NSUTF8StringEncoding], valueString);

        }

    }

蓝牙周边后台执行模式

想要作为一个周边角色在后台工作,你需要在Info.plist文件中添加bluetooth-periphral到UIBackgroundModes关键字下。当你这么做了,系统会在你的app需要读,写,订阅事件的时候唤醒它。

除了可以在后台唤醒app处理连接的中心的读写订阅。蓝牙中心库还可以允许你的app在后台的时候广播。但是你需要了解app在后台的广播和在前台的广播状态不太一样。特别的,当你的app在后台广播时。

CBAdvertisementDataLocalNameKey 广告键是被忽略的,而且local name也不会被广播的

所以 CBAdvertisementDataServiceUUIDsKey中的服务UUID被放在一个“溢出”区,它们只能被明确搜索的iOS设备搜索到。

如果所有app都在后台广播,你的app的包广播频率会变少。

When you start advertising peripheral data, the peripheral manager calls the peripheralManagerDidStartAdvertising(_:error:) method of its delegate object.

Data advertising is done on a “best effort” basis, because space is limited and there may be multiple apps advertising simultaneously. While your app is in the foreground, it can use up to 28 bytes of space in the initial advertisement data for any combination of the supported advertising data keys. If this space is used up, there are an additional 10 bytes of space in the scan response that can be used only for the local name (represented by the value of the CBAdvertisementDataLocalNameKey key). Note that these sizes do not include the 2 bytes of header information that are required for each new data type. Any service universally unique identifiers (UUIDs) contained in the value of the CBAdvertisementDataServiceUUIDsKey key that do not fit in the allotted space are added to a special “overflow” area; they can be discovered only by an iOS device that is explicitly scanning for them. While your app is in the background, the local name is not advertised and all service UUIDs are placed in the overflow area. The exact format of advertising and response data is defined in the Bluetooth 4.0 specification, Volume 3, Part C, Section 11.

当开始广告外围设备数据时,外围设备管理器调用其委托对象的外围信息管理器didstartadvertising (_:error:)方法。

数据广告是在“尽最大努力”的基础上进行的,因为空间有限,同时可能有多个应用程序在做广告。当你的应用程序在前台时,它可以在初始广告数据中使用最多28字节的空间来组合支持的广告数据键。如果耗尽了这个空间,那么扫描响应中还有额外的10字节空间,只能用于本地名称(由CBAdvertisementDataLocalNameKey键值表示)。注意,这些大小不包括每个新数据类型所需的2个字节的头信息。在特定的“溢出”区域中添加不适合于分配的空间的CBAdvertisementDataServiceUUIDsKey键值中包含的任何服务通用惟一标识符(uuid);只有当iOS设备显式地扫描它们时,才能发现它们。当您的应用程序在后台时,本地名称没有广告,所有服务uuid都放置在溢出区域。广告和响应数据的确切格式定义在蓝牙4.0规范第3卷C部分第11节中。

在初始化中心或者周边管理者的时候选择是否需要支持状态的保存和恢复

在初始化时指定CBCentralManagerOptionRestoreIdentifierKey选项,并为中心管理者提供一个字符串作为“恢复标识”就可以了:

myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"myCentralManagerIdentifier" }];

CBPeripheralManagerOptionRestoreIdentifierKey

恢复你的中心和周边管理者

当你的app在后台被系统重启时,你的第一件事就是根据“恢复标识”恢复适当的中心和周边管理者就像他们第一次创建时一样

当你的app被系统重启时,你可以检索系统为你的应用程序保留的中央管理器对象的所有恢复标识符,像这样:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSArray *centralManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey];

在拿到恢复标示符之后,只需要遍历并恢复适当的中央管理者。

- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)state { NSArray *peripherals = state[CBCentralManagerRestoredStatePeripheralsKey]; ...

原文地址:https://www.cnblogs.com/Free-Thinker/p/11452081.html