1. 程式人生 > >iOS App 連線外設的幾種方式

iOS App 連線外設的幾種方式

原創作者: Max_Marry

文章地址: http://www.jianshu.com/p/852bf92c5c92

隨著近年來車聯網和物聯網的興起,智慧家居和智慧硬體的逐步火熱,越來越多的 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 模式切換

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 <ExternalAccessory/ExternalAccessory.h>

1.2、宣告App支援的協議

不宣告協議直接呼叫EA框架的類會崩潰。
使用 UISupportedExternalAccessoryProtocols 鍵在 Info.plist 中宣告支援的協議,值為陣列,陣列的元素為支援的協議,元素的順序任意且不限數量。這些值只用於判斷 App 與附件裝置的通訊能力。當App與裝置通訊時,具體通訊協議由我們程式設計決定。

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

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

}

  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 連線外設方面的工作,因此蒐集查詢相關資訊,文章中資訊出自於以下簡友:我是雲峰小羅熊皮皮,在此對兩位的分享表示感謝。