その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

【iOS8】App Extension の実装方法 その2:Custom Keyboard

その1:Action」から1ヵ月以上経ってしまいましたが、「その2」として Custom Keyboard の App Extension 実装手順について書きたいと思います。 *1



キーボードは改善し続けてきた iOS の中でもわりと進化が止まっていた/むしろ使いづらくなるアップデートもあった部分なので、自前でのキーボード実装を可能とする機能追加は期待していた人も多かったのではないでしょうか。

1. ターゲットを作成する

Xcode の [File] > [New] > [Target] から、[Application Extension] > [Custom Keyboard] を選択します。


(※NDAに配慮し、Xcode6のスクショではなく、公開情報である App Extension Programming Guide の図3-1 を貼ってあります。)

2 Extension の実装

自動生成されたコードについて

手順1でターゲットを追加すると、UIInputViewController のサブクラス "KeyboardViewController" が自動生成されます。


UIInputViewController のヘッダを見てみると、

@protocol UITextDocumentProxy <UIKeyInput>

@property (nonatomic, readonly) NSString *documentContextBeforeInput;
@property (nonatomic, readonly) NSString *documentContextAfterInput;

@end

NS_CLASS_AVAILABLE_IOS(8_0) @interface UIInputViewController : UIViewController <UITextInputDelegate>

@property (nonatomic, retain) UIInputView *inputView;

@property (nonatomic, readonly) NSObject <UITextDocumentProxy> *textDocumentProxy;

- (void)dismissKeyboard;
- (void)advanceToNextInputMode;

// This will not provide a complete repository of a language's vocabulary.
// It is solely intended to supplement existing lexicons.
- (void)requestSupplementaryLexiconWithCompletion:(void (^)(UILexicon *))completionHandler;

@end

こんな感じでカスタムキーボード用に拡張された UIViewController サブクラスとなっています。


参考:UIInputViewController Class Reference


で、生成されたコード(KeyboardViewController)の中身を見てみると、viewDidLoad で下記のような処理が行われています。

self.nextKeyboardButton = [UIButton buttonWithType:UIButtonTypeSystem];

[self.nextKeyboardButton setTitle:NSLocalizedString(@"Next Keyboard", @"Title for 'Next Keyboard' button") forState:UIControlStateNormal];
[self.nextKeyboardButton sizeToFit];
self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = NO;

[self.nextKeyboardButton addTarget:self action:@selector(advanceToNextInputMode) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:self.nextKeyboardButton];

NSLayoutConstraint *nextKeyboardButtonLeftSideConstraint = [NSLayoutConstraint constraintWithItem:self.nextKeyboardButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0];
NSLayoutConstraint *nextKeyboardButtonBottomConstraint = [NSLayoutConstraint constraintWithItem:self.nextKeyboardButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
[self.view addConstraints:@[nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint]];


パッと見長いですが、やってることは

  • UIButton オブジェクト生成
  • Auto Layout の制約追加

ざっくりこれだけです。


ポイントとしては、生成した UIButton にアクションとしてセットされている advanceToNextInputMode メソッドです。UIInputViewController のリファレンスに

Switches to the next keyboard in the list of user-enabled keyboards.

とある通り、キーボード切り替えのためのメソッドです。


つまり、この自動生成されたキーはキーボード切り替え用のキー、ということがわかります。

文字入力キーを追加する

独自の文字入力用のキーを追加してみます。

UIButton *customKeyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
[customKeyBtn setTitle:@"@shu223" forState:UIControlStateNormal];
[customKeyBtn sizeToFit];
[customKeyBtn addTarget:self
                 action:@selector(customKeyBtnTapped:)
       forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:customKeyBtn];


上記のように普通に UIButton オブジェクトを生成して、アクション用のメソッドを次のように実装します。

- (void)customKeyBtnTapped:(UIButton *)sender {
    
    [self.textDocumentProxy insertText:@"https://twitter.com/shu223"];
}

これで、キーの押下時(タップして離したとき)に、 UITextView なり UITextField なりの UIKeyInput プロトコルを実装したビューで、かつ First Responder なものに対して指定の文字列が挿入されるようになります。

カスタムキーボードを使用する

作成した App Extension のターゲットを内包するアプリ(Containing App)を実機 / シミュレータにインストールするとそのカスタムキーボードが使えるようになるわけですが、有効にするためにはエンドユーザー側で設定のひと手間が必要です。


NDAに配慮してスクショは控えますが、iOS の「設定」アプリから次の手順でカスタムキーボードを有効にします。

  1. [Settings] > [General] > [Keyboard] > [Keyboards]
  2. [Add New Keyboard] を選択
  3. リストの中に作成したカスタムキーボードがあるはずなので、タップして有効にする


これで、メールアプリなりメモ帳アプリなりを起動して、テキスト入力中にキーボード切り替えするとカスタムキーボードが出るようになります。

参考資料


*1:一応 Extension Point は 6種類全部試してみるつもりでいるので、ゆっくりながらも「その6」まで続く予定。