ThumbFan Keyboard 1.0.1がリリースされました。
今回のアプリでの変更点を見ながら、iOSキーボードやiOS8開発の技術についてまとめておきたいと思います。
関係ないですが、最近カメラとレンズを新しくして、夕日が綺麗だったので写真撮ってみました。
- Keyboardアプリの設定保存
- アプリが起動しない要因
- アプリの高機能化とReactiveCocoa
- バックスペースキーやカーソルキーをホールドすると、連打される
- 特殊文字の入力
- キータッチの精度の向上
- これから
前提として、iOSキーボードアプリは、iOS8より使用可能になった、Extentionという技術を用いて作成可能です。日本語ドキュメント – Apple Developer こちらにも、日本語訳された、App Extensionsプログラミングガイドがあり、英語を読まずに多くの情報を得ることができます。Extension(キーボードやNotificationウィジェットなど)は大元のアプリとは別領域で動くもので、通常状態ではホストアプリケーションと情報を共有できません。
こちらのApp Extensionsプログラミングガイド内の図にあるように、ホストアプリケーションとキーボードエクステンションを情報共有をするためには、”Request Open Access(フルアクセス)”というチェックを設定画面から設定する必要があります。しかし、これを行うと、キーボードが入力した内容を保存して、サーバーに入力のログを送ることなどが技術的に可能になります。
当アプリは現状で単語記録機能などは入れていないため、ユーザーを不安にさせるフルアクセスを現在導入していません。しかし、当アプリは片手で操作できるキーボードで、左手モード、右手モードのように片側にキーボードのキーを寄せることができます。
他のアプリでは、この情報を保存するためには、フルアクセスを有効にする必要があるアプリもあります。その場合はアプリ本体(ホストアプリケーション)にデータを保存することができるのですが、前述のようにセキュリティの心配をユーザーにかけることになります。
Appエクステンションプログラミングガイドにも、NSUserDefaultsを使用してホストアプリケーションとエクステンションが通信する方法については書かれているのですが、エクステンション内だけで設定を保存する方法については見当たりません。
これをうまく行う方法を、Stackoverflowという、開発者用の質問サイトに質問してみたのですが、はっきりとした答えは得られませんでした。objective c – iOS 8 Keyboard read/write setting without requesting open access – Stack Overflow
最初から、いろいろ試してみて、ホストアプリケーションと通信しないでも、キーボードエクステンション内に保存してしまえばいいじゃないかと考えて、[NSUserDefaults standardDefaults]という通常のアプリ内のデータ保存の方法を試してみました。確かにデータは保存されているようなのですが、キーボードが起動しなかったり、作成中のキーボードを選択できなくなったりすることがあり、NSUserDefaultsは使用できないかもしれないと考えて、保存機能をオフにして最初のバージョンをリリースしました。
しかし、よくよく調査してみると、キーボードが起動しない不具合は必ずしもNSUserDefaultsの使用によって起きているわけではないということがわかってきました。そのため、1.0.1では、再度NSUserDefaultsを使用して、最後に使用したキーボードの方向を記録するようにしています。これで今の所、キーボードの方向を使用するアプリを超えて記録することができています。もちろん、Extention内の設定なので、ホストアプリケーションからは、現在の設定にアクセスすることはできません。
前の部分でのアプリが起動しない要因には幾つかあります。
メモリの使用
処理の効率や性能を改善する
App Extensionsに割り当てるメモリ量は、フォアグラウンドで動作するアプリケーションに比べ てかなり制限されます。iOSでもOS Xでも、ユーザがホストアプリケーションでの作業に戻ろうと すると、システムがExtensionを積極的に停止させることがあります。中でも特にメモリ量の制限 がきついExtensionがあります。たとえばウィジェットは、同時にいくつも開くことが多いので、 特にメモリ効率を意識しなければなりません。
一つの理由として、メモリ使用量によって起動しない場合がありました。ReactiveCocoaを使用して、画面項目を作りすぎた時に、この問題に直面しました。UILabelオブジェクトの作りすぎで、全くキーボードが起動しなくなりました。これはReactiveCocoaを使う部分と、delegateパターンでシンプルに記述する部分を使い分けて解決しました。
起動時間が遅いために起動しない
メモリの使用が落ち着いても、キーボードが起動しないことがあり、やはり、[NSUserDefaults standardDefaults]の使用によって起動しないのかなと心配していましたが、実際に正しく動いていることもあり、おかしいなとおもいました。キーボードが起動するときと起動しない時があるので、メモリ使用によるものではないと予想して、他に要因があるかを考えてみました。そこでおもいたったのが、NSUserDefaultsはplistファイルをアクセスするので、スピードが遅いということでした。それでキーボード起動時にアプリが遅くなる処理をしていないかを調査してみたところ、怪しいのは、NSLogでした。NSLogはかなり遅い処理で、細かい動きを後から確認できるように色々なところに入れていたため、(開発時のみですが)起動にかなりの時間がかかっていました。
それで、キーボードエキステンションではDebug時にもNSLogを吐かないようにすると、キーボードが出ないということがほぼなくなりました。確かにNSUserDefaultsは時間を取られるのですが、それだけでキーボードが起動しないほどは遅くないのではないかと思います。
ホストアプリケーションのアップデートでキーボードアプリが起動しない
もう一つこれはアプリの問題ではなくて、iOSの問題だと思うのですが、キーボードとして登録されていても、アップデートでパスが変わった直後や、開発用のプロファイルでインストールした後にAppStoreからインストールされた時などに、キーボードが起動できなくなることがあります。これはおそらくアプリ側では何もしようがなくて、設定アプリから対象のキーボードを一度削除して再インストールしたり、一度キーボードを使用したアプリをキルして再インストールすると問題が解決する場合が多いです。
こちらのキーボードアプリにはReactiveCocoaを使用しています。ReactiveCocoaを使用すると、VMにアプリのステータスを記録しておいて、そのステータスに反応してアプリを動かしたり、キータッチの反応に関してもシグナルが反応して、いらないタッチをフィルタリングしたりするコードが書けたので、変更点が色々なところに散在せずに、各機能を開発できたので、機能の追加などを容易に行うことができました。
英語ではあまり使いませんが、それ以外の文字には基本文字の変形形が沢山あります。iOSのキーボードでも変形型の文字は長押しすると、候補に現れます。
これと同じことを実現しましたが、分かりやすくするために、ホールドされたら他のキーを消して、変形型のキーが現れるようにしています。
iOSの場合、UIButtonをたくさん置いてキーボードを作るのが普通に感じますが、実際にはiOSのキーボードには、ボタン以上の機能が求められています。タッチを開始してミスタッチに気がついたら、指をスライドさせて希望のキーに指を移動させることも必要ですし、前述の特殊文字のように、タッチして長押ししたら特殊文字を出現させることも必要です。そしてタッチの確定はキーを押下した時ではなくて、指を離した時になります。これは実際の物理キーボードとは違った動きになりますが、タッチスクリーンの特性を考えると、正しい動きになります。
これらの動きに関しては、初期バージョンの1.0でも実装されていました。実際にはUIButtonは一つも配置されておらず、UILabelのみが沢山配置されていて、全体のViewにタッチが開始された時に、指の位置に一番近いキーを反応させて、タッチが終了した時にそれを実際にキーを送るという操作を入れています。
しかし、使ってみると、なにかミスタイプがあることに気がつきました。キーボードを使ってくださったユーザーからも報告がありました。
.@tomohisa 作者さんからリプがくるとは。便利なアプリありがとうございます。キーアップ時に入力してるんですね、これ。押した時に認識した文字が指を離す時に変わる事が多少あるようで、押し間違えてないけど意図してない文字が入力されるというのが個人的には多少あります。(続く
— ナラ (@nalabjp) 2014, 12月 31
この原因について考えてみたところ特に細かいタッチに関しては、タッチを開始した時の中心座標とタッチを終了した時の終了座標がずれることに気がつきました。次に打とうと考えているキーの方に無意識に指が動くこともありますし、指の先端の方に重心が入っていた場合、指の根元の方から指が浮いて離れて、最終的には指の先端の方でタッチが離れることもあります。
この状況に対処するため、指を離した時の座標ではなく、指を離し始める時の座標を記録するようにしました。そうすることによって、急いで動かした指の動きの前の、ユーザーとして押したと感じられた最後の動きを取得するようにしています。これも微調整が絡んでいるので、完全に誰もが納得するタッチにすることは難しいと思いますが、個人的にはこの処理によってタイポが半分以下になったと感じています。
先回の記事にも書きましたが、TODOリストとしては、
- Auto Complete(タイポの修正)
- Auto Suggestion(途中まで打った時に残りの単語を提案)
- キーボードのサイズ、位置の自由移動
などにとりかかれれば良いなと感じています。
日本語入力は単純にQwertyキーボードを移植するのも何か違うかなと思うので、片手でもっと簡単に操作できるUIがないか模索していければと思います。
いまは、英語を含むアルファベット言語のみのアプリですが、興味があったら有料ですが是非購入して使用していただければと思います。
ちなみにこのアプリの4日後にほぼ同じアイディアのアプリが外国の別の開発者からリリースされたのですが、キーボードの配置がおかしかったり、片手キーボードなのに、エンターキーや文字切り替えキーが逆サイドにあったりでUIが考慮されていなかったので、今の所、扇型英語キーボードでは一番使いやすいアプリと思います。個人的にも慣れるとiPhone 6 plusでもかなり気楽に片手で操作できるので(もちろん戻るボタンなど親指だけで完全に操作が簡単にできるわけではないですが)便利と思っています。有料アプリにしてはまだまだですが宣伝していない割にはダウンロードされているようで嬉しい次第です。