iOS开发之蓝牙开发

蓝牙

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

你可能感兴趣的:(iOS开发之蓝牙开发)