IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS 蓝牙开发实现文件传输 -> 正文阅读

[移动开发]iOS 蓝牙开发实现文件传输

??这是一篇旧文,三年前就写过了,一直没有时间分享出来,最近简单整理了下,希望能帮到有需要的人。
??由于我这里没有相关的蓝牙设备,主要用了两个手机,一个作为主设备,一个做为从设备。另外进行蓝牙开发有一个调试利器。
在这里插入图片描述
主设备和从设备我分别创建了一个管理类。
主设备主要进行的操作如下:

  • 开始扫描设备
  • 停止扫描设备
  • 连接设备
  • 断开连接设备
  • 发送数据

具体源码如下:

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

NS_ASSUME_NONNULL_BEGIN

@interface JKBlueToothCenterHelper : NSObject
/// 设备管理者状态block
@property (nonatomic, copy) void(^btStatusBlock)(NSInteger status,NSString *message);
/// 设备连接状态的block
@property (nonatomic, copy) void(^btConnectStatusBlock)(CBPeripheral *peripheral, NSError * _Nullable error);
/// 断开链接block
@property (nonatomic, copy) void(^btDisconnectStatusBlock)(CBPeripheral *peripheral, NSError * _Nullable error);
/// 扫描到的设备列表block
@property (nonatomic,copy) void(^btScanDevicesBlock)(NSMutableArray <CBPeripheral *>*devices);

/// 接收到数据的block
@property (nonatomic,copy) void(^receivedDataBlock)(NSData *data, NSError *error);

/**
 开始扫描设备

 @param services 扫描的服务
 @param options 扫描的选项配置
 @param containDefaultService 是否包含默认的服务
 @return JKBlueToothCenterHelper 对象
 */
- (instancetype)initWithScanServices:(nullable NSArray<CBUUID *> *)services options:(nullable NSDictionary <NSString *, id> *)options containDefaultService:(BOOL)containDefaultService;

/**
扫描设备
 */
- (void)scanDevice;

/**
 停止扫描设备
 */
- (void)stopScanDevice;

/**
 连接设备

 @param peripheral 设备
 @param options 配置信息
 */
- (void)connectToDevice:(CBPeripheral *)peripheral options:(NSDictionary <NSString *, id> *)options;

/**
 断开连接设备

 @param peripheral 设备
 */
- (void)disconnectToDevice:(CBPeripheral *)peripheral;


/**
 设备管理者向设备发送数据

 @param data 二进制数据
 @param peripheral 接受数据的设备
 @param CBCharacteristic 特征
 @param type 请求类型
 */
- (void)sendData:(NSData *)data toPeripheral:(CBPeripheral *)peripheral forCharacteristic:(CBCharacteristic *)CBCharacteristic type:(CBCharacteristicWriteType)type complete:(void(^)(NSError *error))completeBlock;

@end

NS_ASSUME_NONNULL_END
typedef void(^JKBTCenterSendCompleteBlock)(NSError *error);

@interface JKBlueToothCenterHelper()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property (nonatomic, strong) CBCentralManager  *centerManager; ///< 管理者
@property (nonatomic, strong) NSMutableArray *scanServices;            ///< 扫描的服务
@property (nonatomic, strong) NSDictionary <NSString *, id>      *scanOptions; ///< 扫描的配置
@property (nonatomic,strong) NSMutableArray *scannedDevices; ///< s扫描到的设备
@property (strong , nonatomic) CBPeripheral * discoveredPeripheral;//周边设备
@property (nonatomic,copy) JKBTCenterSendCompleteBlock sendCompleteBlock;


@end

@implementation JKBlueToothCenterHelper
- (instancetype)initWithScanServices:(nullable NSArray<CBUUID *> *)services options:(nullable NSDictionary <NSString *, id> *)options containDefaultService:(BOOL)containDefaultService{
    self = [super init];
    if (self) {
        
        [self.scanServices addObjectsFromArray:services];
        if (containDefaultService) {
            [self setupDefalutScanService];
        }
        self.scanOptions = options;
        [self centerManager];
    }
    return self;
}

- (void)setupDefalutScanService{
    CBUUID *uuid = [CBUUID UUIDWithString:DEFAULT_SERVICE_UUID];
    [self.scanServices addObject:uuid];
    
}

- (void)scanDevice{
     [self.scannedDevices removeAllObjects];
     [self.centerManager scanForPeripheralsWithServices:self.scanServices options:self.scanOptions];
}

- (void)stopScanDevice{
    
    [self.centerManager stopScan];
}

- (void)connectToDevice:(CBPeripheral *)peripheral options:(NSDictionary <NSString *, id> *)options{
    self.discoveredPeripheral = peripheral;
    self.discoveredPeripheral.delegate = self;
    [self.centerManager connectPeripheral:peripheral options:options];
}

- (void)disconnectToDevice:(CBPeripheral *)peripheral{
    [self.centerManager cancelPeripheralConnection:peripheral];
}

- (void)sendData:(NSData *)data toPeripheral:(CBPeripheral *)peripheral forCharacteristic:(CBCharacteristic *)CBCharacteristic type:(CBCharacteristicWriteType)type complete:(void(^)(NSError *error))completeBlock{
    self.sendCompleteBlock = completeBlock;
    [peripheral writeValue:data forCharacteristic:CBCharacteristic type:type];
}

#pragma mark - - - - CBCentralManagerDelegate - - - -
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    if (@available(iOS 10.0, *)) {
        switch (central.state) {
            case CBManagerStatePoweredOn://蓝牙打开
            {
                [self.centerManager scanForPeripheralsWithServices:self.scanServices options:self.scanOptions];
            }
                break;
            case CBManagerStatePoweredOff://蓝牙关闭了
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(CBManagerStatePoweredOff, @"蓝牙已关闭,请打开蓝牙");
                }
            }
                break;
            case CBManagerStateUnsupported://不支持
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(CBManagerStatePoweredOff, @"蓝牙设备不支持!");
                }
            }
                break;
                
            default:
                break;
        }
        
    } else {
        // Fallback on earlier versions
            switch (central.state) {
                case 5://蓝牙打开
                {
                    [self.centerManager scanForPeripheralsWithServices:self.scanServices options:self.scanOptions];
                }
                    break;
                case 4://蓝牙关闭了
                {
                    if (self.btStatusBlock) {
                        self.btStatusBlock(4, @"蓝牙已关闭,请打开蓝牙");
                    }
                }
                    break;
                case 2://不支持
                {
                    if (self.btStatusBlock) {
                        self.btStatusBlock(2, @"蓝牙设备不支持!");
                    }
                }
                    break;
                    
                default:
                    break;
            }
    }
    
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    if (!peripheral) {
        return;
    }
    [peripheral discoverServices:self.scanServices];
    if (![self.scannedDevices containsObject:peripheral]) {
        [self.scannedDevices addObject:peripheral];
        if (self.btScanDevicesBlock) {
            self.btScanDevicesBlock(self.scannedDevices);
        }
    }
    
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(nonnull CBPeripheral *)peripheral error:(nullable NSError *)error{
    if (self.btConnectStatusBlock) {
        self.btConnectStatusBlock(peripheral, error);
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    if (@available(iOS 9.0, *)) {
        if (self.centerManager.isScanning) {
            [self stopScanDevice];
        }
    } else {
        // Fallback on earlier versions
        [self stopScanDevice];
    }
    self.discoveredPeripheral = peripheral;
    [peripheral setDelegate:self];
    [peripheral discoverServices:nil];
    
    if (self.btConnectStatusBlock) {
        self.btConnectStatusBlock(peripheral, nil);
    }
}


- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(nonnull CBPeripheral *)peripheral error:(nullable NSError *)error{
    if (self.btDisconnectStatusBlock) {
        self.btDisconnectStatusBlock(peripheral, error);
    }
}

//- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *, id> *)dict{
//    
//}


#pragma mark - - - - CBPeripheralDelegate - - - -
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error{
    peripheral.delegate = self;
    NSArray *services = peripheral.services;
    for (CBService *service in services) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error{
    
    for (CBCharacteristic *characteristic in service.characteristics) {
        if ([[NSString stringWithFormat:@"%@",characteristic.UUID] isEqualToString: DEFAULT_CHARACTERISTIC_UUID]) {
            [self.discoveredPeripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
        
    }
    
}


// 写入成功
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (self.sendCompleteBlock) {
        self.sendCompleteBlock(error);
    }
}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        //NSLog(@"订阅失败");
        //NSLog(@"%@",error);
    }
    if (characteristic.isNotifying) {
        //NSLog(@"订阅成功");
        
    } else {
        //NSLog(@"取消订阅");
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    [peripheral readValueForCharacteristic:characteristic];
    NSData *data = characteristic.value;
    
    if (self.receivedDataBlock) {
        self.receivedDataBlock(data,error);
    }
}


#pragma mark - - - - lazyLoad - - - -
- (CBCentralManager *)centerManager{
    if (!_centerManager) {
        dispatch_queue_t queue = dispatch_queue_create("com.btCenterManager.queue", 0);
        CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:queue options:nil];
        centralManager.delegate = self;
        _centerManager = centralManager;
    }
    return _centerManager;
}

- (NSMutableArray *)scannedDevices{
    if (!_scannedDevices) {
        _scannedDevices = [NSMutableArray new];
    }
    return _scannedDevices;
}

- (NSMutableArray *)scanServices{
    if (!_scanServices) {
        _scanServices = [NSMutableArray new];
    }
    return _scanServices;
}

@end

从设备进行的操作如下:

  • 添加服务
  • 开始广播
  • 停止广播
  • 发送数据
    具体源码如下:
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

typedef void(^JKBTPeripheralStatusBlock)(NSInteger status,NSString *message);
typedef void(^JKBTPeripheralRecievedDataBlock)(NSData *data,NSError *error);

@interface JKBlueToothPeripheralHelper : NSObject

@property (nonatomic,copy) JKBTPeripheralStatusBlock btStatusBlock;///< 蓝牙状态的block
@property (nonatomic,copy) JKBTPeripheralRecievedDataBlock receivedDataBlock;



/**
 初始化JKBlueToothPeripheralHelper 对象

 @param services 提供的服务数组
 @param adContent 广播内容
 */
- (void)addServices:(NSArray <CBMutableService *>*)services adContent:(NSDictionary *)adContent;

/**
 添加默认的服务
 */
- (void)addDefaultService;

/**
 开始广播
 */
- (void)startAdvertising;

/**
 停止广播
 */
- (void)stopAdvertising;

/**
发送数据到设备管理器

 @param data 二进制数据
 @param centerDevices 主设备
 @param characteristic 特征
 */
- (void)sendData:(NSData *)data toCenterManagers:(NSArray <CBCentral*>*)centerDevices forCharacteristic:(CBMutableCharacteristic *)characteristic;

@end

#import "JKBlueToothPeripheralHelper.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <UIKit/UIKit.h>
#import "JKBlueToothMacro.h"
@interface JKBlueToothPeripheralHelper()<CBPeripheralManagerDelegate>
@property (nonatomic,strong)CBPeripheralManager *peripheralManager;
@property (nonatomic,strong) NSDictionary *adContent;        ///< 广播内容
@property (nonatomic,strong) CBMutableService *defaultService; ///< 默认提供的服务
@property (nonatomic,strong) CBMutableCharacteristic *defaultCharacteristic; ///< 默认具有的特征
@property (nonatomic,strong) NSMutableArray <CBMutableService *>*services;
@property (nonatomic,strong) NSMutableArray <CBCentral *>*centrals;
@end

@implementation JKBlueToothPeripheralHelper

- (void)addServices:(NSArray <CBMutableService *>*)services adContent:(NSDictionary *)adContent{
    if (!self.peripheralManager) {
        dispatch_queue_t queue = dispatch_queue_create("com.btPeripheralManager.queue", 0);
        self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:queue];
    }
    if (services.count>0) {
        [self.services addObjectsFromArray:services];
    }
    self.adContent = adContent;
    
}

- (void)addDefaultService{
    CBUUID *serviceID = [CBUUID UUIDWithString:DEFAULT_SERVICE_UUID];
    CBMutableService *service = [[CBMutableService alloc] initWithType:serviceID primary:YES];
    // 创建服务中的特征
    CBUUID *characteristicID = [CBUUID UUIDWithString:DEFAULT_CHARACTERISTIC_UUID];
    CBMutableCharacteristic *characteristic = [
                                               [CBMutableCharacteristic alloc]
                                               initWithType:characteristicID
                                               properties:
                                               CBCharacteristicPropertyRead |
                                               CBCharacteristicPropertyWrite |
                                               CBCharacteristicPropertyNotify
                                               value:nil
                                               permissions:CBAttributePermissionsReadable |
                                               CBAttributePermissionsWriteable
                                               ];
    
    // 特征添加进服务
    
    [JKBlueToothModule service:service addCharacteristic:characteristic];
    self.defaultCharacteristic = characteristic;
    self.defaultService = service;
    [self.services addObject:self.defaultService];
}

- (void)startAdvertising{
    
    [self.peripheralManager startAdvertising:self.adContent];
}

- (void)stopAdvertising{
    
    [self.peripheralManager stopAdvertising];
}

- (void)sendData:(NSData *)data toCenterManagers:(NSArray <CBCentral*>*)centerDevices forCharacteristic:(CBMutableCharacteristic *)characteristic{
    characteristic = characteristic?:self.defaultCharacteristic;
    if (!centerDevices || centerDevices.count == 0) {
        centerDevices = self.centrals;
    }
    [self.peripheralManager updateValue:data forCharacteristic:characteristic onSubscribedCentrals:centerDevices];
}

#pragma mark - - - - CBPeripheralManagerDelegate - - - -
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    if (@available(iOS 10.0, *)) {
        switch (peripheral.state) {
            case CBManagerStatePoweredOn://蓝牙打开
                {
                    for (CBMutableService *service in self.services) {
                        [self.peripheralManager addService:service];
                    }
                 [self startAdvertising];
                }
                break;
            case CBManagerStatePoweredOff://蓝牙关闭了
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(CBManagerStatePoweredOff, @"蓝牙已关闭,请打开蓝牙");
                }
            }
                break;
            case CBManagerStateUnsupported://不支持
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(CBManagerStatePoweredOff, @"蓝牙设备不支持!");
                }
            }
                break;
                
            default:
                break;
        }
        
    } else {
        // Fallback on earlier versions
        switch (peripheral.state) {
            case 5://蓝牙打开
            {
                for (CBMutableService *service in self.services) {
                    [self.peripheralManager addService:service];
                }
                [self startAdvertising];
            }
                break;
            case 4://蓝牙关闭了
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(4, @"蓝牙已关闭,请打开蓝牙");
                }
            }
                break;
            case 2://不支持
            {
                if (self.btStatusBlock) {
                    self.btStatusBlock(2, @"蓝牙设备不支持!");
                }
            }
                break;
                
            default:
                break;
        }
    }
}

-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{

}


- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
//    if (request.characteristic.properties & CBCharacteristicPropertyRead) {
//        NSData *data = request.characteristic.value;
//       // [request setValue:data];
//        //[self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
//    } else {
//        [self.peripheralManager respondToRequest:request withResult:CBATTErrorReadNotPermitted];
//    }
    
}

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests {
    CBATTRequest *request = requests.lastObject;
    if (request.characteristic.properties & CBCharacteristicPropertyWrite) {
        CBMutableCharacteristic *characteristic = (CBMutableCharacteristic *)request.characteristic;
        characteristic.value = request.value;
        if (self.receivedDataBlock) {
            self.receivedDataBlock(request.value,nil);
        }
        
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
    } else {
        if (self.receivedDataBlock) {
            NSError *error = [[NSError alloc] initWithDomain:@"JKBlueToothModule" code:CBATTErrorWriteNotPermitted userInfo:@{@"msg":@"CBATTErrorWriteNotPermitted error"}];
            self.receivedDataBlock(nil,error);
        }
        [self.peripheralManager respondToRequest:request withResult:CBATTErrorWriteNotPermitted];
    }
}

//订阅characteristics
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{
    //NSLog(@"订阅了 %@的数据",characteristic.UUID);
    [self.centrals addObject:central];
    
}

//取消订阅characteristics
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
    //NSLog(@"取消订阅 %@的数据",characteristic.UUID);
    [self.centrals removeObject:central];
    
}

#pragma mark - - - - lazyLoad - - - -
- (NSMutableArray *)services{
    if (!_services) {
        _services  = [NSMutableArray new];
    }
    return _services;
}

- (NSMutableArray *)centrals{
    if (!_centrals) {
        _centrals = [NSMutableArray new];
    }
    return _centrals;
}

@end

代码可以直接复制直接使用。由于我这边是私有库,就不开放给大家了。另外文件传输时,参考我之前写的一篇文章《iOS蓝牙开发之数据传输精华篇》
里面有讲到数据拼接的一个工具 ,pod集成如下:

pod 'JKTransferDataHelper'

这里写图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 11:07:57  更:2021-09-05 11:09:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:11:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码