CodeIQ MAGAZINECodeIQ MAGAZINE

iOS 8で解禁されたカスタムキーボードを作ってみよう #iOS8 #DeNA

2014.07.10 Category:技術コラム Tag: , ,

  • 19
  • このエントリーをはてなブックマークに追加
dena2_

WWDC 2014で公開された新言語SwiftをはじめとするiOS 8の新機能の数々。

Appleから一般向けに公開された数多くの情報から、今回はiOS 8の新機能の一つであるApp Extension、特にカスタムキーボードに焦点を当て、DeNAのShintaro Kuronumaさんが解説レポートを寄稿してくれました。
by 馬場美由紀 (CodeIQ中の人)

WWDC 2014のあとの進捗どうですか?

WWDC 2014が終わって1カ月ほど経ちましたが、皆様いかがお過ごしでしょうか。何よりも開発者の皆様にとって衝撃的だったのはやはりSwiftの登場でしょうか。

モダンな言語に慣れ親しんだエンジニアの中には、Objective-Cの文法キモい・メソッド長いというあたりで、食わず嫌い的にiOS開発に踏み込み損ねていた方々もいらっしゃると少なからず見聞きしていましたが、新言語Swiftは大いにその障壁を下げ、新しいエンジニアたちの参入やそれによってもたらされる技術の流入を促しそうですね。

新言語登場のインパクトの大きさから、iOS 8自体の新機能については開発者の目線がそらされてしまった感がありますが、WWDC 2014ではもちろんHomeKitであるとかMetalであるとかいった新しいフレームワークも数々登場しています。また従来許されなかった拡張が可能になった部分もあります。

技術的に盛りだくさんになったことに配慮してか、今年はAppleから一般向けに多くの情報がすでに公開されています。全体感を押さえるだけでも大変といった感じですが、進捗いがかでしょうか?製品開発で使用予定のない機能などは勉強コストを割きづらいものですし、意識して普段触らないものを触ってみないとなかなか捗らないですね…。

今回は勉強も兼ねてiOS 8の新機能の一つであるApp Extension、特にカスタムキーボードに焦点を当ててみたいと思います。

尚、ご存じの通り、iOS Developer ProgramのNDAという縛りがありますので、

  • 本稿では Apple から一般向けに公開済みの情報のみに基づいて記述します(※注釈1)。尚、Pre-Releaseの情報に基づくものですから、iOS 8の正式リリースまでに仕様が変わりうることはご了承ください。
  • 実行結果のスクリーンショットなどは割愛させてください(テキスト説明だとわかりにくくて申し訳ないのですが)。
  • xibの図は Xcode5 上で撮影したもので代用とさせてください。
  • サンプルコードを提供しますので、実行結果は各自の開発環境でご確認ください。

※注釈1
ちなみに、丹念にググると本稿よりももっと立ち入った詳しい説明をしてくれているサイトも実はちらほら見つかるのですが、明らかに公開ドキュメントに書かれている以上の情報や、Xcode6での実行結果のスクリーンショットなどが含まれるため、泣く泣く紹介を差し控えさせていただきます…。英語圏はいろいろ情報が多いですが、日本語での紹介記事はあまり見つからなかったので、今回このテーマを選んでみました。

カスタムキーボード解禁によってもたらされること

iOS 8では新しいアプリ間連携機構「App Extension」が導入されました。この機能によって可能になることの一つとしてカスタムキーボードの提供があります。

カスタムキーボードという呼び名からすると、見た目がいじれるだけじゃないの、と思われる方もいらっしゃるかもしれませんが、そうではなく、

  1. 独自の配列・UI表現を持った入力インターフェース(広義のキーボード)を提供する
  2. 入力されたキーを取得して、何らかの加工を施した変換結果の文字列を、アプリのテキスト処理系に出力する
  3. 変換処理系はユーザーの許可を得た上でサーバーとの通信や住所情報・位置情報なども変換処理に織り込める

ということが可能になるということです。入力しやすい・見た目に使い心地がよいという部分は1.から、そして誤りのない正しい文章表現を効率よく得るという部分は2.からもたらされます。

さらには3.によってアプリ外のユーザー環境から得られる情報を活用した個性的な変換系の出現も見込めるというわけです。単なる入力UIにとどまらない、高度に特化した自然言語の処理系をサードパーティから提供できるようになるということになります。

日本語で長めの文章を書いたり、ネットスラングを多用した文章を書いたりされる方の中には、iOS標準の日本語変換が用途に合わず苦労していた方もいらっしゃることでしょう。iOS 8からはサードパーティ製のカスタムキーボードがきっと多数参入してくるでしょうから、iOS端末だけでもますます快適な生活が送れるようになる日もそう遠くないことかもしれないですね。

日本語以外でも変換を必要とする言語はもちろんありますから、自然言語を得意とするデベロッパーにとってはターゲット市場が一気に拡大し、大きなユーザーベースを獲得するチャンスでもあります。

ともあれ、1.も2.も3.も、いずれもカスタムキーボードデベロッパーの責任範囲になるので、実は本格的に作ろうとすると結構しんどい作業になると思われます。特に2. の部分はOSが全く肩代わりしてくれず、また実用性そのものに直結するコアコンピタンスとなる部分でもあるので、そう簡単に実装できるようなものではないでしょう。対象となる自然言語についての深い理解と技術が不可欠です。

また、3.についてもセキュリティ・ユーザー保護の観点から、例えユーザーから許可を得て取得しているデータとはいえ不正に流用したり悪用したりしては絶対にいけません。Appleのドキュメントにおいてもユーザーとの信頼関係を築くこと・信頼関係を裏切らないことが強調されています。

こうした信頼と実績の求められる機能であることも踏まえ、すでにデスクトップ市場や変換系入りiOSアプリで実績のある企業製品からの移植ソフトウェアキーボードが最有力であり、期待を集めていることでしょう。直近ではジャストシステムさんが対応に意欲とかMetaMoJiさんが対応を表明とか個人的にも楽しみなニュースも聞こえていましたね。

カスタムキーボードを作ってみる

自然言語の処理系として本格的なものを作ろうとすると難しいですよ、と書いてきましたが、仕組み自体は実はシンプルで、API仕様も整然と整備されています。今回は電卓変換キーボードを作ってみましょう。せっかくなので開発言語もSwiftにしてみます。

本文中で使用する図は、NDAに配慮し、Appleのドキュメント App Extension Programming Guideからの引用、またはXcode 5上で撮影したものとなります。一部本文の説明と合致しない表示になっていることがありますが、適当に読み替えていただければ幸いです。

まずカスタムキーボードの開発フローと実行の大枠は下図を見てください。

Containing App というのはカスタムキーボードExtensionを端末内部に持ち込むための入れ物です。アプリのバンドル内にExtensionバンドルが封入され、アプリのインストールによって端末内で大域的にExtensionが使用できるようになります。

カスタムキーボードを開発するには、このContaining Appを開発するプロジェクトに対してApp Extensionターゲットとしてカスタムキーボードのターゲットを追加し、実装をすることになります。このターゲットはプロジェクトテンプレートの中に含まれています:

Containing App の開発プロジェクトを適当に用意し、Xcode6のメニューから File > New > Target で上の図のシートダイアログが出てきますので Custom Keyboard のターゲットを追加してみてください。

カスタムキーボードターゲットを追加してみるとExtensionの機能や権限を設定するinfo.plistのほかに UIInputViewController というUIViewControllerのサブクラスが用意されます。最小構成ではこのUIInputViewControllerがキーボードUIとその上からの入力イベントのハンドリング、入力先への変換結果テキストの制御をになうことになります。入力先とのテキストのやりとりは UIInputViewControllertextDocumentProxy を介して行われます。

info.plist の中身

Extensionのための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>

NSExtensionPointIdentifierでcom.apple.keyboard-serviceを指定することで、このExtensionがカスタムキーボードであることを示しています。

NSExtensionPrincipalClassは、キーボードUIを提供するUIInputViewControllerのサブクラスがどれなのかを指定するもので、このExtensionでは KeyboardViewControllerというクラスがそれなのだ、ということが分かります。OSがこのクラスをインスタンス化して使用するわけです。通常のアプリとは違い、UIWindowとかAppDelegateといったものは登場しません(※注釈2)。

あとは NSExtensionAttributesの値であるdictの中で指定されているRequestsOpenAccessが重要です。これをtrueにすることで通信をはじめとする外部アクセスが可能となります。できることが飛躍的に増える反面、開発者の責任も重くなります。これについては次に説明します。

※注釈2
ちなみに NSExtensionMainStoryboardなんていうキーも存在して、名前の通りstoryboardが指定できるようですので、UIViewControllerの派生であるUIInputViewControllerを指定するならこっちの方がいいんじゃ…?と考える方もいらっしゃるんじゃないかと思いますが、実際コーディングして試してみられるといろいろお察しいただけるんじゃないかと思います…。

必須要素

ガイドラインによると、カスタムキーボードを実装する上で次の2つの要素が不可欠とされています:

  1. 信頼
  2. 「次のキーボードへ」の切り替えボタンの提供

このうち1.は、ユーザーのプライバシーにも関わるキー入力を預かる以上、ユーザーとキーボード機能の間の信頼は欠くことのできない要素であるということです。キー入力の保護、データの使用を必要最低限に留めること、精度の高さはもちろんのこと、ネットワークアクセス等の外部アクセス権限も使用するならユーザーに用途と利点をきちんと説明して合意を得ること、またそうして得た情報に対する深い配慮が必須とされています(※注釈3)。

今回は端末へのキー入力だけに基づいて、データを永続化せずに実現できる範囲の例に留めますので、サンプルでの配慮は省略しました。

※注釈3
ユーザーの信頼・期待に応えるという観点では、「ユーザーがキーボードに対して期待していることは何か」というのを理解すべきとプログラミングガイドの中で触れられています。たとえばUIKeyboardTypeの指定に対して、ふさわしいキーボードレイアウトを提供すること、文頭の自動大文字化、スペルチェック、サジェストなど、iOSの標準キーボードがすでに提供しているようなことはサードパーティキーボードでも同様に使えることが期待されるであろうという訳です。ただ、これについては配慮必須というわけではなく、どの機能を実装しどの機能を実装しないかはベンダーの判断に委ねられています。

一方、2.の「次のキーボードへ」ボタンですが、標準キーボードではglobe keyと呼ばれるものです。地球のマークの表示されたあのボタンはおなじみでしょう(下図)。一般にユーザーは複数のキーボードを使用する設定をしていますので、ユーザーが目的に応じて入力手段を切り替えられるよう、「次のキーボードへ」切り替える機能は当然必須です。こちらは各キーボードごとに用意しなければならないものです。

切り替えUIこそ用意しなければなりませんが、切り替えの処理自体は簡単に実装できるよう配慮されていて、UIInputViewControllerのadvanceToNextInputModeメソッドを呼び出すだけでおしまいです。

キーボードUIの作成

ここでは、下図のようなxibを使ってみます。File’s Ownerを、NSExtensionPrincipalClassで指定したUIInputViewControllerの派生クラスに設定しておくと、IBOutletやIBActionもあらかじめ接続してしまえるのでオススメです。

あとはUIInputViewControllerのviewDidLoadあたりで、inputViewプロパティのサブビューとしてねじ込んでしまうだけで表示されます:

    override func viewDidLoad() {
        super.viewDidLoad()

        var v = UINib(nibName:"CustomKeyboardXib", bundle:nil).instantiateWithOwner(self,options:nil)[0] as UIView
        self.inputView.addSubview(v)
    }

簡単ですね。今回はUIButtonとUILabelくらいしか使っていませんが、任意のUIViewやUIGestureRecognizerが配置できると、ドキュメントには記載されています。

文字を入力先に表示する

カスタムキーボードから入力されたキーに対して入力先にテキストを表示するには、以下のようにします:

    func insert(num : Int) {
        var proxy = textDocumentProxy as UITextDocumentProxy
        proxy.insertText(String(num))
    }

textDocumentProxyに、挿入したい文字列を渡すだけと至ってシンプルです。キーボード上でユーザーが入力をしても、このメソッドを実行するまでは入力先に文字列は渡りません。今回のサンプルでは出力キーを入力するまでは、数式としてキーボード上に表示を行い、出力キーを入力して初めて入力先に計算結果が出力されるように実装してみました。

文字削除を行う

入力の間違いは誰しもありますので、文字削除は当然必要です。こちらもtextDocumentProxyを介して行うことができます。

    func delChar() {
        var proxy = textDocumentProxy as UITextDocumentProxy
        proxy.deleteBackward()
    }

deleteBackward メソッドはカーソルの前1文字を削除します。複数文字削除したい場合は、このメソッドを削除したい文字数分を実行することになります。

入力先の選択範囲変更や文字置換に対応する

ユーザーは、キーボードでの入力中でも、入力先を直接触って操作することで、選択範囲を変更することができます。変換系が文脈を理解する上で、この選択範囲の変更は把握したい場合が多いです。また、入力先の文字列が変更されるタイミングを受け取りたい場合もあるでしょう。この場合は UIInputViewController に UITextInputDelegate プロトコルの実装を行えばよいです。

func selectionDidChange(_ textInput: UITextInput!)

のように、UITextInput (入力先にあたるもの)のオブジェクトを引数から得ることができますから、このオブジェクトを介して入力先に関する詳細な情報のやりとりや制御を行うことができます。

実行してみる

iOSシミュレーター上でカスタムキーボードを実行する手順については、Appleのプログラミングガイドに公開されています。NDAへの配慮としてシミュレータのスクリーンショットの掲載は差し控えさせていただきます。伝わりにくくて申し訳ないのですが、テキストで手順を示しますと:

  1. まずスキーム設定を確認し、Containing App と いずれかのiOSシミュレータが選択された状態にしてください。(※注釈4)
  2. ツールバーのプレイボタンを押し(あるいはメニューの Product > Run を実行し)、Containing Appとそれに包まれているカスタムキーボードのビルドを行い、iOSシミュレータ上で Containing App を実行します。
  3. iOSシミュレータにおいて、メニューの Hardware > Home を実行し、Springboardを表示します。
  4. iOSシミュレータのSettingsアプリを開き、 General > Keyboard > Keyboardsと進んで、Add New Keyboardをタップします。
  5. Purchased Keyboards というグループがあり、そこにカスタムキーボードの名前が出ていますのでこれをタップします。モーダルビューが表示されるのでここでキーボードを有効にしDoneでモーダルを閉じます。
  6. iOSシミュレータにおいて、メニューのHardware > Homeを実行し、Springboardに戻ります。
  7. Springboard上で画面を引き下げると、Spotlight検索フィールドが出現するはずです。ここをタップし、キーボードを出現させましょう。globe key(次のキーボードに切り替えるボタン)を何度か押せば、カスタムキーボードが出現し動作確認ができます。

※注釈4
ここでカスタムキーボードのターゲットが選択された状態のまま実行するとどうなるかは、実際にやってみてもらえればいろいろお察しいただけるかと思います…。

こんな感じです。Containing Appに包まれて持ち込まれたカスタムキーボードExtensionが、端末内でグローバルに使用できることも、シミュレータ上で確認できます。

なお、App Extension のデバッグについては、まだXcode6でも徐々にサポートを進めている状況みたいですので、Xcode6 新しいβがリリースされたらRelease Notesをみて機能変更されていないか目を通しておくとよいです。本稿執筆時点のβ2ではデバッグ大変そうだなあという印象でしたが、つい先日リリースされたβ3のRelease Notesを見てみると…あとはご自身でご確認をお願いします!

サンプルコード

今回作成したカスタムキーボードのソースコードは、下記で提供しています。ググりながら初めてSwiftで書いたというのを差し引いても、なかなかひどいコードで申し訳ないのですが、実際の動作を見るには、サンプルを動かしてみるのがよいと思いますので、ご笑覧ください。

あとがき

今回のサンプルのような、機能を絞ったカスタムキーボードであれば、比較的簡単に実装できることをご覧頂きました。UIは比較的作りやすい一方で、実用的な観点ではやはり変換系として賢いこと・気が利いていることが求められると思われ、そこには自然言語処理に関する高度な技術が不可欠です。

外部からのデータ取得やサーバーを使った入力補助を取り扱う場合にはさらにユーザーの情報を守る責務も伴ってきます。そういう意味では開発者にとって敷居の高い機能ではありますが、それを乗り越えてやってくるであろうサードパーティ製カスタムキーボードには期待せずにはいられません。

iOSユーザーの端末体験を大きく変えてくれるような独創的なカスタムキーボードに出会える日を楽しみにしています。

CodeIQコード銀行にあなたのコードを預けてみませんか?

  • CodeIQコード銀行ではあなたのコードを財産と考えます。
  • お預かりいただいたコードは、CodeIQコード銀行がしっかり評価し、フィードバックいたします。
  • 当コード銀行にお預けいただいたコードは、企業がみてスカウトをかける可能性があります。
  • 転職したい方や将来転職することを考えている方で、今の自分のスキルレベルを知りたい方はぜひ挑戦してみてください。
  • 企業からスカウトがきたら困る人は挑戦しないでください。

興味を持った方はこちらからチャレンジを!

  • 19
  • このエントリーをはてなブックマークに追加

■関連記事

Siriに聞いてみた!音声認識を成立させる「音響モデル」と「言語モデル」について... Siriは何でも知っている 自分自身のことでさえも… Siriの面白さの一つは問答の作り込みで、その種のコンテンツが後を絶ちませんが、検索機能にアクセスできることによって、「Google先生」に続く物知りキャラが誕生した感もありますね。 彼女は何でも知っています。 そう、自己を確立させている音...
DeNA南場智子氏が語った「経営会議より、UI/UXが大事。なぜ今デザインなのか?」... DeNAが新規事業を「やる」と決める三つの質問 何かの才能を持っている人や、ものをクリエイトできる人に対して、すごくコンプレックスを持っているという南場智子氏。なぜ今、デザインが大事なのか──その理由を、自らの失敗談とDeNAの事業戦略を交えながら語ってくれた。 ▲株式会社ディー・エヌ・...
佐々木俊尚氏を顧問に、オウンドメディアも開設!家事シェアサービス「Any+Times」は、個人のスキ... 誰かのニーズと誰かのスキルを、Webとリアルで交換 仕事で毎日遅くなるので、掃除や洗濯をする時間が取れない。そんな悩みを持つエンジニアも少なくないのではないだろうか。ハウスクリーニングサービスはいくつもあるが、安心して頼めて、かつ低コストのサービスはそうそうあるものではない。 「私自身が、便利屋...
Monacaでenchant.jsで作ったHTML5ゲームを、シュン君とスマートフォンに移植してみよ... なぜ、スマートフォンアプリ化する必要があるの? 前回までの講師は、UEI清水亮氏(前編・後編)、日本マイクロソフト物江修氏(Windowsストアアプリ編)、Mozilla Japanの清水智公氏(Firefox OS編)。 そして次なるターゲットは、スマートフォンアプリ移植。講師には、アシアル株...
作りたいアプリ・機能を一発逆引き!iOS SDK機能、フレームワーク概要まとめ #iOS8 #DeN... iOS SDK機能、フレームワーク概要のまとめと機能別逆引き CocoaPodsの登場によって、昨今のiOS開発ではとても簡単にライブラリを導入することができ、皆さんも多くの機能開発が楽になっていると思います。 ただiOS SDK自身にも非常に多くの機能やフレームワークが提供されており、外部ライ...
DeNAのiOSエンジニア内で利用頻度の高いライブラリをランキング化してみました #iOS #DeN... DeNAにおけるiOSアプリ開発 DeNA沖津です。DeNAでは、エンターテインメント事業本部という部署を新設し、非ゲームの新規事業開発に取り組んできました。 1年以上経過した現在、十数のサービスを開発し、リリース・運用を行ってきました。社内のGithub Enterprise上には、たくさんの...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

CodeIQ(コードアイキュー)とは、自分の実力を知りたいITエンジニア向けの、実務スキル評価サービスです。

CodeIQご利用にあたって
関連サイト
codeiq

リクルートグループサイトへ