ExternalAccessory(外部设备相关的一个框架)

主要的类:

hehhe

  • EAAccessoryManager: 管理设备,可以获取当前连接的所有的设备

  • EAAccessory: 连接的硬件设备

  • EASession:主要用来建立通道,让App和连接的设备进行数据的传输(发送和接受)

连接设备的两种方法

  • 到系统蓝牙页面连接设备

  • 应用内弹出tableView警告窗显示可用的传统蓝牙设备,点击即可连接设备

 // 过滤器可过滤符合要求的设备
    [[EAAccessoryManager sharedAccessoryManager] showBluetoothAccessoryPickerWithNameFilter:[NSPredicate predicateWithFormat:@"self CONTAINS 'Cubinote'"] completion:^(NSError * _Nullable error) {
        NSLog(@"error = %@", error);
    }];
 // 不做过滤   
    [[EAAccessoryManager sharedAccessoryManager] showBluetoothAccessoryPickerWithNameFilter:nil completion:nil];

EAAccessoryManager(获取连接设备)

当有硬件断开或连接的时候,ExternalAccessory框架会发送EAAccessoryDidDisconnectNotification和EAAccessoryDidConnectNotification通知,但是需要我们自己注册通知

    [[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessoryDidConnect:) name:EAAccessoryDidConnectNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessoryDidDisconnect:) name:EAAccessoryDidDisconnectNotification object:nil]
- (void)accessoryDidConnect:(NSNotification *)notification {
    EAAccessory *conAccessory = [[notification userInfo] objectForKey:EAAccessoryKey]; // 用EAAccessoryKey来获取连接的设备
    }

- (void)accessoryDidDisconnect:(NSNotification *)notification {
    EAAccessory *disConAccessory = [[notification userInfo] objectForKey:EAAccessoryKey]; // 用EAAccessoryKey来获取断开的设备

    }

获取当前所连接的所有设备

    // 利用EAAccessoryManager的connectedAccessories属性获取
    NSArray *accessoryArray = [[EAAccessoryManager sharedAccessoryManager] connectedAccessories];

判断是否是自己的设备根据协议名来判断.在info.plist添加UISupportedExternalAccessoryProtocols,添加硬件提供的协议

创建EASession (打开输入、输出通道)

[[EASession alloc] initWithAccessory:accessory forProtocol:protocolString]; // 根据EAAccessory和协议名创建EASession

// 1.创造了可以进行发送和接受数据的EASesssion对象
- (BOOL)openSession {
    // 根据已经连接的EAAccessory对象和这个协议(反向域名字符串)来创建EASession对象,并打开输入、输出通道 
    EASession *session = [[EASession alloc] initWithAccessory:self.accessory forProtocol: kSPKLightingHeadphoneProtocolString];
    if(session != nil) {
        // open input stream
        session.inputStream.delegate = self;
        [session.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        [inputStream open];

        // open output stream
        session.outputStream.delegate = self;
        [session.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream open];
    }
    else {
        NSLog(@"Failed to create session");
    }

    return (nil != session);
}
// close the session with the accessory.
- (void)closeSession {
    [[_session inputStream] close];
    [[_session inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [[_session inputStream] setDelegate:nil];
    [[_session outputStream] close];
    [[_session outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [[_session outputStream] setDelegate:nil];

    _session = nil;

    _writeData = nil;
    _readData = nil;
}

// 2.进行发送、接受数据;因为遵守了NSStreamDelegate利用代理的回调监听输入流和输出流
// asynchronous NSStream handleEvent method
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
        case NSStreamEventNone:              // 没有事情发生
            break;
        case NSStreamEventOpenCompleted:    // 流被成功打开
            break;
        case NSStreamEventHasBytesAvailable:    // 有数据可以读取
            [self _readData];
            break;
        case NSStreamEventHasSpaceAvailable:    // 流可以接受写入数据
            [self _writeData];
            break;
        case NSStreamEventErrorOccurred:        // 在流上有错误发生
            break;
        case NSStreamEventEndEncountered:       // 到达了流的结束位置
            break;
        default:
            break;
}

发送接受数据

  • HasBytesAvailable:表示stream中有数据需要读取(硬件发送了数据给App)
  • HasSpaceAvailable:表示stream中可以接收数据的写入(App发送了数据给硬件)。其实主要判断stream的hasBytesAvailable属性为Yes就可以直接发送数据给硬件,没必要等到这个回调。
- (void)_writeData {
    while (([[_session outputStream] hasSpaceAvailable]) && ([_writeData length] > 0)) {
        NSInteger bytesWritten = [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]];
        if (bytesWritten == -1) {
            NSLog(@"write error");
            break;
        }
        else if (bytesWritten > 0) {
            [_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
            NSLog(@"bytesWritten %ld", (long)bytesWritten);

        }
    }
}

- (void)_readData {
#define EAD_INPUT_BUFFER_SIZE 128
    uint8_t buf[EAD_INPUT_BUFFER_SIZE];
    while ([[_session inputStream] hasBytesAvailable]) {
        NSInteger bytesRead = [[_session inputStream] read:buf maxLength:EAD_INPUT_BUFFER_SIZE];
        if (_readData == nil) {
            _readData = [[NSMutableData alloc] init];
        }
        [_readData appendBytes:(void *)buf length:bytesRead];
        NSString *stirng = [[NSString alloc] initWithData:_readData encoding:NSUTF8StringEncoding];
        NSLog(@"read %ld bytes from input stream", (long)bytesRead);
    }

}

results matching ""

    No results matching ""