投稿日:

【Swift】 コンテナアプリ内で自作キーボードExtensionをインストールなしで表示させる方法

ios swift アプリ内 カスタムキーボード エクステンション 表示 インストール 方法 inputView




キーボードエクステンションの情報はネット上にそれなりに出回るようになりましたが、コンテナアプリ(以下親アプリ)内でユーザーの追加の有無に関係なく表示できるようにする情報が見当たらなかったのでここでご紹介します。





style="display:inline-block;width:336px;height:280px"
data-ad-client="ca-pub-3481943934845626"
data-ad-slot="8806407289">






最初に試したこと



親アプリ内でインストールなしで表示できる、と明確に書いている文章は僕が探した限りでは海外のこちらの記事の”Make the containing app (somewhat) useful”という項目のものが唯一でした。

A mini-editor using the keyboard so that users can try the keyboard before installing it. This can be fairly easily implemented by attaching a UIInputView and your keyboard’s UIInputViewController to a UITextView. See the Text Programming Guide for iOS for more information.



またこちらの海外の記事によると、カスタムキーボードを表示させるにはtextView.inputViewにカスタムキーボードのビューを代入し、textView.reloadInputViews()を呼べばOKとのこと。


そこでまず試したのが以下。

let keyboardController = KeyboardViewController()
myTextView.inputView = keyboardController.view
myTextView.reloadInputViews()
(※自分のカスタムキーボードは.viewを使用)

しかしこれでは表示されず。
普通のUIViewであればtextView.inputViewへの代入で表示されると思いますが、キーボードエクステンションはそうはいきません。

前述の文章をよく読んでみると「by attaching a UIInputView and your keyboard’s UIInputViewController to a UITextView.」と書いてあり、どうやらUITextViewのinputViewControllerとKeyboardViewControllerを繋げないといけないようです。


しかし残念ながらSwiftではUITextViewのinputViewControllerをオーバーライドできないので、この部分だけObjective-Cファイルを使う必要があります。


Objective-CでUITextViewの拡張クラス作成



ヘッダーファイルはinterface記述のみでOK。

//// UITextView+TextInputMode.h

@interface UITextView (TextInputMode)
@end


実装ファイルでinputViewControllerをオーバーライド。
そのままではSwiftファイルであるKeyboardViewControllerを初期化できないので、KeyboardMediatorなる仲介クラス(Swiftファイル)を作って利用しています。

#import "UITextView+TextInputMode.h"
#import "AppName-Swift.h"

@implementation UITextView (TextInputMode)

- (UIInputViewController *) inputViewController {
//// Swiftファイル群との仲介クラス
   KeyboardMediator *mediator = [KeyboardMediator new];

//// カスタムキーボードのコントローラ取得
UIInputViewController *keyboardViewController = [mediator getKeyboardController];

//// サイズセット。originはたぶん反映されない。
       keyboardViewController.view.frame = CGRectMake(0, [mediator getTopMargin], [mediator getScreenWidth], [mediator getCoardHeight]);
//// inputViewへ代入しなくてもたぶん動作する
       self.inputView = keyboardViewController.view;
       NSLog(@"カスタムキーボードをセットします。\n");
       return keyboardViewController;
}
@end
仲介のKeyboardMediatorクラスではKeyboardViewControllerの初期化やframeサイズ、その他必要なデータを返すメソッドを記述しています。

そして最後にreturn keyboardViewControllerをすれば無事にカスタムキーボードが表示されると思います。

ただし上記のコードは説明用にシンプルにしたもので、動作検証していないので各自で確認お願いします(怠け者ですみません笑)

僕の環境ではself.inputView = keyboardViewController.viewをしなくてもカスタムキーボードはちゃんと表示・動作しました。
しかしこの場合はキーボードの位置(origin)調整ができなくなるようです。

これは位置調整のときはtextView.inputView.superviewのframeなどをいじる必要があるんですが、inputViewがnilになってしまうためです。

システムキーボードに戻したい場合はreturn [super inputViewController];を記述すればOKです。


その他の細かい挙動など



僕もまだ取り組み始めたばかりなので細かい動作は把握しきれてなく、どのタイミングでinputView = nilをすればいいのかなどがわかっていません。

アプリがバックグラウンドから復帰したときなどはカスタムキーボードの挙動がおかしくなることが多いですね。
これはキーボードエクステンションとしての動作をしっかり安定させた上での話なので、やはり親アプリ側でのリソースの管理に問題がありそうです。

ほかに発見したのは、NSNotificationの"applicationWillEnterBackground"通知タイミングでカスタムキーボードを解放させるようにしていると、外付けのcommand + tabでアプリスイッチャーを表示させたタイミングで強制的に別アプリへ飛んでしまうことです。

ユーザーとしてはけっこう煩わしいので気をつけた方が良さそうです。

もう1つは、外付けのファンクションキーにある「ソフトウェアキーボード表示キー」でシステムキーボードの表示をONにしてしまうと、
return [super inputViewController];を実行してもシステムキーボードへ切り替わらなくなるので注意です。
(この場合はファンクションキーでシステムキーボードを隠す)



カスタムキーボードのグローブボタンを押すと、カスタムキーボードはそのままで、押すたびに入力言語だけが変わっていきます。

今のところ分かっているのはこんなところです。
ではでは。


Sponsored Link





Comment