Android 输入法详解
文本输入是输入法和编辑器协同作用的结果,输入法可以是软键盘、语音等,扩展了 InputMethodService 来实现,编辑器主要是接受文本并显示文本的组件,一般是 EditText,输入法与编辑器的交互一般是当输入框获得焦点,弹出当前系统默认输入法,输入字符,选择候选词,更新输入字符到编辑框,本文将从如下几个方面介绍 Android 输入法机制,如下:
官方文档

IMF 框架
Android 输入放框架主要包括三部分内容:
- 客户端,当前输入内容的 App,主要是
InputMethodManager和EditText/TextView。 - 输入法管理服务,主要是
InputMethodManagerService。 - 输入法:主要是
InputMethodService。
可知最关键的就是 InputMethodManager、InputMethodManagerService、InputMethodService 三者之间的关系,后文中出现可将其简称为 IMM、IMMS和IMS,其关系如下:
sequenceDiagram
participant IMM as 客户端(IMM)
participant IMMS as 输入法管理服务(IMMS)
participant IMS as 输入法(IMS)
IMM->>IMMS: 显示、隐藏输入法
IMMS->>IMS: 显示、隐藏输入法
IMS-->>IMM: 返回输入信息
上述三个模块分别对应不同的进程,客户端 IMM 属于 App 应用进程,输入法 IMS 属于输入法自己的进程,输入法管理服务 IMMS 属于系统进程,三者之间需要通过 IPC 机制来进行通信, Androd中最根主要的 IPC 通信方式都就是 Binder 机制。
其中客户端 IMM 与 输入法 IMS 之间的交互已经通过 EditText 及其父类 TextView 实现,如果是自定义的编辑框,需要自行实现与输入法的交互。
输入法拉起流程
当点击一个输入框 EditText 将获得焦点,系统默认的输入法将会被拉起,EditText 继承自 TextView,关键实现在 TextView 中,拉起输入法的关键流程如下:
sequenceDiagram
autonumber
TextView->>TextView:onKeyDown/onTouchEvent
TextView->>TextView:viewClicked
TextView->>IMM:viewClicked
IMM->>IMM: checkFocus
IMM->>IMM: startInputInner
IMM->>IMMS: startInputOrWindowGainedFocus
IMMS->>IMMS: startInput
IMMS->>IMMS: startInputLocked
IMMS->>IMMS: startInputUncheckedLocked
IMMS->>IMMS: startInputInnerLocked
IMMS->>IMMS: bindCurrentInputMethodServiceLocked
IMMS->>IMMS: onServiceConnected
IMMS->>IMS: attachToken
IMMS->>IMS: createSession
IMS-->>IMMS: onSessionCreated
IMMS->>IMS: bindInput
IMMS->>IMS: startInput
IMMS->>IMS: showSoftInput
IMS->>IMS: showWindow
IMS->>IMS: showWindowInner
IMS->>IMS: onStartInputView
可知,输入法 IMS 的拉起可由按键和触摸事件触发,经由 IMM、IMMS 通过一系列 IPC 调用拉起系统默认输入法 IMS,上述流程中省略了一些操作,实际流程要更复杂,重点关注如下返回值:
1 | // InputBindResult.java |
当没有绑定输入法和 session 没创建的时候都在等待输入法绑定和 session 创建,当完成这两步之后客户端会再次请求输入法,为便于理解上图中没有体现这个过程,拉起 IMS 的关键代码如下:
1 | // InputMethodManagerService.java |
当绑定输入法 IMS 成功后将获去到 IInputMethod 的远程服务对象 mCurMethod,通过 mCurMethod 就可以操作 IInputMethod.aidl 中定义的相关接口了,如下:
1 |
|
到此,系统输入法从编辑器 EditText 获得焦点开始到输入法 IMS 服务绑定成功的流程结束,这里注意下 startInputUncheckedLocked 方法,后续 IMM、IMMS 和 IMS 三者之间的交互关系都在其中,最终调用 showSoftInput 显示输入法。
输入法管理服务(IMMS)
InputMethodManagerService 是用来管理输入法的系统服务,IMMS 属于系统服务的一部分,随着系统的启动而启动,IMMS 的初始化流程如下图所示:
sequenceDiagram
autonumber
SystemServer->>SystemServer:main
SystemServer->>SystemServer:run
SystemServer->>SystemServer:startOtherServices
SystemServer->>SystemServiceManager: startService
SystemServiceManager->>IMMS:onStart
IMMS->>SystemService:publishBinderService
SystemService->>ServiceManager: addService
ServiceManager->>ServiceManagerProxy:addServvice
ServiceManagerProxy->>BinderProxy:transact
如上图 IMMS 的初始化流程,从 SystemServer 到 IMMS 再到 ServiceManager,最后到 ServiceManagerProxy 这里完成 Java 层的系统服务注册流程,BinderProxy 是 native 层 IBinder 在 Java 层的代理对象,其初始化只能通过 Native 层的 javaObjectforIBinder 函数来初始化,不能直接创建,到此系统服务 IMMS 在 Java 层的初始化结束,Native 层的暂时不关注,下面附上 BinderProxy 的定义及注释供参考:
1 | /** |


IMMS 的核心实现是 IInputMethodManager.aidl 和 IInputSessionCallback.aidl,前者提供给 IMM 调用,后者提供给 IMS 调用,如下:
- IInputMethodManager.aidl:定义了操作输入法的公共接口对外提供给客户端
IMM,最常用的比如显示、隐藏、切换软键盘等。 - IInputSessionCallback.aidl: 用于允许输入法创建会话的时候通知
IMMS,之后IMMS就可以绑定输入法IMS了。
InputMethodManagerService 实现了 IInputMethodManager.aidl 提供给 IMM 使用,MethodCallback 实现了 IInputSessionCallback.aidl,用来回调 IMS 创建的 IInputMethodSession,关键流程如下:
sequenceDiagram
autonumber
IMMS->>IMMS: requestClientSessionLocked
IMMS->>IInputMethodWrapper: createSession
IInputMethodWrapper->>InputMethodSessionCallbackWrapper:sessionCreated
InputMethodSessionCallbackWrapper->>MethodCallback: sessionCreated
MethodCallback-->>IMMS: onSessionCreated
看下 IMMS 的 onSessionCreated 方法实现:
1 | void onSessionCreated(IInputMethod method, IInputMethodSession session, |
如上 onSessionCreated 会绑定客户端到此 IMMS 的关键流程结束。
输入法(IMS)
InputMethodService 为标准 UI 元素(输入视图、候选视图和全屏模式下运行)提供了一个基本框架,但如何使用它们取决于特定的实现者,其是自定义输入法的关键类,其本身是一个 Service 的派生类,如下:
1 | public class PinyinIME extends InputMethodService { |
自定义输入法要在 AndroidManifest.xml 中进行声明,参考如下:
1 | <service android:name=".PinyinIME" |
其中权限 BIND_INPUT_METHOD 的声明可以使之能够连接到系统,设置了一个与 android.view.InputMethod 操作匹配的 Intent。
IMS 的核心实现是 IInputMethod.aidl 和 IIInputMethodSession.aidl,前者提供给 IMMS 调用,后者提供给 IMM 调用,如下:
- IInputMethod.aidl:输入法
IMM是一个Service,其核心实现就是 IInputMethod.aidl 的实现IInputMethodWrapper\,提供了操作输入法的核心方法。 - IInputMethodSession.aidl:提供了客户端
IMM操作输入法的接口,IMM中存在IInputMethodSession类型的实例mCurMethod供其调用。
收到客户端 IMM 输入操作后,输入法 IMS 将会显示输入法布局,可以参考 SoftKeyboardView 的实现,输入法 IMS 的生命周期如下:

其关键生命周期如下:
- onBindInput:客户端
IMM绑定该输入法IMS的时候调用。 - onStartInput:用户在编辑框开始输入文字的时候调用。
- onCreateInputView:创建并返回输入区域的视图,第一次显示输入区域视图的时候调用,默认实现返回 null,可实现
onEvaluateInputViewShown来控制候显示输入区域视图,更改输入区域视图使用setInputView进行更改。 - onCreateCandidatesView:创建并返回显示候选词的视图,第一次显示候选词视图的时候调用,默认实现返回 null,可使用
setCandidatesViewShown方法控制候选词视图的显示,更改候选视图使用setCandidatesView进行更改。 - onStartInputView:当前页面的输入框获取了焦点时调用。
客户端(IMM)
InputMethodManager 主要用来处理当前应用程序与输入法之间的交互,每次只能运行一个输入法,多个应用程序使用输入法,确保获得焦点并保证只有一个应用程序在使用输入法,应用程序使用 Textview 及其子类默认实现了这种交互,也可以自定义文本编辑器来实现这种交互。
IMM 的核心实现是 IInputMethodClient.aidl 和 IInputContext.aidl,如下:
- IInputMethodClient.aidl:简单理解为
IMMS绑定IMS的时候通知IMM输入法已经准备好了可以进行绑定了,具体是由IMM内部实现,对应mClient。 - IInputContext.aidl:定义操作输入法编辑器
IME的方法,默认实现是EditableInputConnection。
下面看看 IMM 的初始化流程:
sequenceDiagram
ViewRootImpl->>WindowManagerGlobal: ViewRootImpl(context,display)
WindowManagerGlobal->>WindowManagerService: getWindowSession
WindowManagerService->>Session: openSession
Session->>InputMethodManagerService: addClient
可知,ViewRootImp 创建的时候会获取 IWindowSession,如果 IWindowSession 为空的时候,会通过 WindowManagerService 创建一个 IWindowSession ,其实现为上图中的 Session,在 Session 创建的时候调用 IMMS 的 addClient 将客户端 IMM 的关键实现 IInputMethodClient 和 IInputContext 添加到 IMMS 由 IMMS 统一维护。
IMM与IMMS的交互主要是 IInputMethodManager.aidl,使用时通过getSystemService获取input_method系统服务,也就是IMMS,之后就可以调用输入法管理器IMMS提供的公共接口了。IMM与IMS的交互主要是 IInputMethodSession.aidl,定义供客户端操作输入法的方法,IMMS请求IInputMethod创建IInputMethodSession,IMMS绑定客户端IMM的时候将IInputMethodSession传入IMM。
IMS、IMMS和IMM之间的交互
输入法(IMS)、输入法管理服务(IMMS)和客户端(IMM)之间的交互主要是通过一系列 aidl 进行交互的,关键 aidl 如下图所示:
sequenceDiagram
participant IMM as 客户端(IMM)
participant IMMS as 输入法管理服务(IMMS)
participant IMS as 输入法(IMS)
IMM->>IMMS: IInputMethodManager.aidl
IMMS->>IMM: IInputMethodClient.aidl
IMMS->>IMS: IInputMethod.aidl
IMS->>IMMS: IInputSessionCallback.aidl
IMS->>IMM: IInputContext.aidl
IMM->>IMS: IInputMethodSession.aidl
IMS、IMMS和IMM之间的交互如下:
IMM使用IInputMethodManager请求IMMS。IMMS绑定IMS获得操作输入法的相关接口IInputMethod。IMMS请求IMS创建IInputMethodSession。IMMS通过IInputMethodClient告知IMM当前IInputMethodSession。IMM和IMS通过IInputMethodSession和IInputContext交互。
IMM、IMMS 和 IMS 三者之间的交互都是 IPC 调用,对于使用者来说无需关注三者之间的复杂调用,如上就是 Android 机制下的输入法框架。