本文为官方文档:About External Accessories及相关文档、个人开发调试过程的汇总。
与附件设备通讯的App需设备支持的协议,这些协议由设备制造商维护,可是自定义或标准协议,标准协议可与其他设备通信,iOS不负责这些协议的维护。
为防止命名空间冲突,推荐使用反DNS形式命名协议,如com.apple.myProtocol
、com.dji.video
、com.dji.protocol
、com.dji.common
。
1、编程步骤
1.1、引入框架与头文件
外部附件框架(ExternalAccessory.framework)为App与附件设备通信提供了桥梁。因此,在Xcode项目中,需要为每个与附件设备通信相关的项目添加ExternalAccessory.framework。
下一步是引入头文件#import <ExternalAccessory/ExternalAccessory.h>
。
1.2、声明App支持的协议
不声明协议直接调用EA框架的类会崩溃。
使用UISupportedExternalAccessoryProtocols
键在Info.plist中声明支持的协议,值为数组,数组的元素为支持的协议,元素的顺序任意且不限数量。这些值只用于判断App与附件设备的通信能力。当App与设备通信时,具体通信协议由我们编程决定。
当附件设备插入iOS设备时,系统才知道App可被新插入的设备启动。若当前已安装的App都没注册协议,则系统可能到App Store去搜索支持新设备声明的协议的App。
UISupportedExternalAccessoryProtocols
对应的值虽说可参考UISupportedExternalAccessoryProtocols,实际此链接并没给出有帮助的信息,《MFi Accessory Interface Specification for Apple Devices》也没给出所谓标准协议的字符串值。
1.3、开始通信
-
创建
EASession
。此对象管理与附件设备交互的情况,它与底层系统工作,在设备上来回传输数据。一旦会话建立,数据通过NSInputStream
和NSOutputStream
的实例在App中传输。收发的数据包的格式由与附件设备通信的协议决定。 -
接收数据。使用自定义委托对象,监视
NSInputStream
实例可从附件设备接收数据。 -
发送数据。向
NSOutputStream
写入数据包即可发送至附件设备。
1.4、一个读取外接设备的示例
1、Info.plist中加入Supported external accessory protocols
,值为com.apple.p1
。这个只是令系统认为我们的应用有能力与外接设备沟通,这里使用Lightning USB Camera Adapter测试。
2、读取外接设备信息代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableString *info = [[NSMutableString alloc] initWithCapacity:1024];
EAAccessoryManager *manager = [EAAccessoryManager sharedAccessoryManager];
NSArray<EAAccessory *> *accessArr = [manager connectedAccessories];
for (EAAccessory *access in accessArr) {
for (NSString *proStr in access.protocolStrings) {
[info appendFormat:@"protocolString = %@\n", proStr];
}
[info appendFormat:@"\n"];
[info appendFormat:@"manufacturer = %@\n", access.manufacturer];
[info appendFormat:@"name = %@\n", access.name];
[info appendFormat:@"modelNumber = %@\n", access.modelNumber];
[info appendFormat:@"serialNumber = %@\n", access.serialNumber];
[info appendFormat:@"firmwareRevision = %@\n", access.firmwareRevision];
[info appendFormat:@"hardwareRevision = %@\n", access.hardwareRevision];
[info appendFormat:@"dockType = %@\n", access.dockType];
}
dispatch_async(dispatch_get_main_queue(), ^{
label.text = info;
});
});
运行结果为:
manufacturer = Apple
name = Apple USB Camera Adapter
modelNumber = A1440
serialNumber =
firmwareRevision = 1.0.0
hardwareRevision = 1.0.0
dockType = (null)
1.5、与外接设备交互数据的示例
如下代码展示与DXO One相机通信。
1、在非UI线程中打开设备,否则可能导致程序崩溃。
EAAccessoryManager *manager = [EAAccessoryManager sharedAccessoryManager];
NSArray<EAAccessory *> *accessArr = [manager connectedAccessories];
if (accessArr.first) {
EASession *session = [[EASession alloc] initWithAccessory:accessArr.firstObject forProtocol:@"com.dxo.one.protocol"];
if (!session) return;
NSInputStream *inputStream = [session inputStream];
if (!inputStream) {
// LOG inputStream = null
}
inputStream.delegate = self;
[inputStream open];
}
2、实现NSStreamDelegate
协议
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
// LOG stream & event code
switch (eventCode) {
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
// 开始读取
break;
case NSStreamEventHasBytesAvailable:
// 获取可读数据大小,读取流才有效。
break;
case NSStreamEventHasSpaceAvailable:
// 获取可写空间大小,写入流才有效。
break;
case NSStreamEventErrorOccurred:
// 出错处理
break;
case NSStreamEventEndEncountered:
// 读取结束
break;
}
}
2、ExternalAccessory框架
1、EAAccessory
提供一个已连接的设备的信息,如制造商,固件版本等。
2、EAAccessoryManager
协调MFi设备与iOS设备之间的工作。
3、EASession
用来创建App与附件设备之间的通信通道。
4、EAWiFiUnconfiguredAccessory
提供未配置的MFI Wireless Accessory Configuration设备的信息给App。
5、EAWiFiUnconfiguredAccessoryBrowser
让App访问MFi Wireless Accessory Configuration进程。
3、开发技巧
Lightning接了设备则不能连接计算机,所以直观的做法是,将日志用UITextView显示出来。写成日志就得每次都拔掉设备,插上电脑,如此反复。
另一个办法是,通过蓝牙测试传输协议,手机连接电脑,可单步调试。验证完再用Lightning连接设备联调。
网友评论
然后用您的代码跑了一下
发现获取不到连接的设备...
这个会是什么原因呢?
想进群的可以加本人微信:luoxub ,备注:MFi, 邀请进群。
另外,MFi的资料很少,楼主有什么好的参考资料么?