입력 방법 만들기

입력 방식 편집기(IME)는 사용자가 텍스트를 입력할 수 있는 사용자 컨트롤입니다. Android에서 제공하는 확장 가능한 입력 방법 프레임워크로 애플리케이션이 터치 키보드나 음성 입력과 같은 대체 입력 방법을 사용자에게 제공할 수 있습니다. 사용자는 원하는 IME를 설치한 후 시스템 설정에서 사용할 IME를 선택하여 전체 시스템에서 사용할 수 있습니다. 한 번에 IME 하나만 사용 설정할 수 있습니다.

IME를 Android 시스템에 추가하려면 InputMethodService를 확장하는 클래스가 포함된 Android 애플리케이션을 만듭니다. 또한 일반적으로 IME 서비스에 옵션을 전달하는 '설정' 활동을 만듭니다. 시스템 설정의 일부로 표시되는 설정 UI를 정의할 수도 있습니다.

이 가이드에서는 다음을 다룹니다.

  • IME 수명 주기
  • 애플리케이션 manifest에서 IME 구성요소 선언
  • IME API
  • IME UI 디자인
  • IME에서 애플리케이션으로 텍스트 전송
  • IME 하위유형 사용

IME를 사용해 본 적이 없다면 먼저 입문 자료 화면 입력 방법을 읽어야 합니다.

IME 수명 주기

다음 다이어그램은 IME의 수명 주기를 설명합니다.

그림 1. IME 수명 주기

다음 섹션에서는 이 수명 주기를 따르는 IME와 연결된 UI 및 코드를 구현하는 방법을 설명합니다.

manifest에서 IME 구성요소 선언

Android 시스템에서 IME는 특수 IME 서비스가 포함된 Android 애플리케이션입니다. 애플리케이션의 manifest 파일은 서비스를 선언하고 필요한 권한을 요청하며 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.inputmethodserviceandroid.view.inputmethod 패키지에 있습니다. KeyEvent 클래스는 키보드 문자를 처리하는 데 중요합니다.

IME의 핵심은 InputMethodService를 확장하는 클래스이며 이는 서비스 구성요소입니다. 일반 서비스 수명 주기를 구현하는 것 외에도 이 클래스에는 IME UI를 제공하고 사용자 입력을 처리하며 현재 포커스가 있는 필드에 텍스트를 전달하는 콜백이 있습니다. 기본적으로 InputMethodService 클래스는 IME의 상태 및 가시성을 관리하고 현재 입력 필드와 통신하기 위한 구현을 대부분 제공합니다.

다음 클래스도 중요합니다.

BaseInputConnection
InputMethod의 통신 채널을 입력을 수신하는 애플리케이션에 다시 정의합니다. 커서 주위의 텍스트를 읽고 텍스트 상자에 텍스트를 커밋하며 원시 키 이벤트를 애플리케이션에 전송하는 데 사용합니다. 애플리케이션은 기본 인터페이스 InputConnection을 구현하는 대신 이 클래스를 확장해야 합니다.
KeyboardView
키보드를 렌더링하고 사용자 입력 이벤트에 응답하는 View의 확장 프로그램입니다. 키보드 레이아웃이 XML 파일에서 정의할 수 있는 Keyboard의 인스턴스에서 지정됩니다.

입력 방법 UI 디자인

IME에는 두 가지 기본 시각적 요소인 입력 뷰와 후보군 뷰가 있습니다. 디자인하는 입력 방법과 관련된 요소만 구현하면 됩니다.

입력 뷰

입력 뷰는 사용자가 키클릭, 필기 입력 또는 동작 형식으로 텍스트를 입력하는 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
            }
        }
    }
    

자바

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

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

        return inputView;
    }
    

이 예에서 MyKeyboardViewKeyboardView의 맞춤 구현 인스턴스로 Keyboard를 렌더링합니다.

후보군 뷰

후보군 뷰는 사용자가 선택할 잠재적 단어 수정이나 제안을 IME에서 표시하는 UI입니다. IME 수명 주기에서 시스템은 후보군 뷰를 표시할 준비가 되면 onCreateCandidatesView()를 호출합니다. 이 메서드를 구현할 때 단어 제안을 표시하는 레이아웃을 반환하거나 어떤 것도 표시하고 싶지 않으면 null을 반환합니다. null 응답은 기본 동작이므로 제안을 제공하지 않는다면 이를 구현할 필요가 없습니다.

UI 디자인 고려사항

이 섹션에서는 IME의 특정 UI 디자인 고려사항을 설명합니다.

여러 화면 크기 처리

IME의 UI는 다양한 화면 크기에 맞게 조정 가능해야 하고 가로 및 세로 방향을 모두 처리할 수도 있어야 합니다. 전체 화면 모드가 아닌 IME에서는 애플리케이션이 텍스트 필드 및 관련 컨텍스트를 표시할 충분한 공간을 남겨서 IME가 화면의 절반 이상을 차지하지 않도록 합니다. 전체 화면 모드 IME에서는 이것이 문제가 되지 않습니다.

다양한 입력 유형 처리

Android 텍스트 필드로 자유 형식 텍스트, 숫자, URL, 이메일 주소, 검색 문자열과 같은 특정 입력 유형을 설정할 수 있습니다. 새로운 IME를 구현할 때 각 필드의 입력 유형을 감지하여 적절한 인터페이스를 제공해야 합니다. 그러나 사용자가 입력 유형에 유효한 텍스트를 입력했는지 확인하려고 IME를 설정할 필요는 없습니다. 그런 작업은 텍스트 필드를 소유하는 애플리케이션의 책임입니다.

예를 들어 다음은 Android 플랫폼과 함께 제공되는 라틴어 IME가 텍스트 및 전화번호 입력에 제공하는 인터페이스의 스크린샷입니다.

그림 2. 라틴어 IME 입력 유형

입력 필드에서 포커스를 수신하고 IME가 시작되면 시스템은 onStartInputView()를 호출하여 텍스트 필드의 입력 유형 및 기타 속성에 관한 세부정보가 포함된 EditorInfo 객체를 전달합니다. 이 객체의 inputType 필드에는 텍스트 필드의 입력 유형이 포함되어 있습니다.

inputType 필드는 다양한 입력 유형 설정의 비트 패턴이 포함된 int입니다. 텍스트 필드의 입력 유형에 관해 테스트하려면 다음과 같이 상수 TYPE_MASK_CLASS로 마스크하세요.

Kotlin

    inputType and InputType.TYPE_MASK_CLASS
    

자바

    inputType & InputType.TYPE_MASK_CLASS
    

입력 유형 비트 패턴에는 다음을 포함하여 여러 값 중 하나가 있을 수 있습니다.

TYPE_CLASS_NUMBER
숫자를 입력하는 텍스트 필드입니다. 이전 스크린샷에 표시된 것처럼 라틴어 IME는 이 유형의 필드에 숫자 패드를 표시합니다.
TYPE_CLASS_DATETIME
날짜와 시간을 입력하는 텍스트 필드입니다.
TYPE_CLASS_PHONE
전화번호를 입력하는 텍스트 필드입니다.
TYPE_CLASS_TEXT
지원되는 모든 문자를 입력하는 텍스트 필드입니다.

이러한 상수는 InputType 참조 문서에 자세히 설명되어 있습니다.

inputType 필드에는 다음과 같이 텍스트 필드 유형의 변형을 표시하는 다른 비트가 포함될 수 있습니다.

TYPE_TEXT_VARIATION_PASSWORD
비밀번호를 입력하는 TYPE_CLASS_TEXT의 변형입니다. 입력 방법은 실제 텍스트 대신 딩벳을 표시합니다.
TYPE_TEXT_VARIATION_URI
웹 URL 및 기타 Uniform Resource Identifier(URI)를 입력하는 TYPE_CLASS_TEXT의 변형입니다.
TYPE_TEXT_FLAG_AUTO_COMPLETE
애플리케이션이 사전, 검색 또는 기타 기능에서 '자동 완성'하는 텍스트를 입력하는 TYPE_CLASS_TEXT의 변형입니다.

이러한 변형을 테스트할 때 적절한 상수를 사용하여 inputType을 마스크해야 합니다. 사용 가능한 마스크 상수는 InputType 참조 문서에 나열되어 있습니다.

주의: 자체 IME에서 텍스트를 비밀번호 필드로 전송하는 경우 텍스트가 올바르게 처리되는지 확인하세요. 입력 뷰와 후보군 뷰에서 모두 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)
    }
    

자바

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

커밋하기 전에 텍스트 작성

IME에서 텍스트 예측을 실행하는 경우나 글리프 또는 단어를 작성하는 데 여러 단계가 필요한 경우 사용자가 단어를 커밋할 때까지 텍스트 필드에 진행률을 표시한 다음 일부 작성을 완성된 텍스트로 교체할 수 있습니다. setComposingText()에 텍스트를 전달할 때 '스팬'을 추가하여 텍스트를 특별하게 취급할 수도 있습니다.

다음 스니펫은 텍스트 필드에 진행률을 표시하는 방법을 보여줍니다.

Kotlin

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

자바

    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과 같은 언어
  • 음성, 키보드, 필기 입력과 같은 입력 모드
  • 10키 또는 쿼티 키보드 레이아웃과 같은 IME와 관련된 기타 입력 스타일, 양식, 속성

기본적으로 모드는 '키보드', '음성' 등의 모든 텍스트일 수 있습니다. 하위유형은 이들의 조합을 노출할 수도 있습니다.

하위유형 정보는 알림바에서 사용 가능한 IME 전환 대화상자, 그리고 IME 설정에 사용됩니다. 이 정보로 프레임워크에서 IME의 특정 하위유형을 직접 불러올 수도 있습니다. IME를 빌드할 때 하위유형 기능을 사용하세요. 사용자가 다양한 IME 언어와 모드 사이에서 식별하고 전환하는 데 도움을 줍니다.

<subtype> 요소를 사용하여 입력 방법의 XML 리소스 파일 중 하나에서 하위유형을 정의합니다. 다음 스니펫은 두 가지 하위유형으로 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를 사용하여 하위유형의 언어 라벨과 동일한 하위유형 라벨을 가져옵니다. 다음 두 스니펫에서 이 작업을 보여줍니다. 첫 번째 스니펫은 입력 방법 XML 파일의 일부를 표시합니다.

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

다음 스니펫은 IME의 strings.xml 파일의 일부입니다. 문자열 리소스 label_subtype_generic은 입력 방법 UI 정의에서 하위유형의 라벨을 설정하는 데 사용되며 다음과 같이 정의됩니다.

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

이 설정으로 하위유형의 표시 이름이 언어 설정과 일치하게 됩니다. 예를 들어 모든 영어 언어에서 표시 이름은 '영어(미국)'입니다.

알림바에서 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()를 호출하여 두 번째 매개변수에 false를 전달합니다. false 값은 어떤 IME에 속하는지 상관없이 모든 하위유형을 동일하게 취급하라고 시스템에 알립니다. true를 지정하면 시스템이 현재 IME의 하위유형을 순환해야 합니다.

주의: Android 5.0(API 레벨 21) 이하에서는 switchToNextInputMethod()supportsSwitchingToNextInputMethod 속성을 인식하지 못합니다. 사용자가 전환 키 없이 IME로 전환하면 그 IME에 고정될 수 있고 쉽게 다른 것으로 전환할 수 없습니다.

일반적인 IME 고려사항

다음은 IME를 구현할 때 고려할 다른 사항입니다.

  • 사용자가 IME UI에서 직접 옵션을 설정하는 방법을 제공합니다.
  • 여러 IME가 기기에 설치될 수 있으므로 사용자가 입력 방법 UI에서 다른 IME로 직접 전환하는 방법을 제공합니다.
  • IME UI를 빠르게 불러옵니다. 사용자가 텍스트 필드를 탭하자마자 IME를 볼 수 있도록 크기가 큰 리소스는 미리 로드하거나 요청에 따라 로드합니다. 입력 방법의 후속 호출을 위한 리소스와 뷰를 캐시합니다.
  • 반대로 입력 방법 창이 숨겨진 직후 대용량 메모리 할당을 해제하여 애플리케이션에서 실행할 충분한 메모리를 가질 수 있도록 해야 합니다. IME가 몇 초 동안 숨겨진 상태라면 지연된 메시지를 사용하여 리소스를 해제해 보세요.
  • 사용자가 IME와 연결된 언어에 최대한 많은 문자를 입력할 수 있도록 합니다. 사용자는 비밀번호나 사용자 이름에 구두점을 사용할 수 있으므로 IME에서 여러 다양한 문자를 제공하여 사용자가 비밀번호를 입력하고 기기에 액세스하도록 해야 합니다.