小程序蓝牙通讯ios
2015-09-25 13:56:40 u011587401 阅读数 594

iOS  蓝牙的相关框架有

1 GameKit.framework

【只能存在于iOS设备之间,既是服务端,又是客户端,多用于游戏】


2 CoreBlueTooth.framework

【必须要支持蓝牙4.0,且iPhone4以上,即至少4s手机。可与第三方设备交互数据,

官方demo是Temperature Sensor 】


3 ExternalAccessory.framework

【可于第三方蓝牙设备交互,但是蓝牙设备必须经过MFI认证,需要有苹果的协议,

官方demo是 EADemo和 BTLE】


4 Multipeer Connectivity.framework

【只能用于iOS设备之间,且iOS7才引入。主要是为了共享文件,但是文件是在sandbox内  ,

官方demo是ios7 sample】


下面我讲逐一进行讲解:

一、GameKit.framework

GameKit主要是完成联网的相关功能,包括蓝牙和Internet两种方式。

使用方法是:选择你的工程,切换到Build Phases 再选择 Link Binary With Libraries 点击加号 添加GameKit.framework库。

在头文件中包含必要的库头文件:#import <GameKit/GameKit.h>

另外需要两个协议: <GKPeerPickerControllerDelegate, GKSessionDelegate>,前者是用来触发网络查找模块的标准控件(窗口),后者是处理链接会话session的。

GKPeerPickerControllerDelegate 一般有三个方法需要实现:

-(GKSession *) peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type;

-(void) peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session;

-(void) peerPickerControllerDidCancel:(GKPeerPickerController *)picker;


触发产生网络查找窗口的方法:

GKPeerPickerController *picker = [[GKPeerPickerController alloc] init];

picker.delegate = self;

picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;

[picker show];


执行时,应该会有如下窗口:

发现设备后,应该时如下的样子:

联接成功后,会有新的session的产生。对于session的引用,主要是这两个方法。

- (void) receiveData:(NSData *)data fromPeer:(NSString *) peerID inSession: (GKSession *)session context: (void *)context

-(void) session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state

根据函数名字可以看出来,一个是用来控制收数据的,一个使用来处理联接状态发生变化的。

具体使用方法请参考:http://tech.it168.com/a2010/0114/837/000000837727.shtml

demo:http://code4app.com/ios/CoreBlueTooth蓝牙通信/538852ef933bf01e358b5556


二、CoreBlueTooth.framework

详情请参考:

http://blog.csdn.net/chenli522/article/details/17114417

http://blog.csdn.net/chenli522/article/details/17114933


三、 ExternalAccessory.framework

外部附件框架参考

1. 介绍
定义在:
    EAAccessory.h
    EAAccessoryManager.h
    EASession.h

2. EAAccessory类参考
EAAccessory类为你的程序提供了单一连接的附属硬件的信息。你可以使用这个类中的信息来确定你的程序是否能为给定的附件打开一个会话。当你打开会话后,你还可以为附件对象自定义一个委托来得知附件的状态变化。你的委托必须遵守EAAccessoryDelete协议。

你应该使用附件定义的协议来决定是否连接此附件。此协议与附件能够处理的数据类型有关。你可以使用其他属性来帮助你决定是否连接到这个附件,但是一系列的协议应该是你考虑的主要因素。

附件可以通过30针的底部连接器或是无线蓝牙与设备进行连接。

3.EAAccessoryManager类参考
EAAccessoryManager类和与基于iPhone操作系统的设备相连接的附件一起工作。你用这个类得到你的应用程序可能想连接的一系列附件。你还可以用这个类开始和终止发送附件连接或终止连接的声明。

4. EASession类参考
EASession类用来创建你的应用程序和与之相连的硬件附件的通信通道。创建会话时,你必须实现你想用来和附件通信的协议。初始化这个类的实例后,你用可以使用协议提供的输入输出数据流来与附件相互传输数据。

创建了一个会话对象后,你应当立即找回并设置会话提供的数据流对象。数据流发送事件到与它相关的委托中来告之数据流状态的改变。比如:数据流通知委托,数据正在等待被读取,或用来写数据的空间已经可以使用。

当用给定数据流发送或接收数据时,你负责保证根据特定的协议来格式化此数据。EASess并不知道特定的附件协议也不会在传输前后去格式化数据。


四、 Multipeer Connectivity.framework

详情请参考:

http://blog.csdn.net/phunxm/article/details/43450167

https://developer.apple.com/library/ios/documentation/MultipeerConnectivity/Reference/MultipeerConnectivityFramework/

2015-08-27 11:30:27 liulongcode 阅读数 222

1建立中心角色

1
2
3
#import <CoreBluetooth/CoreBluetooth.h> 
CBCentralManager *manager; 
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; 

2扫描外设(discover)

[manager scanForPeripheralsWithServices:nil options:options]; 

3连接外设(connect)

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 
{
        if([peripheral.name  isEqualToString:BLE_SERVICE_NAME]){
                [self connect:peripheral];
        }
s); 
}       
 
-(BOOL)connect:(CBPeripheral *)peripheral{
        self.manager.delegate = self;
        [self.manager connectPeripheral:peripheral
                                options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
}

  

4扫描外设中的服务和特征(discover)

1
2
3
4
5
6
7
8
9
10
11
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral 
       
    NSLog(@"Did connect to peripheral: %@", peripheral); 
    _testPeripheral = peripheral; 
       
    [peripheral setDelegate:self];  <br>//查找服务
    [peripheral discoverServices:nil]; 
       
       
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error 
   
       
    NSLog(@"didDiscoverServices"); 
       
    if (error) 
    
        NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]); 
           
        if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectService:withPeripheral:error:)]) 
            [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil]; 
           
        return
    
       
   
    for (CBService *service in peripheral.services) 
    
         //发现服务
        if ([service.UUID isEqual:[CBUUID UUIDWithString:UUIDSTR_ISSC_PROPRIETARY_SERVICE]]) 
        
            NSLog(@"Service found with UUID: %@", service.UUID);  <br>//查找特征
            [peripheral discoverCharacteristics:nil forService:service]; 
            break
        
           
           
    
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
     
    if (error)
    {
        NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
         
        [self error];
        return;
    }
     
    NSLog(@"服务:%@",service.UUID);
    for (CBCharacteristic *characteristic in service.characteristics)
    {
       //发现特征
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"xxxxxxx"]]) {
                NSLog(@"监听:%@",characteristic);<br>//监听特征
                [self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
         
    }
}

5与外设做数据交互(读 与 写)  

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error)
    {
        NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);
        self.error_b = BluetoothError_System;
        [self error];
        return;
    }
     
//    NSLog(@"收到的数据:%@",characteristic.value);
    [self decodeData:characteristic.value];
}

1
2
NSData *d2 = [[PBABluetoothDecode sharedManager] HexStringToNSData:@"0x02"];
                [self.peripheral writeValue:d2 forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
2013-04-01 09:30:56 wanghouqing 阅读数 1020

搞下蓝牙,集合下:


gamekit ios设备间使用

和蓝牙设备外设 External Accessory

低电 ble 使用CoreBluetooth 

EA:

和配件进行通讯

在iPhone OS 3.0及之后的系统上,External Accessory框架(ExternalAccessory.framework)提供了一种管道机制,使应用程序可以和iPhone或iPod touch设备的配件进行通讯。通过这种管道,应用程序开发者可以将配件级别的功能集成到自己的程序中。

为了使用External Accessory框架的接口,您必须将ExternalAccessory.framework加入到Xcode工程,并连接到相应的目标中。此外,还需要在相应的源代码文件的顶部包含一个#import <ExternalAccessory/ExternalAccessory.h>语句,才能访问该框架的类和头文件。有关如何为工程添加框架的更多信息,请参见Xcode工程管理指南中的工程中的文件部分;有关External Accessory框架中类的一般信息,请参见External Accessory框架参考

配件的基础

在和配件进行通讯之前,需要与配件的制造商紧密合作,理解配件提供的服务。制造商必须在配件的硬件中加入显式的支持,才能和iPhone OS进行通讯。作为这种支持的一部分,配件必须支持至少一种命令协议,也就是支持一种定制的通讯模式,使配件和应用程序之间可以进行数据传输。苹果并不维护一个协议的注册表,支持何种协议及是否使用其他制造商支持的定制或标准协议是由制造商自行决定的。

作为和配件制造商通讯的一部分,您必须找出给定的配件支持什么协议。为了避免名字空间发生冲突,协议的名称由反向的DNS字符串来指定,形式是com.apple.myProtocol。这使得每个配件制造商都可以根据自己的需要定义协议,以支持不同的配件产品线。

应用程序通过打开一个使用指定协议的会话来和配件进行通讯。打开会话的方法是创建一个EASession类的实例,该类中包含NSInputStreamNSOutputStream对象,可以和配件进行通讯。通过这些流对象,应用程序可以向配件发送未经加工的数据包,以及接收来自配件的类似数据包。因此,您必须按照期望的协议来理解每个数据包的格式。

声明应用程序支持的协议

能够和配件通讯的应用程序应该在其Info.plist文件中声明支持的协议,使系统知道在相应的配件接入时,该应用程序可以被启动。如果当前没有应用程序可以支持接入的配件,系统可以选择启动App Store并指向支持该设备的应用程序。

为了声明支持的协议,您必须在应用程序的Info.plist文件中包含UISupportedExternalAccessoryProtocols键。该键包含一个字符串数组,用于标识应用程序支持的通讯协议。您的应用程序可以在这个列表中以任意顺序包含任意数量的协议。系统并不使用这个列表来确定应用程序应该选择哪个协议,而只是用它来确定应用程序是否能够和相应的配件进行通讯。您的代码需要在开始和配件进行对话时选择适当的通讯协议。

在运行时连接配件

在配件接入系统并做好通讯准备之前,通过External Accessory框架无法看到配件。当配件变为可见时,您的应用程序就可以获取相应的配件对象,然后用其支持的一或多个协议打开会话。

共享的EAAccessoryManager对象为应用程序寻找与之通讯的配件提供主入口点。该类包含一个已经接入的配件对象的数组,您可以对其进行枚举,看看是否存在应用程序支持的配件。EAAccessory对象中的绝大多数信息(比如名称、制造商、和型号信息)都只是用于显示。如果您要确定应用程序是否可以连接一个配件,必须看配件的协议,确认应用程序是否支持其中的某个协议。

请注意:多个配件对象支持同一协议是可能的。如果发生这种情况,您的代码必须负责选择使用哪个配件对象。

对于给定的配件对象,每次只能有一个指定协议的会话。EAAccessory对象的protocolStrings属性包含一个字典,字典的键是配件支持的协议。如果您试图用一个已经在使用的协议创建会话,External Accessory框架就会产生错误。

程序清单8-1展示了如何检查接入配件的列表并从中取得应用程序支持的第一个配件。它为指定的协议创建一个会话,并对会话的输入和输出流进行配置。在这个方法返回会话对象时,已经完成和配件的连接,并可以开始发送和接收数据了。

程序清单8-1  创建和配件的通讯会话

- (EASession *)openSessionForProtocol:(NSString *)protocolString
{
    NSArray *accessories = [[EAAccessoryManager sharedAccessoryManager]
                                   connectedAccessories];
    EAAccessory *accessory = nil;
    EASession *session = nil;
 
    for (EAAccessory *obj in accessories)
    {
        if ([[obj protocolStrings] containsObject:protocolString])
        {
            accessory = obj;
            break;
        }
    }
 
    if (accessory)
    {
        session = [[EASession alloc] initWithAccessory:accessory
                                 forProtocol:protocolString];
        if (session)
        {
            [[session inputStream] setDelegate:self];
            [[session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop]
                                     forMode:NSDefaultRunLoopMode];
            [[session inputStream] open];
            [[session outputStream] setDelegate:self];
            [[session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop]
                                     forMode:NSDefaultRunLoopMode];
            [[session outputStream] open];
            [session autorelease];
        }
    }
 
    return session;
}

在配置好输入输出流之后,最好一步就是处理和流相关的数据了。程序清单8-2展示了在委托方法中处理流事件的基本代码结构。清单中的方法可以响应来自配件输入输出流的事件。当配件向应用程序发送数据时,事件发生表示有数据可供读取;类似地,当配件准备好接收应用程序数据时,也通过事件来表示(当然,您并不一定要等到这个事件发生才向流写出数据,应用程序也可以调用流的hasBytesAvailable方法来确认配件是否还能够接收数据)。有关流及如何处理流事件的更多信息,请参见Cocoa流编程指南

程序清单8-2  处理流事件

// Handle communications from the streams.
- (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent
{
    switch (streamEvent)
    {
        case NSStreamHasBytesAvailable:
            // Process the incoming stream data.
            break;
 
        case NSStreamEventHasSpaceAvailable:
            // Send the next queued command.
            break;
 
        default:
            break;
    }
 
}

监控与配件有关的事件

当配件接入或断开时,External Accessory框架都可以发送通告。但是这些通告并不自动发送,如果您的应用程序感兴趣,必须调用EAAccessoryManager类的registerForLocalNotifications方法来显式请求。当配件接入、认证、并准备好和应用程序进行交互时,框架可以发出一个EAAccessoryDidConnectNotification通告;而当配件断开时,框架则可以发送一个EAAccessoryDidDisconnectNotification通告。您可以通过缺省的NSNotificationCenter来注册接收这些通告。两种通告都包含受影响的配件的信息。

除了通过缺省的通告中心接收通告之外,当前正在和配件进行交互的应用程序可以为相应的EAAccessory对象分配一个委托,使它在发生变化的时候得到通知。委托对象必须遵循EAAccessoryDelegate协议,该协议目前包含名为accessoryDidDisconnect:的可选方法,您可以通过这个方法来接收配件断开通告,而不需要事先配置通告观察者。


2016-06-30 16:19:05 AirZingJ 阅读数 2847

蓝牙协议本身经历了从1.0到4.0的升级演变, 最新的4.0以其低功耗著称,所以一般也叫BLE(Bluetoothlow energy)。

iOS 有两个框架支持蓝牙与外设连接。一个是 ExternalAccessory。从ios3.0就开始支持,也是在iphone4s出来之前用的比较多的一种模式,但是它有个不好的地方,External Accessory需要拿到苹果公司的MFI认证。

另一个框架则是本文要介绍的CoreBluetooth,在iphone4s开始支持,专门用于与BLE设备通讯(因为它的API都是基于BLE的)。这个不需要MFI,并且现在很多蓝牙设备都支持4.0,所以也是在IOS比较推荐的一种开发方法。

CoreBluetooth介绍

CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。对应他们分别有一组相关的API和类,如下图所示:


如果你要编程的设备是central那么你大部分用到,反之亦然。在我们这个示例中,金融刷卡器是peripheral,我们的iphone手机是central,所以我将大部分使用上图中左边部分的类。使用peripheral编程的例子也有很多,比如像用一个ipad和一个iphone通讯,ipad可以认为是central,iphone端是peripheral,这种情况下在iphone端就要使用上图右边部分的类来开发了。

服务和特征

有个概念有必要先说明一下。什么是服务和特征呢(service and characteristic)?

每个蓝牙4.0的设备都是通过服务和特征来展示自己的,一个设备必然包含一个或多个服务,每个服务下面又包含若干个特征。特征是与外界交互的最小单位。比如说,一台蓝牙4.0设备,用特征A来描述自己的出厂信息,用特征B来与收发数据等。

服务和特征都是用UUID来唯一标识的,UUID的概念如果不清楚请自行google,国际蓝牙组织为一些很典型的设备(比如测量心跳和血压的设备)规定了标准的service UUID(特征的UUID比较多,这里就不列举了),如下:

#define      BLE_UUID_ALERT_NOTIFICATION_SERVICE   0x1811  
 #define     BLE_UUID_BATTERY_SERVICE   0x180F  
 #define     BLE_UUID_BLOOD_PRESSURE_SERVICE   0x1810  
 #define     BLE_UUID_CURRENT_TIME_SERVICE   0x1805  
 #define     BLE_UUID_CYCLING_SPEED_AND_CADENCE   0x1816  
 #define     BLE_UUID_DEVICE_INFORMATION_SERVICE   0x180A  
 #define     BLE_UUID_GLUCOSE_SERVICE   0x1808  
 #define     BLE_UUID_HEALTH_THERMOMETER_SERVICE   0x1809  
 #define     BLE_UUID_HEART_RATE_SERVICE   0x180D  
 #define     BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE   0x1812  
 #define     BLE_UUID_IMMEDIATE_ALERT_SERVICE   0x1802  
 #define     BLE_UUID_LINK_LOSS_SERVICE   0x1803  
 #define     BLE_UUID_NEXT_DST_CHANGE_SERVICE   0x1807  
 #define     BLE_UUID_PHONE_ALERT_STATUS_SERVICE   0x180E  
 #define     BLE_UUID_REFERENCE_TIME_UPDATE_SERVICE   0x1806  
 #define     BLE_UUID_RUNNING_SPEED_AND_CADENCE   0x1814  
 #define     BLE_UUID_SCAN_PARAMETERS_SERVICE   0x1813  
 #define     BLE_UUID_TX_POWER_SERVICE   0x1804  
 #define     BLE_UUID_CGM_SERVICE   0x181A  

当然还有很多设备并不在这个标准列表里,比如我用的这个金融刷卡器。蓝牙设备硬件厂商通常都会提供他们的设备里面各个服务(service)和特征(characteristics)的功能,比如哪些是用来交互(读写),哪些可获取模块信息(只读)等.

实现细节

作为一个中心要实现完整的通讯,一般要经过这样几个步骤:

建立中心角色—扫描外设(discover)—连接外设(connect)—扫描外设中的服务和特征(discover)—与外设做数据交互(explore and interact)—断开连接(disconnect)。

1建立中心角色

首先在我自己类的头文件中要包含CoreBluetooth的头文件,并继承两个协议<CBCentralManagerDelegate,CBPeripheralDelegate>,代码如下:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
#import <CoreBluetooth/CoreBluetooth.h>  
CBCentralManager *manager;  
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];  

2扫描外设(discover)

代码如下:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
[manager scanForPeripheralsWithServices:nil options:options];

这个参数应该也是可以指定特定的peripheral的UUID,那么理论上这个central只会discover这个特定的设备,但是我实际测试发现,如果用特定的UUID传参根本找不到任何设备,我用的代码如下:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
NSArray *uuidArray = [NSArray arrayWithObjects:[CBUUID UUIDWithString:@"1800"],[CBUUID UUIDWithString:@"180A"],  
[CBUUID UUIDWithString:@"1CB2D155-33A0-EC21-6011-CD4B50710777"],[CBUUID UUIDWithString:@"6765D311-DD4C-9C14-74E1-A431BBFD0652"],nil];  

[manager scanForPeripheralsWithServices:uuidArray options:options];  

目前不清楚原因,怀疑和设备本身在的广播包有关。

3连接外设(connect)
当扫描到4.0的设备后,系统会通过回调函数告诉我们设备的信息,然后我们就可以连接相应的设备,代码如下:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI  
{  

    if(![_dicoveredPeripherals containsObject:peripheral])  
        [_dicoveredPeripherals addObject:peripheral];  

    NSLog(@"dicoveredPeripherals:%@", _dicoveredPeripherals);  
}  

//连接指定的设备  
-(BOOL)connect:(CBPeripheral *)peripheral  
{  
    NSLog(@"connect start");  
    _testPeripheral = nil;  

    [manager connectPeripheral:peripheral  
                       options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];  

    //开一个定时器监控连接超时的情况  
    connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(connectTimeout:) userInfo:peripheral repeats:NO];  

    return (YES);  
}  

4扫描外设中的服务和特征(discover)
同样的,当连接成功后,系统会通过回调函数告诉我们,然后我们就在这个回调里去扫描设备下所有的服务和特征,代码如下:

[objc] view plain copy 在CODE上查看代码片派生到我的代码片
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral  
{  
    [connectTimer invalidate];//停止时钟  

    NSLog(@"Did connect to peripheral: %@", peripheral);  
    _testPeripheral = peripheral;  

    [peripheral setDelegate:self];  
    [peripheral discoverServices:nil];  


}  

一个设备里的服务和特征往往比较多,大部分情况下我们只是关心其中几个,所以一般会在发现服务和特征的回调里去匹配我们关心那些,比如下面的代码:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error  
{  


    NSLog(@"didDiscoverServices");  

    if (error)  
    {  
        NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);  

        if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectService:withPeripheral:error:)])  
            [self.delegate DidNotifyFailConnectService:nil withPeripheral:nil error:nil];  

        return;  
    }  


    for (CBService *service in peripheral.services)  
    {  

        if ([service.UUID isEqual:[CBUUID UUIDWithString:UUIDSTR_ISSC_PROPRIETARY_SERVICE]])  
        {  
            NSLog(@"Service found with UUID: %@", service.UUID);  
            [peripheral discoverCharacteristics:nil forService:service];  
            isVPOS3356 = YES;  
            break;  
        }  


    }  
}  

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error   
{  

    if (error)   
    {  
        NSLog(@"Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);  

        if ([self.delegate respondsToSelector:@selector(DidNotifyFailConnectChar:withPeripheral:error:)])  
            [self.delegate DidNotifyFailConnectChar:nil withPeripheral:nil error:nil];  

        return;  
    }  


    for (CBCharacteristic *characteristic in service.characteristics)  
    {  
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:UUIDSTR_ISSC_TRANS_TX]])  
        {  
            NSLog(@"Discovered read characteristics:%@ for service: %@", characteristic.UUID, service.UUID);  

            _readCharacteristic = characteristic;//保存读的特征  

            if ([self.delegate respondsToSelector:@selector(DidFoundReadChar:)])  
                [self.delegate DidFoundReadChar:characteristic];  

            break;  
        }  
    }  


    for (CBCharacteristic * characteristic in service.characteristics)  
    {  


        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:UUIDSTR_ISSC_TRANS_RX]])  
        {  

            NSLog(@"Discovered write characteristics:%@ for service: %@", characteristic.UUID, service.UUID);  
            _writeCharacteristic = characteristic;//保存写的特征  

            if ([self.delegate respondsToSelector:@selector(DidFoundWriteChar:)])  
                [self.delegate DidFoundWriteChar:characteristic];  

            break;  


        }  
    }  

    if ([self.delegate respondsToSelector:@selector(DidFoundCharacteristic:withPeripheral:error:)])  
        [self.delegate DidFoundCharacteristic:nil withPeripheral:nil error:nil];  

}  

5与外设做数据交互(explore and interact)

发送数据很简单,我们可以封装一个如下的函数:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
//写数据  
-(void)writeChar:(NSData *)data  
{  
    [_testPeripheral writeValue:data forCharacteristic:_writeCharacteristic type:CBCharacteristicWriteWithResponse];  
}  

_testPeripheral和_writeCharacteristic是前面我们保存的设备对象和可以读写的特征。

然后我们可以在外部调用它,比如当然我要触发刷卡时,先组好数据包,然后调用发送函数:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
-(void)msrRead  
{  

    unsigned char command[512] = {0};  
    unsigned charchar *pTmp;  
    int nSendLen = 0;  
    unsigned char ucCrc[3] = {0};  

    _commandType = COMMAND_MSR_READ;  

    pTmp = command;  


    *pTmp = 0x02;//start  
    pTmp++;  

    *pTmp = 0xc1;//main cmd  
    pTmp++;  

    *pTmp = 0x07;//sub cmd  
    pTmp++;  



    nSendLen = 2;  

    *pTmp = nSendLen/256;  
    pTmp++;  
    *pTmp = nSendLen%256;  
    pTmp++;  

    *pTmp = 0x00;//sub cmd  
    pTmp++;  

    *pTmp = 0x00;//sub cmd  
    pTmp++;  


    Crc16CCITT(command+1,pTmp-command-1,ucCrc);  
    memcpy(pTmp,ucCrc,2);  


    NSData *data = [[NSData alloc] initWithBytes:&command length:9];  
    NSLog(@"send data:%@", data);  
    [g_BLEInstance.recvData setLength:0];  

    [g_BLEInstance writeChar:data];  
}  

比如说,你要交互的特征,它的properties的值是0x10,表示你只能用订阅的方式来接收数据。我这里是用订阅的方式,启动订阅的代码如下:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
//监听设备  
-(void)startSubscribe  
{  
    [_testPeripheral setNotifyValue:YES forCharacteristic:_readCharacteristic];  
}  

当设备有数据返回时,同样是通过一个系统回调通知我,如下所示:
[objc] view plain copy 在CODE上查看代码片派生到我的代码片
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error  
{  

    if (error)   
    {  
        NSLog(@"Error updating value for characteristic %@ error: %@", characteristic.UUID, [error localizedDescription]);  

        if ([_mainMenuDelegate respondsToSelector:@selector(DidNotifyReadError:)])  
            [_mainMenuDelegate DidNotifyReadError:error];  

        return;  
    }  

    [_recvData appendData:characteristic.value];  


    if ([_recvData length] >= 5)//已收到长度  
    {  
        unsigned charchar *buffer = (unsigned charchar *)[_recvData bytes];  
        int nLen = buffer[3]*256 + buffer[4];  
        if ([_recvData length] == (nLen+3+2+2))  
        {  
            //接收完毕,通知代理做事  
            if ([_mainMenuDelegate respondsToSelector:@selector(DidNotifyReadData)])  
                [_mainMenuDelegate DidNotifyReadData];  

        }  
    }  

}  

6 断开连接(disconnect)

这个比较简单,只需要一个API就行了,代码如下:

[objc] view plain copy 在CODE上查看代码片派生到我的代码片
//主动断开设备  
-(void)disConnect  
{  

    if (_testPeripheral != nil)  
    {  
        NSLog(@"disConnect start");  
        [manager cancelPeripheralConnection:_testPeripheral];  
    }  

} 


2015-10-16 18:19:00 weixin_33709590 阅读数 3

CoreBluetooth

https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CoreBluetooth_Framework/

 

转载于:https://www.cnblogs.com/zhiupping8/p/4886037.html

iOS 蓝牙

阅读数 13

IOS 蓝牙

阅读数 18

iOS 蓝牙

阅读数 618

iOS 蓝牙

阅读数 572

iOS之蓝牙

阅读数 106

没有更多推荐了,返回首页