蓝牙
1.GameKit
简介:
- 实现蓝牙设备之间的通讯
- 只能使用在iOS设备之间同一个应用内连接
- 从iOS7开始过期了
- 但是GameKit是最基本的蓝牙通讯框架
- 通过蓝牙可以实现文件的共享(仅限设备沙盒中的文件)
- 此框架一般用于游戏开发(比如五子棋对战)
#import "ViewController.h"
#import
@interface ViewController ()
/**
* 显示图片
*/
@property (weak, nonatomic) IBOutlet UIImageView *showImg;
/*
* 保存当前回话
*/
@property (nonatomic, strong) GKSession *session;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - delegate
/*
* 连接蓝牙的方式 附近 在线
*/
- (void)peerPickerController:(GKPeerPickerController *)picker didSelectConnectionType:(GKPeerPickerConnectionType)type {
NSLog(@"%s %d type =%lu picker %@",__func__,__LINE__,(unsigned long)type,picker);
}
// 连接会话的方式 附近 在线
- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type {
return nil;
}
/* 连接成功
* peerID 连接成功的设备id
* session 当前回话 只需要保存当前的会话 即 可 数据传递
*/
- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session {
// 隐藏选择器
[picker dismiss];
// 接收数据的回调 GameKIt 必须实现的
[session setDataReceiveHandler:self withContext:nil];
// 保存会话
self.session = session;
}
// 只要有数据回来 那么就会调用
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
{
// if (!data) return;
// 转换图片
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
self.showImg.image = img;
});
}
/*
* 退出
*/
- (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
{
}
#pragma mark - imageDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.showImg.image = info[UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - 按钮的点击
- (IBAction)connect:(id)sender {
// 创建蓝牙选择器
GKPeerPickerController *picker = [[GKPeerPickerController alloc]init];
picker.delegate = self;
// 显示
[picker show];
}
- (IBAction)selectImg:(id)sender {
UIImagePickerController *imgPicker = [[UIImagePickerController alloc]init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentViewController:imgPicker animated:YES completion:nil];
}
- (IBAction)sendImg:(id)sender {
if (!self.showImg.image) return;
//图片转化
NSData *data = UIImagePNGRepresentation(self.showImg.image);
// GKSendDataReliable 安全模式
// GKSendDataUnreliable 不安全模式
[self.session sendDataToAllPeers:data withDataMode:GKSendDataUnreliable error:nil];
NSLog(@"session = %@" , self.session);
}
@end
2.mutipeerConnectivity
- iOS 7引入的一个全新框架
- 多点连接
- 替代GameKit框架
- 多用于文件的传输
- iOS设备不联网也能跟附近的人聊天
- FireChat
- See You Around
- 以上近场聊天App都是基于mutipeerConnectivity框架
- 搜索和传输的方式
- 双方WIFI和蓝牙都没有打开:无法实现
- 双方都开启蓝牙:通过蓝牙发现和传输
- 双方都开启WIFI:通过WIFI Direct发现和传输,速度接近AirDrop
- 双方同时开启了WIFI和蓝牙:模拟AirDrop,通过低功耗蓝牙技术扫描发现握手,然后通过WIFI Direct传输
#import "ViewController.h"
#import
/*
1. 注册一个广告 告诉别人 我的设备是可以被发现
2. 扫描蓝牙设备 需要实现代理方法
3. 使用一个MCSession对象存储当前会话 需要实现代理方法
4. 使用MCSession 对象 发送和接收数据
*/
#define SERVICE_TYPE @"xmg"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *showImg;
// 保存会话
@property (nonatomic, strong)MCSession *m_session;
/** 发送广告 */
@property (nonatomic, strong) MCAdvertiserAssistant *assistant;
/** 当前连接到的设备 */
@property (nonatomic, strong) MCPeerID *peerId;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化 会话
// 获取设备的名字
NSString *displayName = [UIDevice currentDevice].name;
// 设备的id
MCPeerID *perrID = [[MCPeerID alloc]initWithDisplayName:displayName];
self.m_session = [[MCSession alloc]initWithPeer:perrID];
self.m_session.delegate = self;
}
// click events
- (IBAction)connect:(id)sender {
MCBrowserViewController *browser = [[MCBrowserViewController alloc]initWithServiceType:SERVICE_TYPE session:self.m_session];
browser.delegate = self;
[self presentViewController:browser animated:YES completion:nil];
}
- (IBAction)selecte:(id)sender {
UIImagePickerController *imgPicker = [[UIImagePickerController alloc]init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentViewController:imgPicker animated:YES completion:nil];
}
- (IBAction)sendImage:(id)sender {
if (!self.showImg.image) return;
// 发送数据
[self.m_session sendData:UIImagePNGRepresentation(self.showImg.image) toPeers:@[self.peerId] withMode:MCSessionSendDataUnreliable error:nil];
NSLog(@"===%@" ,self.m_session);
}
// 设置可被发现
- (IBAction)found:(id)sender {
UISwitch *s = (UISwitch *)sender;
if (s.isOn) {
// 注册广告 可能一个app 发送了多个广告, 所以需要给光绑定唯一标示
self.assistant = [[MCAdvertiserAssistant alloc]initWithServiceType:SERVICE_TYPE discoveryInfo:nil session:self.m_session];
[self.assistant start];
}
}
#pragma mark - 会话的代理方法
// 接收到的数据
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
dispatch_async(dispatch_get_main_queue(), ^{
self.showImg.image = [UIImage imageWithData:data];
});
}
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
}
#pragma mark - 扫描设备的代理
// 连接成功
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController
{
NSLog(@"%s %d",__func__,__LINE__);
[browserViewController dismissViewControllerAnimated:YES completion:nil];
}
// 退出连接
- (void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController
{
}
// 连接哪个设备
- (BOOL)browserViewController:(MCBrowserViewController *)browserViewController
shouldPresentNearbyPeer:(MCPeerID *)peerID
withDiscoveryInfo:(nullable NSDictionary *)info
{
NSLog(@"%s %d",__func__,__LINE__);
self.peerId = peerID;
return YES;
}
#pragma mark - imageDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.showImg.image = info[UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
}
@end
3.CoreBlueTooth
- 可用于第三方蓝牙设备交互,设备必须支持蓝牙4.0
- iPhone的设备必须是4S或者更新
- iPad设备必须是iPad mini或者更新
- iOS的系统必须是iOS 6或者更新
- 蓝牙4.0以
低功耗
著称,所以一般被称为BLE(bluetooth low energy) - 使用模拟器调试
- Xcode 4.6
- iOS 6.1
- 应用场景
- 运动手环
- 智能家居
- 拉卡拉蓝牙刷卡器
核心概念
- CBCentralManager:中心设备(用来连接到外部设备的管家)
- CBPeripheralManager:外部设备(第三方的蓝牙4.0设备)
#import "ViewController.h"
#import
@interface ViewController ()
@property(nonatomic,strong)NSMutableArray *peripherals;
@property(nonatomic,strong)CBCentralManager *cmgr;
@end
@implementation ViewController
- (NSMutableArray *)peripherals
{
if (!_peripherals) {
_peripherals = [NSMutableArray array];
}
return _peripherals;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建中心管家,并且设置代理
self.cmgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
// 2. 扫描外部设备
/**
* scanForPeripheralsWithServices :如果传入指定的数组,那么就只会扫描数组中对应ID的设备
* 如果传入nil,那么就是扫描所有可以发现的设备
* 扫描完外部设备就会通知CBCentralManager的代理
*/
if ([self.cmgr state]== CBCentralManagerStatePoweredOn) {
[self.cmgr scanForPeripheralsWithServices:nil options:0];
}
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(@"%s %d",__func__,__LINE__);
}
#pragma mark - CBCentralManagerDelegate
/**
* 发现外部设备,每发现一个就会调用这个方法
* 所以可以使用一个数组来存储每次扫描完成的数组
*/
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"%s %d",__func__,__LINE__);
// 有可能会导致重复添加扫描到的外设
// 所以需要先判断数组中是否包含这个外设
if(![self.peripherals containsObject:peripheral]){
[self.peripherals addObject:peripheral];
}
}
/**
* 连接外设成功调用
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"%s %d",__func__,__LINE__);
// 查找外设服务
[peripheral discoverServices:nil];
}
/**
* 模拟开始连接方法
*/
- (void)start
{
NSLog(@"%s %d",__func__,__LINE__);
// 3. 连接外设
for (CBPeripheral *ppl in self.peripherals) {
// 扫描外设的服务
// 这个操作应该交给外设的代理方法来做
// 设置代理
ppl.delegate = self;
[self.cmgr connectPeripheral:ppl options:nil];
}
}
#pragma mark - CBPeripheralDelegate
/**
* 发现服务就会调用代理方法
*
* @param peripheral 外设
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"%s %d",__func__,__LINE__);
// 扫描到设备的所有服务
NSArray *services = peripheral.services;
// 根据服务再次扫描每个服务对应的特征
for (CBService *ses in services) {
[peripheral discoverCharacteristics:nil forService:ses];
}
}
/**
* 发现服务对应的特征
*/
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
NSLog(@"%s %d",__func__,__LINE__);
// 服务对应的特征
NSArray *ctcs = service.characteristics;
// 遍历所有的特征
for (CBCharacteristic *character in ctcs) {
// 根据特征的唯一标示过滤
if ([character.UUID.UUIDString isEqualToString:@"XMG"]) {
NSLog(@"可以吃饭了");
}
}
}
/**
* 断开连接
*/
- (void)stop
{
NSLog(@"%s %d",__func__,__LINE__);
// 断开所有连接上的外设
for (CBPeripheral *per in self.peripherals) {
[self.cmgr cancelPeripheralConnection:per];
}
}
@end
4.运动手环
#import "ViewController.h"
#import "XMGBandingController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *userField;
@property (weak, nonatomic) IBOutlet UITextField *pswFeild;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)loginClick:(id)sender {
self.userField.text = @"[email protected]";
self.pswFeild.text = @"361283017xj";
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:self.userField.text forKey:@"account"];
// 78:A5:04:38:53:75
//#ifdef DEBUG
// [params setObject:@"lepao321lepao" forKey:@"password"];//测试时可以不用密码登陆
//#else
[params setObject:[self.pswFeild.text md5] forKey:@"password"];
//#endif
[params setObject:[UIDevice BIData] forKey:@"deviceInfo"];
[params setObject:@"AppStore" forKey:@"creative"];
[params setObject:[UIDevice IPv4] forKey:@"ip"];
// [TCLoadingView showWithLoadingText:@"正在加载中"];
[[HttpManager defaultManager] getRequestToUrl:url_login params:params complete:^(BOOL successed, NSDictionary *result) {
if (successed && [[result objectForKey:@"ret"] intValue]==1) {
NSLog(@"----result = %@",result);
XMGBandingController *bangding = [[XMGBandingController alloc]init];
[self.navigationController pushViewController:bangding animated:YES];
}else{
// [KeyWindow showAlertMessage:result?result[@"msg"]:@"服务器忙,请稍后再试" callback:nil];
}
// [TCLoadingView removeLoadingView];
}];
}
@end
#import "XMGBandingController.h"
#import
#define BLE_SERVICE_UUID @"FEE7"
#define BLE_WIRTE_UUID @"FEC7"
#define BLE_READ_UUID @"FEC8"
@interface XMGBandingController ()
@property (nonatomic,strong)CBCentralManager *cmgr;
@property (nonatomic,strong)CBPeripheral *peripheral;
@end
@implementation XMGBandingController
- (void)viewDidLoad
{
[super viewDidLoad];
// @[@"78:A5:04:38:53:75"]
self.view.backgroundColor = [UIColor whiteColor];
// 建立中心管家
self.cmgr = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
// 扫描外接设备
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if ([central state] == CBCentralManagerStatePoweredOn) {
[self.cmgr scanForPeripheralsWithServices:nil options:nil];
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"peripheral = %@",peripheral);
self.peripheral = peripheral;
self.peripheral.delegate = self;
[self.cmgr connectPeripheral:self.peripheral options:nil];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"%s %d",__func__,__LINE__);
[self.peripheral discoverServices:nil];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"=====%@",peripheral.services);
for (CBService *service in peripheral.services) {
if([service.UUID.UUIDString isEqualToString:@"FEE7"]){
[service.peripheral discoverCharacteristics:nil forService:service];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
NSLog(@"------%@",service.characteristics);
for (CBCharacteristic *chtcs in service.characteristics) {
[self.peripheral discoverDescriptorsForCharacteristic:chtcs];
[self.peripheral readValueForCharacteristic:chtcs];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"%s %d",__func__,__LINE__);
NSLog(@"------%@",characteristic);
for (CBDescriptor *dpr in characteristic.descriptors) {
[self.peripheral readValueForDescriptor:dpr];
}
}
@end