使用 Xamarin 開發 iOS 鍵盤擴展(含網路訪問)
- 2020 年 2 月 10 日
- 筆記
作為一位 .NET 技術的死忠,開發 iOS 應用當然要使用 Xamarin 啦!
本文用我的閱讀的文檔和實踐為素材,介紹如何使用 Xamarin 開發一個 iOS 的鍵盤擴展。
搭建環境
本文不會花篇幅來講如何搭建 Xamarin iOS 開發的環境,不然這篇文章就沒有重點。
於是,請閱讀這一篇來了解如何搭建 Xamarin iOS 的開發環境:
- 安裝調試工具:Mac 部分 Xamarin開發(Mac開發)環境搭建 – 簡書
- 安裝調試工具:Windows 部分 vs2017開發IOS(vs2017 xamarin 連接mac) – ManGo.XYZ – CSDN部落格
- 申請開發者帳號:https://developer.apple.com/register/,閱讀這裡了解坑
- 準備一根 Type-C 到 Lightning 的數據線,用於 Mac 從 Mac 部署到真機進行調試
你需要了解的 iOS 鍵盤擴展的背景知識
了解以下背景知識,有助於我們接下來開發的時候少踩一些坑。當然我不會在這裡說 iOS 應用開發的所有背景知識,只會說與 iOS 鍵盤擴展相關的部分。
- iOS 鍵盤擴展是 iOS 擴展的一種,而 iOS 擴展是 iOS 8.0 才開始引入的概念。
- iOS 擴展需要有一個 iOS 普通應用作為容器一起打包;所以,你需要創建兩個項目來完成 iOS 鍵盤擴展的開發。
- 在後文,我們將直接使用 iOS 容器應用來描述這個概念
- 擴展的包標識符(Bundle Identifier)必須以容器應用的包標識符字元串作為開頭
- iOS 擴展和 iOS 容器應用會被視為兩款完全不同的應用,互相之前不能共享任何數據。
- 如果真的要共享數據,就需要像其他兩款不同應用共享數據一樣的處理方式
- iOS 鍵盤擴展默認是不能訪問網路的,你需要聲明允許訪問網路,並獲得用戶的同意才行。
創建 iOS 鍵盤擴展項目
第一步:創建 Xamarin.Forms 項目。
這個不用太在意裡面的實現,因為它只是我們的「容器項目」(前面有介紹)。實際上在本文我們完全不會碰這個項目裡面的程式碼,只是為了配置我們的 iOS 應用包而已。未來你可以在這個容器應用裡面做鍵盤的個性化設置。

然後,選擇 iOS 平台。
我們只需要 iOS 端。因為對於鍵盤,不同系統的實現差異很大,之間共享的程式碼只能是非鍵盤部分的程式碼了。

第二步:創建 iOS 鍵盤擴展項目



當你創建完之後,你會看到三個不同的項目。
你可能發現 Walterlv.KeyboardExtension.Keyboard 項目有些奇怪,裡面有 Main 函數和 AppDelegate,按道理這是一個主程式包。然而實際測試中單獨有這個項目是跑不起來的(這可能是一個 Bug,如果修復了,請在下面評論或者郵件告知我,謝謝了)。
於是,Main 和 AppDelegate 這兩個文件是可以刪除的。如果你強迫症,就刪掉吧。當然不刪掉也不影響,不過我刪掉了。
第三步:引用 iOS 鍵盤擴展項目
在 iOS 容器應用上面添加鍵盤擴展項目作為引用。


如果你感興趣去查看 Walterlv.KeyboardExtension.iOS 項目中對 Walterlv.KeyboardExtension.Keyboard 項目的引用節點的話,你會發現 Xamarin 已經自動為這個項目標記上了 <IsAppExtension />
。只有加上了 AppExtension 標記,Xamarin 才會把這個項目作為 iOS 擴展項目進行打包。
<ProjectReference Include="....Walterlv.KeyboardExtension.KeyboardWalterlv.KeyboardExtension.Keyboard.csproj"> <Project>{d6f006e7-3c98-4b97-b2d5-4d2e3bc2f945}</Project> <Name>Walterlv.KeyboardExtension.Keyboard</Name> <IsAppExtension>true</IsAppExtension> <IsWatchApp>false</IsWatchApp> </ProjectReference>
在以上三個步驟完成之後,理論上你是可以正常編譯此項目的。

配置包資訊
iOS 應用的包資訊存儲在 plist 中。所以在這一節,你需要正確配置兩個項目的 plist。
沒錯!是兩個項目。還記得前面背景知識裡面我們說到容器項目和擴展項目就是兩個不同的應用嗎?
配置 plist 的方法,就是在 Visual Studio 裡面雙擊這個文件。
按照下圖這樣配置:

說明:
- Application Name 對應 plist 中的 CFBundleDisplayName 屬性,也就是應用的顯示名稱。
- 對於容器應用,就是 iOS 圖標下面的名稱,對於鍵盤,就是切換鍵盤的時候所用的名稱。
- 下圖中 iOS 應用圖標下面的名稱 CloudKeyboard 就是我在 Walterlv.CloudKeyboard 項目中的容器應用的名稱。
- 下圖中在 iOS 切換鍵盤時,Cloud 就是我在 Walterlv.CloudKeyboard 項目中的鍵盤名稱。
- 擴展項目的 Bundle Identifier 名稱必須以容器項目的 Bundle Identifier 名稱作為前綴。
- 如果不滿足要求,部署時擴展將不會生效。


至此,你的項目可以直接編譯了。如果你有真機部署環境,都可以直接部署到真機上看效果了。
真機部署調試
本文不會花篇幅來講如何真機部署調試,不然這篇文章就沒有重點。
但是你可以閱讀:使用 Xamarin 在 iOS 真機上部署應用進行調試
當然這是 Mac 版本的(畢竟我在 Windows 上實際也沒有成功真機調試過,我是 git 同步到 Mac 上用 Visual Studio for Mac 來真機調試的)。
只是你需要注意做這些內容:
- 你需要同意一份開發者證書(不然打不開應用):
- 設置 -> 通用 -> 設備管理 -> [自己的開發者帳號] -> 信任
- 還需要打開這個鍵盤(不然看不到鍵盤):
- 設置 -> 通用 -> 鍵盤 -> 添加新鍵盤… -> [選擇我們剛剛開發的鍵盤]
下面是我部署到真機上之後,在亮暗兩種不同的介面下的鍵盤截圖(就是上面的項目,沒有改任何程式碼):

處理鍵盤的文字輸入、退格和確定
我們把 Walterlv.CloudKeyboard.iOS.Extension 也就是那個鍵盤擴展項目刪除得只剩下 KeyboardViewController.cs 了,我們也只需要在這個類中寫程式碼而已。
要控制文字輸入,就是使用 TextDocumentProxy
實例。我們的 KeyboardViewController
繼承自 UIInputViewController
,於是我們能夠在類中直接使用 TextDocumentProxy
實例。
在游標處插入文字:
TextDocumentProxy.InsertText("walterlv");
如果要插入換行或者確認輸入,則使用:
TextDocumentProxy.InsertText("n");
在游標處刪除前一個字:
TextDocumentProxy.DeleteBackward();
如果想要清空文本,則可以循環刪除:
while (TextDocumentProxy.HasText) { TextDocumentProxy.DeleteBackward(); }
你沒有辦法刪除後一個字,也不能獲取到用戶輸入的任何內容。
關於換行,特別注意:如果文本框被設置為發送或者其他非換行的功能,那麼使用 InsertText
單獨插入換行時才能正常執行這些功能。如果調用此程式碼之前還有其他的插入文字,那麼最終就只會是換行,而不會執行其他的功能。實際上我在這一點上踩了坑,導致在 QQ 或者其他工具中只能實現換行,而無法發送消息。
iOS 的鍵盤有不同種類的確認,需要鍵盤針對 TextDocumentProxy.
我還沒有找到辦法直接完成文本的輸入,例如執行確認按鈕的邏輯。而確認按鈕有這麼些不同的情況:
// 我當然是寫 C# 語言版本的枚舉,而不是 Object-C 版本的啦。 public enum UIReturnKeyType : long { Default, Go, Google, Join, Next, Route, Search, Send, Yahoo, Done, EmergencyCall, Continue, }
添加鍵盤的網路訪問支援
允許完全訪問(包括網路)
純本地的鍵盤很難在打字速度上獲得優勢,各種主流的輸入法也通常藉助網路來提高自身的輸入準確度。
用戶需要在鍵盤設置裡面開啟鍵盤的「允許完全訪問」才能讓對應的輸入法獲得網路訪問的許可權。如果用戶沒有給許可權,那麼網路訪問的時候鍵盤擴展就會出現異常,然後閃退。

然而如果你去我們剛剛開發的輸入法中看,你會發現我們的輸入法沒有提供這樣的選項可以設置。那麼如何能夠添加這個設置以便進行網路訪問呢?
方法是修改鍵盤擴展項目的 Info.plist 文件。這個時候的修改,我們就不能使用 Visual Studio 中自帶的 plist 編輯器了,我們需要使用文本編輯器來編輯 plist 文件。
在你的 Info.plist 文件中找到 RequestsOpenAccess
屬性,然後將它分值從 false
改為 true
:
<key>RequestsOpenAccess</key> -- <false/> ++ <true/>
這個屬性設為 true
之後,再次部署,你將可以在你的鍵盤設置裡面看到「允許完全訪問」的設置項。開啟之後,你就能在你的鍵盤裡面訪問網路了。
允許訪問 http 不安全網路
一般來說你不用閱讀這一小節的內容。因為現在基本上各種服務都已經是 https 了,http 基本已經絕跡。但是如果你需要臨時部署一個服務,沒來得及申請 https 證書的話,那麼就需要使用本小結的內容讓你的鍵盤支援 http 的訪問。
繼續打開你的鍵盤擴展項目的 Info.plist 文件,在根字典的最後添加一個完整的字典屬性 NSAppTransportSecurity
:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSExceptionDomains</key> <dict> <key>walterlv.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
特別注意,裡面的 walterlv.com
需要換成你自己的域名。是域名,不用包含埠號。
這樣,你就能在鍵盤中訪問 http://walterlv.com 了。
本文總結
- 本文介紹了使用 Xamarin 開發 iOS 鍵盤插件的背景知識。
- 必須了解這些知識才不會在一些不太重要的坑上耗費太長時間。
- 本文教大家如何開發 iOS 鍵盤插件,主要是項目組織以及寫程式碼。
- 至少,使用文本編寫出來的程式碼,能夠在不作任何修改的情況下部署到真機。(實際上我們只在 KeyboardViewController.cs 中加了寥寥幾行程式碼。)
- 本文不涉及到搭建開發環境,不涉及如何連接真機調試。
- 你可能需要配合這些部落格才能完成部署以及調試:
- Xamarin開發(Mac開發)環境搭建 – 簡書
- vs2017開發IOS(vs2017 xamarin 連接mac) – ManGo.XYZ – CSDN部落格
如果你還遇到了一些其他詭異的問題:
- 歡迎閱讀 使用 Xamarin 開發 iOS 應用中需要注意的若干個問題。
- 歡迎在評論區評論或者向我發郵件。
參考資料
[iOS 8 Custom Keyboard Tutorial: How to Create A Third-Party Keyboard Extension |
iPhone and iOS App UI Design Templates](http://www.appdesignvault.com/ios-8-custom-keyboard-extension/#a_aid=mdev) |
---|
- 如何使用Xamarin開發iOS輸入法 – 簡書
- ios – Make HTTP Request from Custom Keyboard App Extension – Stack Overflow
- ios – Transport security has blocked a cleartext HTTP – Stack Overflow
- iOS – 輸入框有值時才能點擊鍵盤上的returnkey(enablesReturnKeyA… – 簡書
- objective c – Handling Return key in iOS 8 keyboard extension – Stack Overflow
- objective c – Handling Return key in iOS 8 keyboard extension – Stack Overflow
- iphone – iOS keyboard with 「Go」 button instead of return – Stack Overflow
- Custom Keyboards – Extensions – iOS – Human Interface Guidelines – Apple Developer
- Creating a Custom Keyboard In IOS… – Swift India – Medium
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名 呂毅 (包含鏈接: https://blog.walterlv.com ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發布。如有任何疑問,請 與我聯繫 ([email protected]) 。