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];
}
}
