ExternalAccessory串口通信
ExternalAccessory 使用文档
-
前言
公司希望通过串口通信的方式实现苹果手机与公司产品进行通信,通过Lighting接口,也就是苹果的数据线。苹果的API ExternalAccessory就是来解决这个问题的。
👇以下介绍一下ExternalAccessory的用法
简介
ExternalAccessory通过三个类来实现通信
- EAAccessory 代表外部设备,包含了外部设备的信息;
- EAAccessoryManager 外部设备的管理者;
- EASession 当与一个外部设备建立通信渠道后,整个会话由这个类操作;
为项目添加ExternalAccessory通信机制的步骤
1. 引入类库
引入framework ExternalAccessory.framework
在使用时添加 #import <ExternalAccessory/ExternalAccessory.h>
2. 在plist 文件中加入 UISupportedExternalAccessoryProtocols 字段,这是一个数组,将所有用到的协议字符串加入到这个数组中。这里的协议字符串是外设提前预制的,需要与硬件开发人员确认。苹果系统已经帮我们管理了已经连接的设备,这里添加协议名称的目的是告诉系统我的APP可以与包含这个协议的外设进行交互。
<key>UISupportedExternalAccessoryProtocols</key>
<array>
<string></string>
</array>
3. 获取已经与手机连接的全部外部设备,监听设备的链接以及断开的状态变化。
_accessoryList = [[NSMutableArray alloc] initWithArray:[[EAAccessoryManager sharedAccessoryManager] connectedAccessories]];//这个数组中包含的是 EAAccessory
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_accessoryDidConnect:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_accessoryDidDisconnect:) name:EAAccessoryDidDisconnectNotification object:nil];
//调用这个方法告诉系统,当设备链接状态发生改变时给APP发送通知。
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
4. 根据protocolString 筛选出EAAccessory 创建会话 EASession ,并且监听收到信息以及可以发送信息的回调。
- (EASession *)openSessionForProtocol:(NSString *)protocolString
{
NSArray *accessories = [[EAAccessoryManager sharedAccessoryManager]
connectedAccessories];
EASession *session = nil;
for (EAAccessory *obj in accessories)
{
if ([[obj protocolStrings] containsObject:protocolString])
{
_accessory = obj;
_accessory.delegate = self;
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];
}
}
return session;
}
#pragma mark - NSStream Delegate
- (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent
{
switch (streamEvent)
{
case NSStreamEventHasBytesAvailable:
{// Process the incoming stream data.
[self receiveData];
}
break;
case NSStreamEventHasSpaceAvailable:
{// Send the next queued command.
[self writeData];
}
break;
default:
break;
}
}
5. 接收配套设备的信息,以及向配套设备发送信息。
接收数据:
-(void)receiveData
{
NSInteger maxLength = 128;
uint8_t readBuffer [maxLength];
//是否已经到结尾标识
BOOL endOfStreamReached = NO;
// NOTE: this tight loop will block until stream ends
while (! endOfStreamReached)
{
NSInteger bytesRead = [_session.inputStream read: readBuffer maxLength:maxLength];
if (bytesRead == 0)
{//文件读取到最后
endOfStreamReached = YES;
}
else if (bytesRead == -1)
{//文件读取错误
endOfStreamReached = YES;
}
else
{
NSString *readBufferString =[[NSString alloc] initWithBytesNoCopy:readBuffer length:bytesRead encoding: NSUTF8StringEncoding freeWhenDone: NO];
NSLog(@"收到设备信息:%@",readBufferString);
TTSLOG(@"收到设备信息");
}
}
}
发送数据: 发送数据没有必要在状态回调后再发送,也可以通过判断hasSpaceAvailable的状态来决定是否能够发送。
-(void)writeData
{
BOOL isAvailable = _session.outputStream.hasSpaceAvailable;
if (isAvailable == YES) {
NSData *data = [[NSData alloc]initWithBase64EncodedString:@"出发了老铁" options:NSDataBase64DecodingIgnoreUnknownCharacters];
[_session.outputStream write:[data bytes] maxLength:data.length];
}
}