Android 11 のデベロッパー プレビューが公開されました。ぜひお試しのうえ、フィードバックをお寄せください

インプット メソッドを作成する

インプット メソッド エディタ(IME)は、ユーザーがテキストを入力できるようにするユーザー コントロールです。Android は、拡張可能なインプット メソッド フレームワークを備えています。これにより、画面キーボードや音声入力など、代替的インプット メソッドをユーザーに提供するアプリを作成できます。ユーザーは、目的の IME をインストールした後、使用する IME をシステム設定から選択することで、その IME をシステムレベルで使用できます。一度に有効にできる IME は 1 つだけです。

IME を Android システムに追加するには、InputMethodService を拡張するクラスを含む Android アプリを作成します。また、通常は、オプションを IME サービスに渡す「設定」アクティビティを作成します。設定 UI を定義して、システム設定の一部として表示することもできます。

このガイドでは、以下の内容について説明します。

  • IME のライフサイクル
  • アプリ マニフェスト内で IME コンポーネントを宣言する
  • IME API
  • IME UI を設計する
  • IME からアプリにテキストを送信する
  • IME サブタイプを作成する

これまでに IME の開発を行ったことがない場合は、まず、オンスクリーン インプット メソッドをご覧ください。

IME のライフサイクル

IME のライフサイクルを以下の図に示します。

図 1: IME のライフサイクル

以下のセクションでは、このライフサイクルに基づいて、IME に関連付けられる UI とコードを実装する方法について説明します。

マニフェスト内で IME コンポーネントを宣言する

Android システムにおいて、IME は、特別な IME サービスを含む Android アプリです。アプリのマニフェスト ファイルは、サービスを宣言し、必要なパーミッションをリクエストし、action.view.InputMethod アクションに合致するインテント フィルタを提供し、IME の特性を定義するメタデータを提供する必要があります。また、システム設定から起動できる「設定」アクティビティを定義することで、ユーザーが IME の動作を変更できる設定インターフェースを提供することができます。

IME サービスを宣言するスニペットを以下に示します。このスニペットは、サービスが IME をシステムに接続できるようにする BIND_INPUT_METHOD パーミッションをリクエストして、android.view.InputMethod アクションに合致するインテント フィルタをセットアップし、IME のメタデータを定義しています。

    <!-- Declares the input method service -->
    <service android:name="FastInputIME"
        android:label="@string/fast_input_label"
        android:permission="android.permission.BIND_INPUT_METHOD">
        <intent-filter>
            <action android:name="android.view.InputMethod" />
        </intent-filter>
        <meta-data android:name="android.view.im"
                   android:resource="@xml/method" />
    </service>
    

IME 用の設定アクティビティを宣言するスニペットを以下に示します。このスニペットには、対象アクティビティが IME アプリのメイン エントリ ポイントであることを示す ACTION_MAIN のインテント フィルタがあります。

    <!-- Optional: an activity for controlling the IME settings -->
    <activity android:name="FastInputIMESettings"
        android:label="@string/fast_input_settings">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
        </intent-filter>
    </activity>
    

また、直接 UI から IME の設定にアクセスできるようにすることもできます。

インプット メソッド API

IME に固有のクラスは、android.inputmethodservice パッケージと android.view.inputmethod パッケージに含まれています。キーボード文字を処理するうえで、KeyEvent クラスが重要になります。

IME の中心部分は、サービス コンポーネントです。これは、InputMethodService を拡張するクラスです。通常のサービス ライフサイクルの実装に加えて、このクラスには、IME の UI を提供し、ユーザー入力を処理し、現在フォーカスのあるフィールドにテキストを配信するためのコールバックがあります。デフォルトでは、IME の状態や表示設定を管理し、現在の入力フィールドと通信するための実装のほとんどの部分を、InputMethodService クラスによって実現できます。

以下のクラスも重要です。

BaseInputConnection
InputMethod から、入力を受信するアプリへの通信チャネルを定義します。このクラスを使用することで、カーソルの周囲のテキストを読み取り、テキスト ボックスにテキストをコミットし、RAW キーイベントをアプリに送信することができます。アプリは、InputConnection ベース インターフェースを実装するのではなく、このクラスを拡張する必要があります。
KeyboardView
View の拡張機能で、キーボードをレンダリングし、ユーザー入力イベントに応答します。キーボード レイアウトは、XML ファイルで定義可能な Keyboard のインスタンスによって指定します。

インプット メソッド UI を設計する

IME には、input ビューと candidates ビューという 2 つの主要な視覚要素があります。実装する必要があるのは、設計するインプット メソッドに関係する要素だけに限られます。

input ビュー

input ビューは、キークリックや手書き、ジェスチャーといった形式でユーザーがテキストを入力する UI です。IME が初めて表示されるとき、システムは onCreateInputView() コールバックを呼び出します。このメソッドの実装では、IME ウィンドウ内に表示するレイアウトを作成し、システムにレイアウトを返します。onCreateInputView() メソッドを実装する例を以下のスニペットに示します。

Kotlin

    override fun onCreateInputView(): View {
        return layoutInflater.inflate(R.layout.input, null).apply {
            if (this is MyKeyboardView) {
                setOnKeyboardActionListener(this@MyInputMethod)
                keyboard = latinKeyboard
            }
        }
    }
    

Java

    @Override
    public View onCreateInputView() {
        MyKeyboardView inputView =
            (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null);

        inputView.setOnKeyboardActionListener(this);
        inputView.setKeyboard(latinKeyboard);

        return inputView;
    }
    

この例において、MyKeyboardView は、Keyboard をレンダリングする KeyboardView のカスタム実装のインスタンスです。

candidates ビュー

candidates ビューは、ユーザーが選択できる単語の修正候補や提案を IME が表示する UI です。IME ライフサイクルにおいて、システムは、candidates ビューを表示する準備が整うと、onCreateCandidatesView() を呼び出します。このメソッドの実装では、単語候補を表示するレイアウトを返すか、何も表示したくない場合は null を返します。デフォルト動作は null レスポンスであるため、候補を提示しない場合、このメソッドを実装する必要はありません。

UI 設計に関する注意事項

このセクションでは、IME の UI 設計に関する注意事項について説明します。

さまざまな画面サイズを処理する

IME の UI は、さまざまな画面サイズに合わせて拡大縮小できる必要があります。また、横向きと縦向きの両方を処理できる必要があります。非フルスクリーン IME モードでは、テキスト フィールドおよび関連コンテキストをアプリが表示するのに十分なスペースを残し、IME が占有する範囲を画面の半分以下に抑えます。フルスクリーン IME モードの場合、この点は問題になりません。

さまざまな入力タイプを処理する

Android テキスト フィールドでは、自由形式テキストや、数字、URL、メールアドレス、検索文字列など、さまざまな入力タイプを個々に設定できます。新しい IME を実装する場合、各フィールドの入力タイプを検出して、その入力タイプに適したインターフェースを提供する必要があります。ただし、入力タイプに対して有効なテキストをユーザーが入力したかチェックするように IME をセットアップする必要はありません。このようなチェックは、テキスト フィールドを所有するアプリが行います。

たとえば、Android プラットフォームに組み込まれている Latin IME が、テキスト入力および電話番号入力用に提供するインターフェースのスクリーンショットは次のとおりです。

図 2: Latin IME の入力タイプ

入力フィールドがフォーカスを受け取り、IME が起動すると、システムは onStartInputView() を呼び出し、入力タイプや各種のテキスト フィールド属性に関する詳細情報を格納した EditorInfo オブジェクトを渡します。このオブジェクトの inputType フィールドに、テキスト フィールドの入力タイプが格納されています。

inputType フィールドは、さまざまな入力タイプ設定のビットパターンを格納している int です。テキスト フィールドの入力タイプをテストするには、次のように TYPE_MASK_CLASS 定数でマスキングします。

Kotlin

    inputType and InputType.TYPE_MASK_CLASS
    

Java

    inputType & InputType.TYPE_MASK_CLASS
    

入力タイプのビットパターンとしては、次のような値を指定できます。

TYPE_CLASS_NUMBER
数値を入力するためのテキスト フィールド。上記のスクリーンショットで示したように、Latin IME は、このタイプのフィールドに対してテンキーを表示します。
TYPE_CLASS_DATETIME
日時を入力するためのテキスト フィールド。
TYPE_CLASS_PHONE
電話番号を入力するためのテキスト フィールド。
TYPE_CLASS_TEXT
サポートされているすべての文字を入力するためのテキスト フィールド。

各定数の詳細については、InputType のリファレンス ドキュメントをご覧ください。

inputType フィールドには、以下のようなテキスト フィールド型のバリアントを示す別のビットを含めることができます。

TYPE_TEXT_VARIATION_PASSWORD
パスワードを入力するための TYPE_CLASS_TEXT のバリアント。インプット メソッドは、実際のテキストの代わりに装飾記号を表示します。
TYPE_TEXT_VARIATION_URI
ウェブ URL および各種 URI(Uniform Resource Identifier)を入力するための TYPE_CLASS_TEXT のバリアント。
TYPE_TEXT_FLAG_AUTO_COMPLETE
辞書や検索などの機能に基づいてアプリが「オートコンプリート」するテキストを入力するための TYPE_CLASS_TEXT のバリアント。

このようなバリアントをテストする際は、必ず適切な定数を使用して inputType をマスキングするようにしてください。利用可能なマスク定数のリストについては、InputType のリファレンス ドキュメントをご覧ください。

注: 独自の IME 内でパスワード フィールドにテキストを送信する場合は、必ずテキストを正しく処理できるようにしてください。input ビューと candidates ビューの両方で、UI 内でパスワードを非表示にしてください。また、パスワードはデバイス上に保存しないでください。詳細については、設計セキュリティ ガイドをご覧ください。

テキストをアプリに送信する

ユーザーが IME を使用してテキストを入力した場合、個々のキーイベントを送信するか、アプリのテキスト フィールド内でカーソルの周囲のテキストを編集することにより、アプリにテキストを送信できます。どちらの場合でも、InputConnection のインスタンスを使用して、テキストを配信します。このインスタンスを取得するには、InputMethodService.getCurrentInputConnection() を呼び出します。

カーソルの周囲のテキストを編集する

テキスト フィールド内の既存テキストの編集を処理する場合、BaseInputConnection 内に以下のような便利なメソッドがあります。

getTextBeforeCursor()
現在のカーソル位置の前にある指定数の文字を格納する CharSequence を返します。
getTextAfterCursor()
現在のカーソル位置の後ろにある指定数の文字を格納する CharSequence を返します。
deleteSurroundingText()
現在のカーソル位置の前後にある指定数の文字を削除します。
commitText()
テキスト フィールドに CharSequence をコミットして、新しいカーソル位置を設定します。

たとえば、カーソルの左側にある 4 文字を「Hello!」というテキストに置き換えるスニペットを以下に示します。

Kotlin

    currentInputConnection.also { ic: InputConnection ->
        ic.deleteSurroundingText(4, 0)
        ic.commitText("Hello", 1)
        ic.commitText("!", 1)
    }
    

Java

    InputConnection ic = getCurrentInputConnection();
    ic.deleteSurroundingText(4, 0);
    ic.commitText("Hello", 1);
    ic.commitText("!", 1);
    

テキストを入力しながらコミットする

IME がテキスト予測を行う場合や、記号や単語を入力する際に複数の手順が必要となる場合は、テキスト フィールドに進行状況を表示し、ユーザーが単語をコミットしたら、部分的な入力内容を完成版テキストに置き換えることができます。また、setComposingText() に渡す際に「span」を追加することで、テキストに特別な処理を施すことができます。

テキスト フィールドに進行状況を表示するスニペットを以下に示します。

Kotlin

    currentInputConnection.also { ic: InputConnection ->
        ic.setComposingText("Composi", 1)
        ic.setComposingText("Composin", 1)
        ic.commitText("Composing ", 1)
    }
    

Java

    InputConnection ic = getCurrentInputConnection();
    ic.setComposingText("Composi", 1);
    ic.setComposingText("Composin", 1);
    ic.commitText("Composing ", 1);
    

ユーザーにどのように表示されるかを次のスクリーンショットに示します。

図 3: テキストを入力しながらコミットする

ハードウェア キーイベントをインターセプトする

インプット メソッド ウィンドウは明示的なフォーカスを持ちませんが、ハードウェア キーイベントを最初に受け取って、それを使用するのか、アプリに転送するのかを選択することができます。たとえば、入力中に候補を選択できるように、方向キーを使用して UI 内を移動できるように設定できます。また、戻るキーをトラップして、インプット メソッド ウィンドウから発生したポップアップを閉じることもできます。

ハードウェア キーをインターセプトするには、onKeyDown()onKeyUp() をオーバーライドします。

自身で処理しないキーについては、必ず super() メソッドを呼び出してください。

IME サブタイプを作成する

サブタイプを使用すると、IME は、IME がサポートする複数の入力モードと言語をエクスポーズできます。サブタイプは、以下を表現することができます。

  • en_US や fr_FR などの言語 / 地域。
  • 音声、キーボード、手書きなどの入力モード。
  • テンキーや QWERTY キーボード レイアウトなど、IME に固有の各種入力スタイル、フォーム、プロパティ。

基本的に、モードには任意のテキスト(「keyboard」、「voice」など)を使用できます。サブタイプは、さまざまな組み合わせをエクスポーズすることもできます。

サブタイプ情報は、通知バーから利用できる IME 切り替えダイアログや、IME 設定で使用されます。また、この情報により、フレームワークは IME の特定のサブタイプを直接表示することができます。IME を作成するときは、サブタイプ機能を使用してください。サブタイプは、ユーザーがさまざまな IME の言語やモードを識別し、切り替える際に役立ちます。

サブタイプを定義する際は、インプット メソッドのいずれかの XML リソース ファイルの中で <subtype> 要素を使用します。2 つのサブタイプ(US English 言語 / 地域のキーボード サブタイプと、フランスの French 言語 / 地域のキーボード サブタイプ)を持つ IME を定義するスニペットを以下に示します。

    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon">
        <subtype android:name="@string/display_name_english_keyboard_ime"
                android:icon="@drawable/subtype_icon_english_keyboard_ime"
                android:imeSubtypeLanguage="en_US"
                android:imeSubtypeMode="keyboard"
                android:imeSubtypeExtraValue="somePrivateOption=true" />
        <subtype android:name="@string/display_name_french_keyboard_ime"
                android:icon="@drawable/subtype_icon_french_keyboard_ime"
                android:imeSubtypeLanguage="fr_FR"
                android:imeSubtypeMode="keyboard"
                android:imeSubtypeExtraValue="foobar=30,someInternalOption=false" />
        <subtype android:name="@string/display_name_german_keyboard_ime" ... />
    </input-method>
    

サブタイプが UI 内で正しくラベル付けされるようにするには、%s を使用して、サブタイプの言語 / 地域ラベルと同じサブタイプ ラベルを取得します。この点について、以下の 2 つのスニペットで説明します。最初のスニペットは、インプット メソッドの XML ファイルの一部を示しています。

    <subtype
        android:label="@string/label_subtype_generic"
        android:imeSubtypeLocale="en_US"
        android:icon="@drawable/icon_en_us"
        android:imeSubtypeMode="keyboard" />
    

次のスニペットは、IME の strings.xml ファイルの一部を示しています。サブタイプのラベルを設定する際にインプット メソッド UI 定義が使用する label_subtype_generic 文字列リソースは、次のように定義されます。

    <string name="label_subtype_generic">%s</string>
    

この設定により、サブタイプの表示名と言語 / 地域設定が一致するようになります。たとえば、English 言語 / 地域の場合、表示名は「英語(アメリカ)」になります。

通知バーから IME サブタイプを選択する

Android システムは、すべての IME がエクスポーズしているすべてのサブタイプを管理します。IME サブタイプは、所属する IME のモードとして扱われます。通知バーで、現在設定されている IME のサブタイプを選択できます。次のスクリーンショットをご覧ください。

図 4: 通知バーから IME サブタイプを選択する

図 5: システム設定でサブタイプを設定する

システム設定から IME サブタイプを選択する

ユーザーは、システム設定領域の「言語と入力」設定パネルで、サブタイプの使用方法を指定できます。

図 6: IME の言語を選択する

IME サブタイプを切り替える

地球型の言語アイコンなどの切り替えキーを、キーボードの一部として提供することで、複数の IME サブタイプをユーザーが簡単に切り替えられるようにすることができます。これにより、キーボードの操作性が大幅に向上し、ユーザーの不満を取り除くことができます。このような切り替え機能を有効にする手順は次のとおりです。

  1. インプット メソッドの XML リソース ファイル内で、supportsSwitchingToNextInputMethod = "true" を宣言します。この宣言は、次のスニペットのようになります。
        <input-method xmlns:android="http://schemas.android.com/apk/res/android"
                android:settingsActivity="com.example.softkeyboard.Settings"
                android:icon="@drawable/ime_icon"
                android:supportsSwitchingToNextInputMethod="true">
        
  2. shouldOfferSwitchingToNextInputMethod() メソッドを呼び出します。
  3. メソッドが true を返した場合は、切り替えキーを表示します。
  4. ユーザーが切り替えキーをタップしたら、switchToNextInputMethod() を呼び出して、2 番目のパラメータに false を渡します。値が false の場合、どの IME に所属しているかにかかわらず、すべてのサブタイプを平等に処理するようにシステムに指示します。true を指定した場合は、現在の IME 内でサブタイプが循環します。

注: Android 5.0(API レベル 21)より前の場合、switchToNextInputMethod()supportsSwitchingToNextInputMethod 属性を認識しません。ユーザーが切り替えキーを使用せずに IME を切り替えると、その IME から抜け出せなくなり、別の IME に簡単に切り替えられなくなる場合があります。

IME に関する一般的な注意事項

IME を実装する際は、次の点に注意してください。

  • IME の UI から直接オプションを設定する方法をユーザーに提供してください。
  • 複数の IME がデバイスにインストールされている可能性があるため、直接インプット メソッド UI から別の IME に切り替える方法をユーザーに提供してください。
  • IME の UI をすばやく表示できるようにしてください。ユーザーがテキスト フィールドをタップしたらすぐに IME が表示されるように、大きなリソースはプリロードするか、オンデマンドでロードします。後でインプット メソッドが呼び出される場合に備え、リソースやビューをキャッシュします。
  • 逆に、インプット メソッド ウィンドウが非表示になったら、すぐに大きなメモリ割り当てを解放する必要があります。これにより、アプリを実行するのに十分なメモリを確保できるようになります。IME が数秒間、非表示状態になった場合は、遅延メッセージを使用してリソースを解放することをおすすめします。
  • IME に関連付けられている言語や言語 / 地域を対象に、可能な限り多様な文字をユーザーが入力できるようにしてください。ユーザーは、パスワードやユーザー名に句読点を使用する可能性があります。ユーザーがパスワードを入力してデバイスにアクセスできるように、IME は、さまざまな文字を提供する必要があります。