ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Fossify Keyboard 源码解析:InputMethodService 生命周期与键盘实现原理完全指南

Fossify Keyboard 源码解析:InputMethodService 生命周期与键盘实现原理完全指南

【免费下载链接】Keyboard

Easy keyboard for inserting all kinds of texts, special characters and numbers.

项目地址:https://gitcode.com/gh_mirrors/keyboard2/Keyboard
点击查看免费下载

Fossify Keyboard 是一款完全离线、注重隐私的开源 Android 输入法,支持多种语言布局、内置剪贴板、表情面板与深色主题。它最核心的实现就是一个继承自 Android 系统类InputMethodService的服务——本文将带你从源码层面拆解Fossify Keyboard 的 InputMethodService 输入服务生命周期,看懂一个自定义键盘从注册、启动到把按键变成文字的完整链路。

一、InputMethodService:键盘应用的心脏

在 Android 里,所有第三方输入法都必须实现一个InputMethodService。系统(输入法管理器 IMS)会负责启动、绑定和切换它,而键盘 UI 与逻辑全部由开发者自己写。

Fossify Keyboard 的核心就集中在一个文件里:

  • 输入服务入口:SimpleKeyboardIME.kt
class SimpleKeyboardIME : InputMethodService(), OnKeyboardActionListener { ... }

它同时实现了OnKeyboardActionListener接口(见 OnKeyboardActionListener.kt),这样键盘视图在捕捉到触摸后,就能通过onPress、onKey、onActionUp等回调把事件交还给服务本身处理。

简单记忆:Service 管"状态与文字",View 管"显示与触摸",两者靠监听器接口互相回调。

二、服务注册:两步声明缺一不可

要让系统识别出这是一个输入法,Fossify Keyboard 做了两件标准动作。

1. 在清单中声明<service>

在 AndroidManifest.xml 中,服务被声明并绑定了一个特殊的元数据:

<service android:name=".services.SimpleKeyboardIME" android:exported="true" android:permission="android.permission.BIND_INPUT_METHOD"> <meta-data android:name="android.view.im" android:resource="@xml/method" /> <intent-filter> <action android:name="android.view.InputMethod" /> </intent-filter> </service>

其中BIND_INPUT_METHOD权限和android.view.InputMethod动作告诉系统"这是一个输入方法",而meta-data指向的描述文件才是真正的"身份证"。

2. 编写输入法描述文件method.xml

method.xml 定义了输入法的图标、设置页与子类型:

<input-method android:icon="@mipmap/ic_launcher" android:settingsActivity="org.fossify.keyboard.activities.SettingsActivity" android:supportsInlineSuggestions="true"> <subtype android:imeSubtypeMode="Keyboard" /> </input-method>

settingsActivity决定了用户点"输入法设置"时跳转到哪里(对应 SettingsActivity.kt)。

三、生命周期:从创建到按键的完整链路

InputMethodService提供了一系列回调,Fossify Keyboard 按需重写了其中关键的几个,它们共同构成了键盘的"一生":

回调方法触发时机主要职责
onInitializeInterface键盘框架初始化后注册设置变化监听,实现"改设置即时生效"
onCreateInputView需要显示键盘 UI 时构建并返回键盘视图树
onStartInput聚焦到某个输入框时读取输入类型、构建对应键盘
onStartInputView键盘视图显示后应用背景色、适配刘海屏
onKey用户按下按键时把按键码转换为文字并写入输入框

1. 构建键盘视图(onCreateInputView)

override fun onCreateInputView(): View { binding = KeyboardViewKeyboardBinding.inflate(layoutInflater) keyboardView = binding.keyboardView.apply { setKeyboard(keyboard!!) setEditorInfo(currentInputEditorInfo) setupEdgeToEdge() mOnKeyboardActionListener = this@SimpleKeyboardIME } return binding.root }

它把布局 keyboard_view_keyboard.xml 膨胀成视图树。这个布局里包含工具栏、表情面板、剪贴板面板,以及真正负责按键显示的自定义视图MyKeyboardView(见 MyKeyboardView.kt)。注意最后把mOnKeyboardActionListener指向了自己——这就是"视图回调服务"的接线点。

2. 感知输入框(onStartInput)

每当用户聚焦到某个输入框,系统都会回调它。Fossify Keyboard 在这里判断输入框类型,动态切换键盘布局:

override fun onStartInput(attribute: EditorInfo?, restarting: Boolean) { inputTypeClass = attribute!!.inputType and TYPE_MASK_CLASS enterKeyType = attribute.imeOptions and (IME_MASK_ACTION or IME_FLAG_NO_ENTER_ACTION) keyboard = createNewKeyboard() keyboardView?.setKeyboard(keyboard!!) ... }

createNewKeyboard()会根据输入类型选择不同的布局资源:数字框用keys_numbers、电话框用keys_phone、日期框用符号键盘,其余默认用字母键盘。这就是为什么在数字输入框里,键盘会自动变成数字布局。

四、从按键到文字:触摸、回调与 commitText

1. 视图负责"点中了哪个键"

MyKeyboardView在onTouchEvent中把触摸坐标映射到具体按键,找到后调用监听器。核心逻辑非常简洁:

private fun getPressedKeyIndex(x: Int, y: Int): Int { return mKeys.indexOfFirst { it.isInside(x, y) } } private fun detectAndSendKey(index: Int, x: Int, y: Int, eventTime: Long) { if (index != NOT_A_KEY && index in mKeys.indices) { mOnKeyboardActionListener!!.onKey(mKeys[index].code) } }

isInside(x, y)是MyKeyboard.Key里的几何判定(见 MyKeyboard.kt),它判断坐标是否落在按键矩形内。命中后就把按键码code通过onKey传回给服务。

2. 服务负责"把键变成字"

服务的onKey是真正的"输入引擎"。它拿到currentInputConnection(通往输入框的桥梁),再根据按键码决定写文字、删字符还是执行回车:

override fun onKey(code: Int) { val inputConnection = currentInputConnection when (code) { MyKeyboard.KEYCODE_DELETE -> { inputConnection.deleteSurroundingText(count, 0) // 退格 } MyKeyboard.KEYCODE_ENTER -> { inputConnection.performEditorAction(imeOptionsActionId) // 回车/搜索/发送 } else -> { inputConnection.commitText(codeChar.toString(), 1) // 提交字符 updateShiftKeyState() } } }

其中commitText是关键 API:它把字符串插入到光标处,是键盘与输入框之间最核心的通信方式。退格键则用deleteSurroundingText删除,回车键用performEditorAction触发"搜索/发送"等动作。

3. 键盘数据来自 XML

MyKeyboard在构造时会解析一份布局 XML(如 keys_letters_english_qwerty.xml),把<Row>、<Key>标签逐行逐键读进内存,算出每个键的坐标、宽高与按键码。这也意味着:想新增一种语言或键盘布局,往往只需再写一份 XML,这也是 Fossify Keyboard 支持几十种语言的秘诀。

五、动态响应:让设置"改完即生效"

键盘是一个长期存活的组件,用户随时可能去改主题、换语言。Fossify Keyboard 在onInitializeInterface里注册了设置监听,一旦相关键值变化就立即刷新视图:

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { if (key in arrayOf(SHOW_KEY_BORDERS, KEYBOARD_LANGUAGE, HEIGHT_PERCENTAGE, ...)) { keyboardView?.setupKeyboard() updateBackgroundColors() } }

配合onUpdateSelection(光标/选区变化时刷新 Shift 状态),键盘始终能跟上输入框的最新状态。这套"监听 + 即时重建"的思路,是自定义InputMethodService里很值得借鉴的工程实践。

小结

回顾 Fossify Keyboard 对InputMethodService的使用,可以总结出一条清晰的主线:

  • 注册:AndroidManifest.xml+method.xml向系统声明"我是一名输入法"
  • 创建:onCreateInputView搭好键盘视图,并把监听器指向自身
  • 启动:onStartInput读取输入框类型,构建匹配的语言/数字键盘
  • 输入:MyKeyboardView命中按键 →onKey回调 →commitText写入文字
  • 响应:设置监听 + 选区更新,让键盘始终保持最新状态

理解这条生命周期链路,你就掌握了 Android 自定义键盘最核心的骨架,无论是移植功能还是开发自己的输入法,都能从 Fossify Keyboard 这份清晰、克制的源码里获得大量参考。

【免费下载链接】Keyboard

Easy keyboard for inserting all kinds of texts, special characters and numbers.

项目地址:https://gitcode.com/gh_mirrors/keyboard2/Keyboard
点击查看免费下载
上一篇:RepoBrain rb-ask实战:如何问出带文件路径+行号的地面化代码答案
下一篇:如何写出你的第一个酒馆脚本:JS-Slash-Runner 脚本库、编辑器与导入导出全流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表