Розробка кастомної клавіатури (Input Method Editor) для Android
Input Method Editor (IME) на Android—це сервіс, зареєстрований в системі через InputMethodService. На відміну від iOS, Android дає розробнику набагато більше свободи: IME може займати довільну висоту, містити WebView, працювати в фоні через bound service. Ця свобода обходиться своїм набором граблей.
Життєвий цикл InputMethodService
Клавіатура існує як системний сервіс. Ключові callbacks:
-
onCreateInputView()— створення вью клавіатури, вызивается один раз -
onStartInputView(EditorInfo, Boolean)— кожного разу при появленні клавіатури; читаємоEditorInfo.inputType, щоб зрозуміти, що за поле—пароль, email, числа, довільний текст -
onFinishInputView(Boolean)— поле втратило фокус -
onComputeInsets(Insets)— критично важливий для управління відступами
EditorInfo.inputType—бітова маска. Поле пароля: inputType & InputType.TYPE_MASK_VARIATION == InputType.TYPE_TEXT_VARIATION_PASSWORD. Якщо не обробити цей випадок явно, автокорекція буде пропонуватися в полях паролів—гарантований відказ у Play Store.
Проблема з висотою та insets
Найчастіша скарга: клавіатура перекриває EditText. Причина—неправильна реалізація onComputeInsets. За замовчуванням система не знає, яку частину екрана займає IME, і не зміщує контент.
@Override
public void onComputeInsets(InputMethodService.Insets outInsets) {
super.onComputeInsets(outInsets);
outInsets.contentTopInsets = outInsets.visibleTopInsets;
}
Але це працює тільки якщо host-додаток використовує adjustResize або adjustPan в windowSoftInputMode. Якщо там стоїть adjustNothing—нічого не поможе, це відповідальність host-додатку. Потрібно це документувати.
Передача тексту в поле
Введення символу: getCurrentInputConnection().commitText("a", 1). Видалення: getCurrentInputConnection().deleteSurroundingText(1, 0). Фіксація composing text (для IME з проміжним станом, як японські/китайські): setComposingText() + finishComposingText().
InputConnection може бути null—відбувається при втраті фокусу між вызовами. Кожен вызов потрібно перевіряти:
val ic = currentInputConnection ?: return
ic.commitText(text, 1)
Зберігання даних та дозволи
IME в Android—привілейований компонент, але дозволи працюють стандартно. Для доступу в інтернет потрібен INTERNET в маніфесті. Словник та настройки—SharedPreferences або Room. Предиктивний ввід з серверної сторони—тільки через явне согласие користувача плюс опис у Privacy Policy.
Play Store перевіряє IME з подвійною увагою: скрита передача натискань клавіш—прямий наруш політики. Якщо клавіатура відправляє щось на сервер (аналітику розкладки, предиктивний ввід), це потрібно декларувати через Data Safety Form.
Тема та Material Design
Починаючи з Android 12, клавіатура повинна підтримувати Dynamic Color з Material You. MaterialTheme через AppCompatDelegate + DynamicColors.applyToActivitiesIfAvailable() не працює в IME напрямку—потрібно застосувати тему до inputView явно через ContextThemeWrapper.
Jetpack Compose всередину IME працює від Compose 1.2, але потребує обережної настройки: ComposeView всередину onCreateInputView() з явним setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow).
Тестування
Тестуємо на реальних пристроях з разними версіями: Android 8 (API 26)—мінімум, якщо не використовуємо нові IME API. Тестуємо в Chrome для Android (окремий InputConnection), у Gmail, у полях з inputType=numberPassword. На емуляторі можна запускати, але поведінка insets відрізняється.
Тривалість розробки: 1–3 тижні. Залежить від наявності предиктивного вводу, підтримки кількох мов та кастомної темізації. Вартість розраховується індивідуально.







