iOS App 連接外設的幾種方式

隨著近年來車聯網和物聯網的興起,智能家居和智能硬體的逐步火熱,越來越多的 App 被用來跟硬體設備進行來連接,獲取硬體相關信息用以展示或者發送指令控制硬體來提供服務。

iOS App 連接外設的常用方式可以分為三大類:

網路埠

建立 Socket 使用 TCP/IP 協議族進行通信,天然支持多通道,想要幾個通道就建幾個 Socket 就可以。它主要有三種方式,

Wi-Fi 連接

優點:

  • 簡單,不需要集成 MFi 晶元

  • 只要對應的硬體有無線網卡,然後將手機和硬體連接到同一個區域網中就可以使用 Socket 通過網路協議通信

  • 缺點:

  • 無線連接信號容易受到干擾,不太穩定,容易斷開

  • 如果硬體使用的場合沒有公共 Wi-Fi,就需要手機自建熱點共享,硬體進行熱點接入,操作步驟較多,對用戶來說學習使用成本較高,並且熱點共享要求手機本身的數據移動網路是穩定的,在沒有移動數據網路信號的地方,熱點無法建立。

  • USB 熱點共享

    這個其實跟 Wi-Fi 中的熱點共享非常類似,也不需要集成 MFi 晶元。

    優點:

  • USB 熱點共享,走的是有線,不容易受到干擾,更穩定,

  • iPhone 可以邊使用可以邊充電

  • 缺點:

  • 操作步驟比較複雜,需要先打開個人熱點共享

  • NCM

    就是把 USB 埠虛擬成標準的網路埠,然後手機和外設就能通過有線網路直連了,可以理解成手機和外設通過一跟網線連起來了,然後就可以用 Socket 通過 TCP,UDP 進行通信了。

    優點:

  • 有線連接,非常穩定,帶寬足夠

  • 不依賴移動網路信號

  • 缺點:

  • 需要集成 MFi 晶元並進行 MFi 認證,有一定門檻

  • 除了 CarPlay,其他跟 iPhone 連接的外設都不能使用 NCM 的方式跟 iPhone 上的 App 進行連接和通信

  • EAP

    EAP 全拼是 External Accessory Protocol,即外部設備協議。這個是蘋果推薦使用的外設連接方式。需要外設集成 MFi 晶元進行 MFi 認證。手機端開發相對簡單,只要集成 iOS 系統提供的一個框架 ExternalAccessory.framework,並且在 info.plist 中配置好協議字元串 (Supported external accessory protocols),當 iOS 設備通過 USB 或者藍牙連接到對應硬體時,iOS 系統會把符合 MFi 認證要求的外設抽象成了一個流對象,App 通過指定的協議字元串來創建一個 EASession 類的實例來訪問到該流對象,就能通過 NSInputStream 和 NSOutputStream 跟硬體件進行通信了。

  • EASession 模式:它的帶寬相對較低,但是允許同時通過多個協議字元串創建多個會話,也就是說直接支持多通道

  • Native Transport 模式:它的帶寬足夠大,理論值是 100MB 以上,但是不支持多通道,如果業務層需要支持多數據通道的話需要 App 自己進行通道的復用與拆分,並且 Native Transport 需要 iPhone 工作在 USB Host 模式,硬體需要支持 USB 模式切換

  • 關於如何使用 EAP 跟外部設備進行通信,可以參考蘋果官方的 Demo (https://developer.apple.com/library/content/samplecode/EADemo/Introduction/Intro.html)進行入門和學習。

    BLE

    BLE 即低功耗藍牙,是 iOS7.0 以後才支持的連接方式。

  • 優點:不需要集成 MFi 晶元做認證,功耗低,手機端開發也相對簡單,集成 iOS 系統提供的 CoreBluetooth.framework 即可

  • 缺點:帶寬很低,一般適合於只需要傳輸少量數據的場景。比如各種智能硬體,像智能水杯,智能體重計,運動手環等,都是採用這種連接方式

  • 總結一下,圖中帶 MFi 字樣的表示該連接方式需要硬體集成 MFi 晶元,做 MFi 認證。關於蘋果的 MFi 認證,對 iOS 開發中來說其實是一個比較陌生並且繁瑣的 Topic,原因如下:

  • 網上鮮有資料,Google 基本上查不到。 因為 MFi 認證是由硬體生產商主導進行的,蘋果首先對硬體生產商的實力 (質量,信譽,生產規模) 有很苛刻的要求,滿足要求的才有進行 MFi 認證的資格。滿足 MFi 認證資格要求的硬體生產商,提交了 MFi 產品計劃後才能得到蘋果 MFi 開發的官方文檔,這個文檔是帶水印的,不允許外泄

  • MFi認證周期很長,過程也很複雜

  • 蘋果官方溝通渠道很窄,電話打不通,郵件回復不及時

  • 關於 MFi 申請的一些事情

    什麼是 MFi 認證?

    蘋果 MFi 認證,是蘋果公司(Apple Inc.)對其授權配件廠商生產的外置配件的一種標識使用許可,是 Apple 公司 「Made for iOS」 的英文縮寫。

    為什麼要做 MFi 認證?

  • 從蘋果角度來看,為了更好的鞏固蘋果的生態圈,只有集成了有MFi 晶元,才能跟 iPhone、iPod,iPad 進行連接通信。而只有經過了 MFi 認證的企業才能批量購買 MFi 晶元,並且都 MFi 晶元的供銷鏈條都有很嚴格的監督管理,所以這樣蘋果可以嚴格控制只有那些滿足蘋果規範和要求的外設才能加入到蘋果生態圈。

  • 從生產廠商來看,經過蘋果官方授權,配件產品能完美兼容蘋果智能設備。提交 MFi 認證過程中,硬體設備需要經過蘋果要求的ATS 自測以及蘋果的嚴格測試,產品質量更有保證。消費者也更加信任經過了 MFi 認證授權的配件;最後成功獲得 MFi 授權這也成為技術與質量實力的一種標誌,因為 MFi 認證通過率僅 2%,其中大部分企業因為申請資格不符合直接被拒絕。

  • 從 iOS 開發人員來看,MFi 認證是由硬體生產商主導進行申請的,是蘋果對外設配件的一種認證和授權。但是很多外設跟蘋果進行連接,並不只是跟 iOS 設備硬體或者 iOS 系統配合就可以完成對應的功能 (比如充電、CarPlay、播放 iPod 音樂 (A2DP)、接聽藍牙電話 (HPF) 或者提供 GPS 輸入源等)。很多時候為了實現特定的需求,需要由 iOS App 的配合,由 iOS App 跟對應外設進行連接和通信,傳輸相關的控制命令對外設進行控制,或者傳輸相關的外設數據進行展示。iOS App 跟外設的連接方式有網路、EAP 和 BLE,其中 EAP 是蘋果官方推薦的跟外設連接的方式。只有經過 MFi 認證的外設才能使用 EAP 跟 App 進行通信。

  • 如何做 MFi 認證?

    MFi 認證的流程比較複雜,可以歸納總結為三個部分,如下圖所示。

    其中黃色背景標註的部分是可能跟 iOS App 開發者相關的。

    一、申請人提交申請資料

    首先,收集公司資料信息,這些資料主要包括了認證負責人聯繫信息,企業情況介紹,公司組織架構、企業網站,物料品質控制以及 ISO 體系證書等資料。然後是在蘋果 MFi 官網(mfi.apple.com)上進行註冊,並提交第一步收集到的公司資料,進行賬號申請。

    接下來蘋果會進行 MFi 體系審核。這個是非常關鍵的一個步驟。 主要考察公司對 MFi 晶元的管理體系,看公司是否有規範的流程和系統來管理 MFi 晶元,能有效防止轉售晶元或者挪用晶元 (把晶元用到未通過 MFi 認知的項目上),蘋果會安排專人或者代理公司來抽查。

    如果 MFi 體系審核過了,蘋果還會對公司其他情況進行考察,來評估該公司是否滿足 MFi 會員的資格。審核的標準主要看公司相關資質,是否有較大的生產規模;是否擁有自主品牌;品牌在業內是否有較高的地位 (主要表現為各類榮譽);是否曾為其他國際知名企業供貨;研發人員是否達到蘋果要求的人數等,申請者一定保證申報資料的真實性,蘋果公司都會一一核實。

    如果這些條件都滿足,恭喜你公司成為了 MFi 會員,能夠有資格購買樣品晶元,並且拿到蘋果提供的 MFi 官方開發文檔,該文檔的每一頁都是帶有申請人姓名水印的,禁止對外公開,如果被發現,有可能會被取消 MFi 會員資格。據說大部分的企業都會被卡在會員資格審核這一步。

    二、提交產品計劃,研發和自測

    如果你的公司是屬於那幸運的那一小部分通過了 MFi 會員資格審核,拿到了蘋果的 MFi 研發官方文檔,也購買了 MFi 樣品晶元,那麼就可以提交產品計劃,進行產品研發和自測了。

    提交產品計劃是非常關鍵的一步,需要根據要研發的公司產品的形態、所用技術方案和需要支持的 iOS 設備、iOS 的相關信息都進行詳細的描述,其中比較重要信息有。

    (1) 附件概覽 (Accessory Overview)

    技術方案 (Technology) 如果你是做支持 CapPlay 的車機,那麼就選擇 CarPlay,否則都應該選擇 iAP;如果你的硬體需要跟 iPhone 連接,並且處理相關業務,而不僅僅是充電線或者數據線,那麼在 Components 里應該選擇 Authentication coprocessor。

    (2) 固件和硬體 (Firmware & Hardware)

    現在所有的 MFi 認證的硬體都需要支持 iAP2 協議,所以必須要選iAP2 或者同時支持 iAP2 和 iAP1。然後外設硬體跟蘋果設備是如何通信的,是使用 USB 的 Host 模式,還 USB 的 Devices 模式,還是串口或者藍牙,這個需要根據產品的需求、特性進行選擇。

    (3) 選擇硬體所支持的 iAP2 的特性

    (4) 選擇所支持的蘋果設備型號

    根據產品的設計選擇所需要支持的蘋果設備型號,包括 iPad,iPhone 和 iPod 的各種型號。

    (5) App 相關的信息

    這部分也是 iOS 開發者需要重點關注的部分,包括 App 的版本號,BundleID 和協議字元串以及 iOS App 的主要功能特性描述,這部分信息需要跟最後送 MFi 審核時附帶的 App 測試包的信息保持一致。提交了產品計劃之後,就可以拿到 PPID (Product Plan ID)。這個 PPID 也是跟 iOS App 開發者需要關注的。當 App 開發完成,提交 AppStore 上線時,需要在版本審核備註信息裡帶上這個 PPID,否則審核是過不了的。

    接下來就可以進行產品研發了。主要是硬體生成商需要根據蘋果提供的開發文檔進行硬體和驅動認證程序的開發。而 iOS App 開發者則主要是需要成 iOS 系統提供的一個系統框架 ExternalAccessory.framework,並且在 info.plist 中配置好協議字元串 (Supported external accessory protocols)。當 iOS 設備通過USB 線或者藍牙連接到對應硬體時,iOS 系統會把符合 MFi 認證要求的外設抽象成了一個流對象,App 通過指定的協議字元串來創建一個 EASession 類的實例來訪問到該流對象,就能通過NSInputStream 和 NSOutputStream 跟硬體件進行通信了。這部分功能實現可以參考蘋果官方的EADemo(https://developer.apple.com/library/content/samplecode/EADemo/Introduction/Intro.html)進行入門和學習。

    產品研發完成後需要進行 ATS (Accessory Test System) 自測,並提供自測報告。ATS 自測蘋果會提供 ATS Box 的測試工具和軟體,主要是針對硬體進行電氣特性相關的測試,包括各個節點的電壓電流值是否滿足蘋果要求,然後傳輸帶寬是否穩定,是否達到蘋果要求等等。

    自測完成之後就可以把硬體和所配套的軟體 (iOS App 的 ipa 安裝包) 送到蘋果指定的測試實驗室進行認證測試。iOS 開發者在這個步驟需要關注的是如何打包 ipa 包。因為如果直接用開發證書打包,那麼蘋果測試人員的 iPhone 不在你開發證書的設備列表中,是無法安裝的。如果用企業證書打包的話,可能 AppStore 發布證書對應的 BundleID 跟企業證書的 BundleID 不一致,所以也不可行。所以推薦的做法是,等到產品研發完成和自測之後,就帶上產品計劃中拿到的 PPID,提交 AppStore 進行審核。等審核通過之後,就可以直接從 AppStore 下載對應的 ipa 安裝包,配合硬體一起送 MFi 認證測試了。

    三、測試審核和批量生產

    這個階段也是硬體生產商主導進行的,跟 iOS App 開發者關係不大。當硬體的 MFi 認證送審通過之後,還需要對產品的包裝也提交認證和審核。審核通過之後,就可以獲得蘋果授權進行 MFi 晶元的批量購買,然後根據銷售計划進行硬體的批量生產和銷售了。

    整個 MFi 認證的周期大概需要3個月到半年的時間,並且每次提交認證測試都需要支付一筆600美金的測試費用,所寄去測試的硬體測試樣品蘋果也是不會寄回來的。

    iOS 外設連接黑科技,不需要 MFi 認證,實現 USB 連接

    USBMuxd,利用這種連接方式不需要做 MFi 認證,支持 iPhone 上的 App 跟外設通過進行通信,非常方便。

    基本原理iPhone 的 iOS 系統中自帶了 USBMuxd 服務,該服務能夠實現USB-TCP 協議的轉換,能夠把 USB 的埠映射到本機 (localhost) 的 TCP 端 (基於 Unix Domain Socket )。只需要在外設端也實現一個 USBMuxd 服務,並指定埠映射關係, 那iPhone 的 App 和外設上的應用就可以使用 Socket 進行 TCP 進行通信了。

    一個開源實例開源項目peertalk( https://github.com/rsms/peertalk) 就是一個完整的使用 USBMuxd 方式實現 iPhone App 跟 Mac App 進行 TCP 通信的例子。因為 Mac OS 系統中天生就自帶了 USBMuxd 服務,所以 peertalk 的 Mac 端程序是比較簡單的。外設一般都不會是 Mac 系統,而是 Android 或者 Linux 系統,那怎麼辦呢?那就自己在系統中集成 USBMuxd 服務,這裡可以利用到libimobiledevice( https://github.com/libimobiledevice)實現在外設上集成 USBMuxd 服務。

    MFi iOS App 端開發步驟

    與附件設備通訊的 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

    1.2、聲明App支持的協議

    不聲明協議直接調用EA框架的類會崩潰。使用 UISupportedExternalAccessoryProtocols 鍵在 Info.plist 中聲明支持的協議,值為數組,數組的元素為支持的協議,元素的順序任意且不限數量。這些值只用於判斷 App 與附件設備的通信能力。當App與設備通信時,具體通信協議由我們編程決定。

    當附件設備插入 iOS 設備時,系統才知道 App 可被新插入的設備啟動。若當前已安裝的 App 都沒註冊協議,則系統可能到 App Store 去搜索支持新設備聲明的協議的 App。

    UISupportedExternalAccessoryProtocols對應的值雖說可參考UISupportedExternalAccessoryProtocols( https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW4),實際此鏈接並沒給出有幫助的信息,《MFi Accessory Interface Specification for Apple Devices》也沒給出所謂標準協議的字元串值。

    1.3、開始通信

    1. 創建 EASession。此對象管理與附件設備交互的情況,它與底層系統工作,在設備上來回傳輸數據。一旦會話建立,數據通過NSInputStream 和 NSOutputStream 的實例在 App 中傳輸。收發的數據包的格式由與附件設備通信的協議決定。

    2. 接收數據。使用自定義委託對象,監視 NSInputStream 實例可從附件設備接收數據。

    3. 發送數據。向 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 *accessArr = [manager connectedAccessories];

    for (EAAccessory *access in accessArr) {

    for (NSString *proStr in access.protocolStrings) {

    [info appendFormat:@"protocolString = %@
    ", proStr];

    }

    [info appendFormat:@"
    "];

    [info appendFormat:@"manufacturer = %@
    ", access.manufacturer];

    [info appendFormat:@"name = %@
    ", access.name];

    [info appendFormat:@"modelNumber = %@
    ", access.modelNumber];

    [info appendFormat:@"serialNumber = %@
    ", access.serialNumber];

    [info appendFormat:@"firmwareRevision = %@
    ", access.firmwareRevision];

    [info appendFormat:@"hardwareRevision = %@
    ", access.hardwareRevision];

    [info appendFormat:@"dockType = %@
    ", 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 *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];

    }

    1. 實現 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 連接設備聯調。

    因本人目前在做關於 iOS App 連接外設方面的工作,因此搜集查找相關信息,文章中信息出自於以下簡友:我是雲峰小羅、熊皮皮,在此對兩位的分享表示感謝。


    推薦閱讀:

    VR外設:Steam手柄 PK Xbox One手柄 哪個好?
    球迷標配,羅技M238球迷典藏版無線滑鼠!
    買電腦外設想便宜量又足,這些技巧要知道!
    紅外機械開關+IP68級防水的機械鍵盤,我們來洗個澡吧

    TAG:方式 | 外設 | 連接 |