はじめに
Visual Studio 2017 community(2017/9/27時点)のXamarin.Androidを使ってAndroid向けのIME(カスタムキーボード)を作る方法およびコツをまとめます。
1.新規ソリューションを立ち上げる
メニューバーのファイル
->新しいソリューション
からソリューション立ち上げのモーダルを開きます。
Android
-> アプリ
-> 空のAndroidアプリ
を選択して次へ
を押します。
2.ファイルの下準備をする。
編集の前に必要なファイルがいくつかありますので先に準備をしてしまいます。
まずはResources
フォルダに中にxml
フォルダを作ります。
xml
フォルダができたら、さらにその中にXMLファイルを追加します。
同様にしてtest_keyboard
というXMLファイルを追加してください。
続いて、layout
フォルダにレイアウトファイルを追加します。
また、Main.axml
の名前を変更してkeyboard.axml
にします。
同様に、MainActivity.cs
の名前も変更してTestKeyboard.cs
にします。
3.コーディング1:Strings.xml
に追記
Resources
/values
/Strings.xml
に一行追記します。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">DroidCustomKeyboard</string>
<string name="test_keyboard">TestKeyboard</string> <!--追記-->
</resources>
4.コーディング2:keyboard.axml
の書き換え
Resources
/layout
/keyboard.axml
を書き換えます。
これがいわゆるキーボード全体のビューになります。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:keyPreviewLayout="@layout/preview" />
5.コーディング3:preview.axml
の書き換え
Resources
/layout
/preview.axml
を書き換えます。
このファイルはキーボードのボタンを押した時にキーの上に表示される小さい矩形のレイアウトを担っているようです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#CFD8DC"
android:textStyle="bold"
android:textSize="45sp" />
6.コーディング4:method.xml
を実装
Resources
/xml
/method.xml
を実装します。
このmethod.xml
がきちんと実装できていないと、Androidの環境設定のIME一覧にキーボードが表示されません。
@string/test_keyboard
はvalues
/Strings.xml
内で定義したものがそのまま呼び出されます。
<?xml version="1.0" encoding="UTF-8" ?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
<subtype
android:label="@string/test_keyboard"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard" >
</subtype>
</input-method>
7.コーディング5:test_keyboard.xml
を実装
Resources
/xml
/test_keyboard.xml
を実装します。
このファイルはキーボードの中身のレイアウトを担います。キーを二段にしたい場合はRow
タグを増やせばOKです。
android:codes
はAndroidのKeyEventを参考にしてください。
<?xml version="1.0" encoding="UTF-8" ?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="25%p"
android:horizontalGap="0px"
android:verticalGap="0px"
android:keyHeight="50sp" >
<Row>
<Key android:codes="29" android:keyLabel="A" android:keyEdgeFlags="left" />
<Key android:codes="30" android:keyLabel="B" />
<Key android:codes="31" android:keyLabel="C" />
<Key android:codes="67" android:keyLabel="Del" android:keyEdgeFlags="right" android:isRepeatable="true"/>
</Row>
</Keyboard>
8.コーディング6:TestKeyboard.cs
の実装(書き換え)
このcs
ファイルがキーボードの入力システム本体になります。
IMEのサービスとするためにInputMethodServiceを継承したクラスを実装します。
using Android.App;
using Android.Content;
using Android.Views;
using Android.Views.InputMethods;
using Android.InputMethodServices;
using Java.Lang;
namespace DroidCustomKeyboard
{
//チェックポイント1
[Service(Permission = "android.permission.BIND_INPUT_METHOD")]
[IntentFilter(new[] { "android.view.InputMethod" })]
[MetaData("android.view.im", Resource = "@xml/method")]
public class TestKeyboard : InputMethodService, KeyboardView.IOnKeyboardActionListener
{
public KeyboardView kv;
public Keyboard k;
//チェックポイント2
public override View OnCreateInputView()
{
kv = (KeyboardView)this.LayoutInflater.Inflate(Resource.Layout.keyboard, null);
k = new Keyboard(this, Resource.Xml.test_keyboard);
kv.Keyboard = k;
kv.OnKeyboardActionListener = this;
return kv;
}
//チェックポイント3
public void OnKey(Android.Views.Keycode primaryCode, Android.Views.Keycode[] keyCodes)
{
IInputConnection ic = CurrentInputConnection;
switch (primaryCode)
{
case Android.Views.Keycode.Del:
ic.DeleteSurroundingText(1, 0);
break;
default:
if (Android.Views.Keycode.A <= primaryCode && primaryCode <= Android.Views.Keycode.Z)
{
char code = (char)(primaryCode - Android.Views.Keycode.A + 65);
ic.CommitText(new Java.Lang.String(code.ToString()), 1);
}
else if (Android.Views.Keycode.Num0 <= primaryCode && primaryCode <= Android.Views.Keycode.Num9)
{
char code = (char)(primaryCode - Android.Views.Keycode.Num0 + 48);
ic.CommitText(new Java.Lang.String(code.ToString()), 1);
}
break;
}
}
//チェックポイント4
public void OnPress(Android.Views.Keycode primaryCode)
{ }
public void OnRelease(Android.Views.Keycode primaryCode)
{ }
public void OnText(ICharSequence text)
{ }
public void SwipeLeft()
{ }
public void SwipeRight()
{ }
public void SwipeDown()
{ }
public void SwipeUp()
{ }
}
}
コードの説明
チェックポイント1
このクラスをIMEのサービスとして認識させるために必要なコードです。これが非常に重要なようで、ブレイクスルーするのが大変でした。Android StudioでIMEを作成する場合はManifestにxml形式で記述するようですが、Xamarin.Androidの場合はこのように直接csファイルに設定を行います。
チェックポイント2
OnCreateInputView
にてキーボードが呼び出された時のキーボードのビューを生成しています。Resource.Layout.keyboard
やResource.Xml.test_keyboard
で警告が出ないようにするには、一度プロジェクトをビルドする必要があります。(ビルドをするとResource.designer.cs
ファイルに呼び出し用の設定が加わります。)
チェックポイント3
OnKey
にてキーが押された時の反応を記述します。
キーコードが手に入るので、それで動作を分岐させます。普通の文字とDeleteやReturnなどのキーを区別するようにします。注意しなくてはならないのは、AndroidやXamarin.Androidで指定されているKeyCodeはASCIIコードとは異なるので、そのまま文字に変換できないという点です。ASCIIやUnicodeにするためのコードが余計に必要です。
チェックポイント4
InputMethodService
およびKeyboardView.IOnKeyboardActionListener
を実装する上で必要な最低限のメソッドたちです。とりわけ何か動作をさせたい場合は実装してあげてください。
6.実行(IMEのインストール)
まずは、プロジェクトの設定を変更します。
メニューバー
-> プロジェクト
-> DroidCustomKeyboard オプション
を押します。
実行
-> 構成
-> Default
の中のエントリポイントをサービスにし、明示的インテントのサービスをDroidCustomKeyboard.TestKeyboard
にします。
ビルドが成功したら実行します。
設定アプリ -> 言語と入力 -> 現在のキーボード -> キーボードの選択 -> DroidCustomKeyboard をON
どこか文字入力ができるところでIMEを起動します。
IMEを切り替えたら自作のキーボードが使えます。
7.終わりに
Android Studioと同様の方法でIMEの実装を試みたところ、IMEのインストールに躓きteratailにお世話になりました。
Xamarin.Androidを使ったAndroidアプリ開発はAndroid Studioでの開発に非常に似ているようですが、実行やビルド設定など細かいところで差があったり、使用できるクラスやメソッドに差があったりして意外と厄介でした。
参考文献も異様に少ないので今後ノウハウが蓄積されると良いですね。