1. 程式人生 > 實用技巧 >iOS下的自定義鍵盤

iOS下的自定義鍵盤

https://www.jianshu.com/p/0713849954de

(本文來自《Custom Keyboard》
自定義鍵盤為那些希望體驗更新穎的輸入法或者需要用到iOS不支援的語言的使用者,提供了替代系統鍵盤的備選。自定義鍵盤的核心功能很簡單:響應按鍵、手勢或其它輸入事件,並提供轉換後的文字字串,並將該字串插入到當前的游標位置。

開始閱讀前
請先確認你需要開發的的確是系統範圍的自定義鍵盤。如果只是希望在你的app內部提供可自定義的鍵盤,可以到《Custom Views for Data Input 》《Text Programming Guide for iOS》瞭解自定義輸入檢視輸入輔助檢視

的相關內容,iOS SDK為此提供了更好的備選方案。

當用戶選擇了自定義鍵盤,該鍵盤即成為每個app的鍵盤。因此,你建立的鍵盤必須包含一些基本的功能。其中最重要的是,必須允許使用者切換到其它鍵盤。

理解使用者對鍵盤的預期

要理解使用者對於自定義鍵盤的預期,可以系統鍵盤為標杆——它反應靈敏且高效。它不會用垃圾資訊或請求打斷使用者輸入。如果你提供了需要使用者互動的功能,應該把它們放到鍵盤的app裡,而不是鍵盤上。

iOS使用者預期的鍵盤功能

每個自定義鍵盤都必須提供的iOS使用者所預期的鍵盤功能是:切換到其它鍵盤的方法。在系統鍵盤中,有一個小地球的按鍵用來完成此功能。iOS 8也提供了專門的API用於切換到下一個鍵盤,可以參見

《提供一種切換到其它鍵盤的方法》

系統鍵盤會根據當前文字輸入物件的UIKeyboardType屬性,展現與之匹配的鍵盤佈局。如果當前的輸入物件需要輸入郵箱,系統鍵盤的句號建就會變化:長按會冒出一些頂級域名的字尾作為候選。你在設計自己的鍵盤佈局時也應當考慮到當前的輸入物件屬性。

iOS使用者還期望自動大寫:在一個標準的文字輸入區域,對於大小寫敏感的語言來說,應當讓句首的字母自動大寫。

這類功能列出如下:

  • 對輸入物件的屬性考慮適當的鍵盤佈局
  • 自動糾錯和建議
  • 自動大寫
  • 兩個空格後自動新增句號
  • Caps lock鍵的支援
  • 鍵帽上的美觀
  • 對於象形文字的多層轉換

你可以自行決定是否實現這些功能;系統並沒有為這些功能提供專用的API,在自己的輸入法中提供這些功能可以讓你的產品更有競爭力。

系統鍵盤中的哪些功能不適用於自定義鍵盤

自定義鍵盤不能訪問在系統設定中的通用鍵盤設定資料(設定 > 通用 > 鍵盤),比如自動大寫、使Caps Lock可用。自定義鍵盤也不能訪問字典還原資訊(設定 > 通用 > 還原 > 還原鍵盤詞典)。要滿足你使用者的靈活性要求,你應該建立一個標準的設定bundle,這個話題在《偏好和設定程式設計指南》《實現iOS設定Bundle》中有討論。這樣你的自定義鍵盤的設定就會出現在系統設定的鍵盤區域。

還有一些文字輸入物件,自定義鍵盤是不能在其上進行輸入的。首先就是任何安全相關的文字輸入物件。這類文字輸入物件設定了其secureTextEntry屬性為YES,在其上的輸入內容將呈現為圓點。

當用戶在密碼框裡輸入時,系統會臨時用系統鍵盤來替代自定義鍵盤。當用戶在非密碼框裡輸入時,自定義鍵盤又會恢復回來。

自定義鍵盤也無權在撥號輸入的位置出現,例如通訊錄的電話號碼輸入區域。對於這類輸入物件,鍵盤是由運營商指定的一個數字/字母的小集合組成,並且具備如下屬性:
UIKeyboardTypePhonePad
UIKeyboardTypeNamePhonePad

當用戶點選撥號輸入物件時,系統將臨時用系統鍵盤替換掉你的自定義鍵盤。當用戶再點選其它標準輸入物件時,自定義鍵盤又會恢復回來。

app的開發者可以選擇在app內部不使用自定義鍵盤。例如銀行類app,或者必須遵守美國HIPAA隱私規則的app,可以這麼幹。這類app實現來自UIApplicationDelegate協議的application:shouldAllowExtensionPointIdentifier:方法,並返回NO,以達到使用系統鍵盤的效果。

由於自定義鍵盤只能繪製其UIInputViewController物件內的主檢視,在它上面不能選擇文字。選擇文字是使用鍵盤的應用程式控制的。如果app提供了編輯選單(如剪下、拷貝和貼上),鍵盤是無權訪問它的。自定義鍵盤不能提供在游標位置的自動inline糾錯能力。

在iOS8.0下,如所有擴充套件app一樣,自定義鍵盤不能訪問麥克風,因此不能實現語音輸入。

最後,顯示插圖不能超過鍵盤的主檢視上邊緣,系統鍵盤可以,但自定義鍵盤不行。如下圖,可以發現自定義鍵盤和系統輸入法的差別: 按鍵插圖不能超越上邊緣

自定義鍵盤API

本節將給出開發自定義鍵盤的快速入門。如下圖,它展示了鍵盤執行過程中一些重要的物件,以及它們在開發流程中的的位置:


自定義鍵盤的基本結構

自定義鍵盤模板(在iOS“Application Extension”目標模板組)包含一個UIInputViewController的子類,它是你開發的鍵盤的主檢視控制器。該模板包含鍵盤所必需的“下一個鍵盤”按鈕的實現,它呼叫了UIInputViewController類的advanceToNextInputMode方法。如上圖所示,可以在輸入檢視控制器的主檢視(在其inputView屬性)中新增子檢視、控制器以及手勢識別器等。對於其它型別的擴充套件應用,在目標上並不存在窗體,因此也就沒有根檢視控制器了。

在模板的Info.plist檔案中有預先配置好的鍵盤所需要的最基本的值。參見其中的NSExtensionAttributes字典關鍵字,配置一個鍵盤的關鍵字在《配置自定義鍵盤的Info.plist檔案》中有介紹。

預設,鍵盤不能訪問網路,不能和它的app共享容器。如果要具備這種能力,必須要將Info.plist檔案中RequestsOpenAccess的值置為YES。這需要擴充套件鍵盤的沙盒,在《設計使用者信任》中有介紹相關內容。

一個輸入檢視控制器遵從各種與文字輸入物件內容互動的協議:

[self.textDocumentProxy insertText:@"hello "]; // Inserts the string "hello " at the insertion point
[self.textDocumentProxy deleteBackward];       // Deletes the character to the left of the insertion point
[self.textDocumentProxy insertText:@"\n"];     // In a text view, inserts a newline character at the insertion point
NSString *precedingContext = self.textDocumentProxy.documentContextBeforeInput;
然後就可以刪除你指定的文字區域了,比如單個字元還是空格後的所有字元。如果要按照語義執行刪除,比如一個單詞、句子、還是一個段落,可以使用[《 CFStringTokenizer Reference》](https://developer.apple.com/reference/corefoundation/cfstringtokenizer-rf8)中描述的函式,注意每個語種的語義規則是不同的。
  • 為了控制游標所在位置的操作,比如支援向前刪除文字,需要呼叫UITextDocumentProxy協議中的adjustTextPositionByCharacterOffset:方法。比如向前刪除一個字元,程式碼如下:
- (void) deleteForward {
    [self.textDocumentProxy adjustTextPositionByCharacterOffset: 1];
    [self.textDocumentProxy deleteBackward];
}
  • 通過實現UITextInputDelegate協議中的方法,可以響應當前輸入文字物件的一些變化,比如內容變化以及使用者觸發的游標位置的變化。

為了展現與當前文字輸入物件適配的鍵盤佈局,需要參照該物件的UIKeyboardType屬性,根據每種你的鍵盤所能支援的屬性,變化佈局內容。

在自定義鍵盤中,有兩種方式來支援多語言:

  • 為每個語言建立一個鍵盤,每個鍵盤都作為向容器app新增的獨立的Target
  • 建立一個多語言鍵盤,動態切換當前語言。可以使用UIInputViewController類的primaryLanguage屬性來動態切換語言。

根據你要支援的語言數量以及你想提供的使用者體驗,你可以從上面選擇最合適的方案。

每種自定義鍵盤(需要RequestsOpenAccess)都可以通過UILexicon類訪問自動糾錯的詞典。通過使用該類,並結合你自己的詞典設計,可以在使用者輸入過程中為他提供輸入建議和自動糾錯。UILexicon物件包含來自如下源的單詞:

  • 來自使用者通訊錄的人名和姓
  • 在 設定 > 通用 > 鍵盤 > 快捷方式(文字替換) 列表
  • 通用詞典

你可以使用自動佈局來調整你的自定義鍵盤主檢視的高度。預設情況下,自定義鍵盤會根據螢幕尺寸以及裝置方向,和系統鍵盤的尺寸保持一致。自定義鍵盤的寬度通常與螢幕當前寬度一致。修改自定義鍵盤主檢視的高度約束即可修改其高度。

下面的程式碼展示如何定義和新增約束:

CGFloat _expandedHeight = 500;
NSLayoutConstraint *_heightConstraint = 
    [NSLayoutConstraint constraintWithItem: self.view 
                                 attribute: NSLayoutAttributeHeight 
                                 relatedBy: NSLayoutRelationEqual 
                                    toItem: nil 
                                 attribute: NSLayoutAttributeNotAnAttribute 
                                multiplier: 0.0 
                                  constant: _expandedHeight];
[self.view addConstraint: _heightConstraint];

注意
在 iOS8.8下,你可以在主檢視畫到螢幕之後的任何時間裡調整鍵盤高度。

自定義鍵盤的開發關鍵

自定義鍵盤開發有兩個關鍵點:

  • 信任。自定義鍵盤能訪問使用者輸入的內容 ,因此在鍵盤和使用者間建立信任非常關鍵。
  • “下一個鍵盤”鍵。通過鍵盤介面必須能讓使用者能切換到下一個鍵盤。

為使用者信任所做的設計

作為自定義鍵盤的開發者,你首先應當考慮的是如何建立和維護使用者信任。你要理解隱私策略的最佳實踐並知道如何實現它才能很好地踐行。

注意
本節為你建立自定義鍵盤提供相關的開發手冊,該手冊要求尊重使用者隱私。瞭解iOS程式設計要求,請閱讀應用商店稽核手冊iOS人機互動手冊iOS開發許可協議,請參見蘋果的《應用稽核支援》《支援使用者隱私》《iOS應用程式設計指南》

對於鍵盤,如下三個方面對於建立和維護使用者信任至關重要:
按鍵資料的安全。使用者希望他們的敲鍵會落在文件以及輸入區域內,而不是上傳到伺服器或者用於其他不明目的。
最小化合理利用其它使用者資料。如果你的鍵盤還需要使用其他使用者資料,例如定位服務或者通訊錄,你有義務解釋這給使用者帶來的好處是什麼。
準確。把輸入事件轉換成文字要求精準,這本身雖然不是一個隱私話題,但他會影響到信任:每次文字轉換需要體現出你的程式碼的精準。

在信任的開發設計過程中,首先考慮的是是否要獲取open access許可權。儘管開啟了open access許可權能給自定義鍵盤開發帶來極大便利,但這也增加了你作為開發者的責任。下面是標準的open access的能力和隱私考慮:

Open Access能力和限制隱私考慮
Off(default) ·鍵盤可以執行所有基本鍵盤的職責

·可以訪問通用詞典以支援自動糾錯和輸入建議
·訪問設定裡的快捷短語
·不與containing應用共享容器
·不訪問鍵盤容器以外的檔案系統
·不訪問鍵盤容器以外的檔案系統
·不能直接或間接訪問iCloud或遊戲中心或應用內購買 | 使用者瞭解按鍵僅僅被髮送到當前使用鍵盤的應用裡 |
| On | ·具備非聯網自定義鍵盤的所有能力
·在使用者許可情況下可以訪問位置服務和通訊錄
·鍵盤和containing app可以訪問共享容器
·鍵盤可以為伺服器側處理過程傳送按鍵或其他輸入事件
·containing app自動糾錯字典提供編輯介面
·通過containing app鍵盤可以使用iCloud來保證自動糾錯詞典和設定的更新
·通過containing app,鍵盤可以參與到遊戲中心和應用內購買
·如果鍵盤支援移動裝置管理(MDM),它可與被管理的應用共同工作 | ·使用者瞭解鍵盤開發者會利用按鍵資料
·你必須遵守有聯網能力的鍵盤開發手冊iOS開發許可協議,可參見《應用稽核支援》|

如果你的自定義鍵盤不需要open access許可權,系統確保敲鍵資訊不會被髮送給你的鍵盤以及別的地方。如果只想提供一般的鍵盤功能,請不要給鍵盤配備聯網能力。由於有沙盒限制,不聯網的鍵盤一定是滿足蘋果的資料隱私手冊並能獲得使用者信任的。

開啟open access許可權(如上所述,可以在Info.plist檔案中配置),能給你的開發帶來更多可能性,同時也帶來更多的責任。

注意
嚮應用商店提交一個open-access的鍵盤必須遵守蘋果《應用稽核支援》中的相關條款。

每一個與open access相關的功能都需要你履行相應的責任,應當最大限度地尊重使用者資料,不得用於與使用者輸入無關的其他任何目的。下表列出了open access帶來的好處以及開發者需承擔的責任:

能力使用者利益示例開發者責任
與containing app共享容器 為鍵盤的自動糾錯詞典管理UI介面 要考慮到自動糾錯資料屬於使用者隱私。不要把他發到你的伺服器,用作與輸入無關的用途。
把按鍵資料發到你的伺服器 通過開發者的計算資源可以提供更好的按鍵處理結果和輸入預測 只有為使用者提供更好的輸入體驗之用時,才能儲存按鍵和語音資料
基於雲的自動糾錯詞典 把人名、地名、熱點新聞加入到自動糾錯詞典中 不要把使用者身份與輸入資料關聯起來,不得將使用者資訊用作與輸入體驗無關的其他目的
通訊錄 把人名、地名、電話號碼新增到自動糾錯詞典中 不得講通訊錄用作與輸入體驗無關的其他目的
位置服務 將附近的地名新增到自動糾錯詞典中 不要在後臺使用位置服務,不得將位置資訊傳送到你的伺服器並用於與輸入體驗無關的其他目的

一個具有open-access許可權的鍵盤和其containing app能將按鍵資料傳送到伺服器端,通過這些資料可以為使用者提供更好的輸入體驗。如果你使用了這些能力,當不需要這些資料的時候,請及時在伺服器端刪除。參見上面的表格來履行你使用open-access許可權中的義務。

提供切換到其他鍵盤的方法

系統鍵盤的小地球按鍵用於切換到其他鍵盤,如下所示:


系統鍵盤的小地球鍵

你的自定義鍵盤必須提供類似的機制能切換到其他鍵盤。

注意
要通過應用稽核,必須在你的鍵盤上提供明顯允許使用者切換鍵盤的UI標識。

呼叫UIInputViewController類的advanceToNextInputMode方法可以切換到其他鍵盤。系統會選擇下一個鍵盤,沒有能獲得鍵盤列表的API,也沒有切換到指定鍵盤的API。

Xcode自定義鍵盤模板中就已經在下一個鍵盤按鈕上具備了advanceToNextInputMode的功能。為了提供最好的使用者體驗,應當把你的下一個鍵盤按鍵放在靠近系統鍵盤的小地球鍵的位置。

開始自定義鍵盤的開發

本節中你將學習到如何建立自定義鍵盤,根據你的目標配置並在iOS模擬器或物理機上把它執行起來。你還將學習到一些替代系統鍵盤應謹記的UI要點。

使用Xcode自定義鍵盤模板

建立鍵盤及其containing app與其他擴充套件應用略有不同。本節將帶你領略基本鍵盤的開發和執行。

在一個容器app中建立鍵盤,步驟如下:

  1. 在Xcode中選擇File > New > Project > iOS > Application選擇Single View Application模板。
  2. 點選Next
  3. 填寫Project Name(如CKIme),點選Next
  4. 選擇要儲存的位置,點選Create。這樣,你就有了一個空app,該app只能完成一個簡單的操作,接下來它將承載鍵盤。在你提交到應用商店之前,你需要完成一些有用的功能。請到應用稽核支援參考應用商店稽核指南
  5. 選擇File > New > Target > iOS > Application Extension選擇Custom Keyboard Extension,點選Next
  6. 填寫Product Name(如CKbd),點選Finish
  7. 確認ProjectEmbed in Application中都顯示的是容器app的名字(CKIme),點選Finish。如果彈出Activate “CKbd” scheme提示讓啟用鍵盤工程,點選Activate

接下來你可以根據需要決定是否要自定義鍵盤的group name,它會出現在設定中的已購買鍵盤列表中。

自定義鍵盤group name,步驟如下:

  1. 在Xcode工程導航檢視中,選擇容器app的Info.plist檔案,
  2. 在右側plist編輯器中,滑鼠hover到Bundle name上,點“+”按鈕建立一行空屬性。
  3. 在Key中填寫Bundle display name,回車
  4. 雙擊該行的Value,填寫你要自定義的鍵盤group name。
  5. 選擇File > Save儲存設定。

下表彙總了在容器app和鍵盤app的Info.plist檔案中你可以配置的UI字串:

iOSUI字串Info.plist關鍵字
· 在系統設定的已購鍵盤列表中的鍵盤group name 在容器app的Info.plist檔案中的Bundle display name
· 系統設定中的鍵盤名稱
· 鍵盤換列表中的鍵盤名稱 在鍵盤app的Info.plist檔案中的Bundle display name

現在你可以在iOS模擬器或真機上執行該鍵盤,看看它目前都具備什麼行為和能力吧。

執行自定義鍵盤並將Xcode偵錯程式attach到它上面

  1. 在Xcode,你的view controller實現中設定一個斷點(比如可以斷在viewDidLoad上)。
  2. 在Xcode工具欄確保當前活動的專案為鍵盤專案,並對應iOS模擬器或裝置。
  3. 選擇選單Project > Run,或點選Build and then run the current scheme按鈕(即播放按鈕)。Xcode會提示選擇host app。選擇一個帶有輸入框的,比如通訊錄或Safari。
  4. 點選Run
    Xcode將執行起你指定的host app。如果這是你第一次使用鍵盤擴充套件應用,需要現在設定中新增並啟用鍵盤:
    1. Settings > General > Keyboard > Keyboards
    2. 點選Add New Keyboard...
    3. OTHER IPHONE KEYBOARDS中點選你剛剛建立的鍵盤
  5. 在iOS模擬器或真機上,調出你的自定義鍵盤。
    點選任意可輸入區域,將顯示出系統鍵盤。按住小地球,選擇你的自定義鍵盤。
    此時你將看到自定義鍵盤,但是偵錯程式尚未attach上來。一個從模板構建而來的極簡鍵盤僅有一個Next Keyboard按鈕,點選後切換回前一個鍵盤。
  6. 取消你的鍵盤(以便在第8步中你可以再次調出鍵盤以命中viewDidLoad斷點)
  7. 在Xcode中,選擇Debug > Attach to Process > By Process Identifier(PID) or Name
    在彈出對話方塊中,輸入你的鍵盤擴充套件應用的名字(包含空格).預設就是該擴充套件應用在工程導航窗口裡的group name。
  8. 點選Attach
    Xcode將顯示出等待attach的偵錯程式。
  9. 在任意能輸入文字的app中調出鍵盤。
    當你的鍵盤主檢視開始載入時,Xcode偵錯程式將attache到你的鍵盤,並命中斷點。

為自定義鍵盤配置Info.plist檔案

自定義鍵盤的Info.plist檔案允許靜態定義鍵盤的現式特徵,包括主要語言,以及是否需要open access許可權。

開啟Xcode並切換到自定義鍵盤的target。在工程導航欄選擇Info.plist檔案,按文字格式呈現如下:

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>IsASCIICapable</key>
        <false/>
        <key>PrefersRightToLeft</key>
        <false/>
        <key>PrimaryLanguage</key>
        <string>en-US</string>
        <key>RequestsOpenAccess</key>
        <false/>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.keyboard-service</string>
    <key>NSExtensionPrincipalClass</key>
    <string>KeyboardViewController</string>
</dict>

每個關鍵字在App Extension Keys中都有解釋。可以使用字典NSExtensionAttributes中的關鍵字來描述你的自定義鍵盤的特徵和需求,如下:

IsASCIICapable- 預設為NO的布林值。使用者鍵盤是否可以向文件中插入ASCII字串。如果要為UIKeyboardTypeASCIICapable屬性的輸入物件展現單獨型別的鍵盤,需要將該值置為YES。

PrefersRightToLeft- 預設為NO的布林值。是否為從右到左的語種設計的的自定義鍵盤。

PrimaryLanguage- 預設為en-US的字串。以<語種>-<區域>的形式描述鍵盤的主語言。可以到http://www.opensource.apple.com/source/CF/CF-476.14/CFLocaleIdentifier.c找到對應的語種和區域。

RequestsOpenAccess- 預設為NO的布林值。是否需要比基礎鍵盤更大的沙盒範圍。把該值置為YES將需要完全訪問許可權,你的鍵盤將獲得如下能力,每個能力都伴隨有相應的許可權:

  • 訪問定位服務,通訊錄資料庫,相機,每個都需要使用者允許
  • 與鍵盤的容器app共享容器資料,以便完成比如在容器app中管理使用者詞庫的介面的功能
  • 通過網路傳送按鍵、輸入事件之類的資料供雲端處理
  • 使用UIPasteboard
  • 播放音訊,包括使用playInputClick方法播放按鍵音
  • 訪問iCloud,可以用來根據使用者身份同步比如鍵盤設定、自定義自動糾錯詞典
  • 通過容器app訪問遊戲中心和應用內購買
  • 如果你的鍵盤支援移動裝置管理(MDM),可以與被管理的app無縫合作

當考慮是否將這些關鍵字設定為YES之前,一定要先閱讀《使用者信任設計》,這裡描述瞭如何尊重和保護使用者資料。



作者:RickMao
連結:https://www.jianshu.com/p/0713849954de
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。