研究材料:
Accessory Interface Specification for Apple Devices.pdf
iPod+Authentication+Coprocessor+Spec+2.0C+R1
如果需要更详细的协议说明,可以下载MFI Accessory Firmware Specification PDF
(文档来自苹果授权方,如有侵权,请告知,本文不宜转载)
Accessory Interface Specification for Apple Devices.pdf
这个文档说明了苹果外设的认证过程、支持的认证模式、外设类型和通信协议,也可以通过查看MFI Accessory Firmware Specification文档了解更加详细的协议内容,比如iAP2的LINK建立过程如下图:
iPod+Authentication+Coprocessor+Spec+2.0C+R1.pdf
这个文档是苹果MFI认证芯片的datasheet,MFI芯片基于I2C通信接口,例如下图的I2C地址选择:
Accessory端如何做bluetooth的验证呢?
我们以一个场景来描述,比如MFI认证的蓝牙设备连接上支持iAP2的iOS设备之后,可以直接拉起一个APP程序到前台,那么我们该怎么做呢?
1、蓝牙设备的Service Discovery Protocal(SDP)必须要支持;
2、SDP的Maximum Transmission Unit(MTU)必须最少支持672bytes,这个可以看是否支持MTU协商;
3、不支持SDP消息记录分片;
4、Extended Inquiry Response(EIR)必须要被支持;
5、service UUID 0x00000000DECAFADEDECADEAFDECACAFE必须在SDP和EIR中被申明;
6、EIR设备名必须和Accessory设备的MFI认证时的IdentificationInformation的名字一致
以上是蓝牙部分需要满足的协议条件,然后接下来就是驱动认证芯片,并完成通过蓝牙通道做MFI认证,第一张图已经说明了验证的流程,如果想完成设备连接上后,直接打开某一个APP的功能,需要设备发送RequestAppLaunch消息到iOS设备上,通过Accessory Interface说明文档的26.3.1的RequestAppLaunch数据格式,我们知道需要携带一个参数AppBundleID,这个参数类型是utf8,e.g. com.kuili.applaunch,这里苹果推荐使用反DNS格式
(对于iAP2流程的link control session和seesion的开发过程这里忽略,官方例子)
支持MFI iAP2的手机端:
Info.plist中增加如下内容:
UISupportedExternalAccessoryProtocols
com.example.apple-samplecode.data
com.kuili.applaunch
注意Info.plist中的一个字符串正是accessory设备通过RequestAppLaunch发送过来的AppBundleID
程序中需要引用外部附件框架:
ExternalAccessory.framework
开始通信:
创建一个EASession,数据通过NSInputStream和NSOutputStream读写流数据。
读取设备信息:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableString *info = [[NSMutableString alloc] initWithCapacity:1024];
EAAccessoryManager *manager = [EAAccessoryManager sharedAccessoryManager];
NSArray *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;
});
});
EAAccessoryManager *manager = [EAAccessoryManager sharedAccessoryManager];
NSArray *accessArr = [manager connectedAccessories];
if (accessArr.first) {
EASession *session = [[EASession alloc] initWithAccessory:accessArr.firstObject forProtocol:@"com.kuili.applaunch"];
if (!session) return;
NSInputStream *inputStream = [session inputStream];
if (!inputStream) {
// LOG inputStream = null
}
inputStream.delegate = self;
[inputStream open];
}
以上iOS代码片段引用了以下博客链接:http://www.jianshu.com/p/8f69c9c4e71e