自定义 keyboard

文章目录
  1. 1. 自定义键盘API
  • 自定义键盘的开发关键
    1. 1. 为用户信任所做的设计
    2. 2. 提供切换到其他键盘的方法
  • 开始自定义键盘的开发
    1. 1. 使用Xcode自定义键盘模板
    2. 2. 为自定义键盘配置Info.plist文件
  • 原文:CustomKeyboard

    自定义键盘API

    开发自定义键盘的快速入门,如下图,它展示了键盘运行过程中一些重要的对象,以及它们在开发流程中的的位置:

    keyboard

    自定义键盘模板(在iOS“Application Extension”目标模板组)包含一个UIInputViewController的子类,它是你开发的键盘的主视图控制器。该模板包含

    键盘所必需的“下一个键盘”按钮的实现,它调用了UIInputViewController类的advanceToNextInputMode方法。如上图所示,可以在输入视图控制器的主视图(在其inputView属性)中添加子视图、控制器以及手势识别器等。对于其它类型的扩展应用,在目标上并不存在窗体,因此也就没有根视图控制器了。

    在模板的Info.plist文件中有预先配置好的键盘所需要的最基本的值。参见其中的NSExtensionAttributes字典关键字,配置一个键盘的关键字在《配置自定义键盘的Info.plist文件》中有介绍。

    默认,键盘不能访问网络,不能和它的app共享容器。如果要具备这种能力,必须要将Info.plist文件中RequestsOpenAccess的值置为YES。这需要扩展键盘的沙盒,在《设计用户信任》中有介绍相关内容。

    一个输入视图控制器遵从各种与文本输入对象内容交互的协议:

    • 响应触摸消息时如果要插入或删除文本,可以使用UIKeyInput协议的insertText:和deleteBackward方法。可以在视图控制器的textDocumentProxy属性中调用这些方法,该属性代表当前文本输入对象,它遵从UITextDocumentProxy协议。如下:
    1
    2
    3
    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
    • 在调用deleteBackward之前要先决定删除的字符数。可以通过textDocumentProxy的documentContextBeforeInput属性,来获得光标附近的文本上下文信息。如下:
    1
    NSString *precedingContext = self.textDocumentProxy.documentContextBeforeInput;
    • 为了控制光标所在位置的操作,比如支持向前删除文字,需要调用UITextDocumentProxy协议中的adjustTextPositionByCharacterOffset:方法。比如向前删除一个字符,代码如下:
    1
    2
    3
    4
    - (void) deleteForward {
    [self.textDocumentProxy adjustTextPositionByCharacterOffset: 1];
    [self.textDocumentProxy deleteBackward];
    }
    • 通过实现UITextInputDelegate协议中的方法,可以响应当前输入文本对象的一些变化,比如内容变化以及用户触发的光标位置的变化。

    为了展现与当前文本输入对象适配的键盘布局,需要参照该对象的UIKeyboardType属性,根据每种你的键盘所能支持的属性,变化布局内容。

    在自定义键盘中,有两种方式来支持多语言:

    • 为每个语言创建一个键盘,每个键盘都作为向容器app添加的独立的Target
    • 创建一个多语言键盘,动态切换当前语言。可以使用UIInputViewController类的primaryLanguage属性来动态切换语言。

    根据你要支持的语言数量以及你想提供的用户体验,你可以从上面选择最合适的方案。

    每种自定义键盘(需要RequestsOpenAccess)都可以通过UILexicon类访问自动纠错的词典。通过使用该类,并结合你自己的词典设计,可以在用户输入过程中为他提供输入建议和自动纠错。UILexicon对象包含来自如下源的单词:

    • 来自用户通讯录的人名和姓
    • 在 设置 > 通用 > 键盘 > 快捷方式(文本替换) 列表
    • 通用词典

    你可以使用自动布局来调整你的自定义键盘主视图的高度。默认情况下,自定义键盘会根据屏幕尺寸以及设备方向,和系统键盘的尺寸保持一致。自定义键盘的宽度通常与屏幕当前宽度一致。修改自定义键盘主视图的高度约束即可修改其高度。

    下面的代码展示如何定义和添加约束:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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];

    自定义键盘的开发关键

    自定义键盘开发有两个关键点:

    • 信任。 自定义键盘能访问用户输入的内容 ,因此在键盘和用户间建立信任非常关键。
    • “下一个键盘”键。 通过键盘界面必须能让用户能切换到下一个键盘。

    为用户信任所做的设计

    作为自定义键盘的开发者,你首先应当考虑的是如何建立和维护用户信任。你要理解隐私策略的最佳实践并知道如何实现它才能很好地践行。

    注意
    本节为你创建自定义键盘提供相关的开发手册,该手册要求尊重用户隐私。了解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权限中的义务。

    提供切换到其他键盘的方法

    系统键盘的小地球按键用于切换到其他键盘:
    The system keyboard’s Globe key

    你的自定义键盘必须提供类似的机制能切换到其他键盘。

    调用UIInputViewController类的advanceToNextInputMode方法可以切换到其他键盘。系统会选择下一个键盘,没有能获得键盘列表的API,也没有切换到指定键盘的API。

    Xcode自定义键盘模板中就已经在下一个键盘按钮上具备了advanceToNextInputMode的功能。为了提供最好的用户体验,应当把你的下一个键盘按键放在靠近系统键盘的小地球键的位置。

    注意
    要通过应用审核,必须在你的键盘上提供明显允许用户切换键盘的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. 确认Project和Embed in Application中都显示的是容器app的名字(CKIme),点击Finish。如果弹出Activate “CKbd” scheme提示让激活键盘工程,点击Activate。

    定义键盘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字符串:

    iOS UI字符串Info.plist关键字
    · 在系统设置的已购键盘列表中的键盘group name在容器app的Info.plist文件中的Bundle display name
    · 系统设置中的键盘名称
    · 键盘换列表中的键盘名称
    在键盘app的Info.plist文件中的Bundle display name

    运行自定义键盘并将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文件,按文本格式呈现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <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之前,一定要先阅读《用户信任设计》,这里描述了如何尊重和保护用户数据。