Android输入法-图片键盘支持
图片键盘支持
图 1. 图片键盘支持示例
用户通常希望使用表情符号、贴纸和其他类型的富媒体内容进行通信。在之前的 Android 版本中,软键盘(也称为输入法或 IME)只能向应用发送 Unicode 表情符号。对于富媒体内容,应用必须构建不能在其他应用中使用的应用专用 API,或者使用通过轻松分享操作或剪贴板发送图片等解决方法。
在 Android 7.1(API 级别 25)中,Android SDK 包含 Commit Content API,它提供了一种通用方式,使 IME 可以将图片和其他富媒体内容直接发送到应用中的文本编辑器。从版本 25.0.0 开始,v13 支持库中也提供此 API。我们建议使用支持库,因为它在搭载 Android 3.2(API 级别 13)及更高版本的设备上运行,并且包含可简化实现的帮助程序方法。
借助此 API,您可以构建可接受来自任意键盘的富媒体内容的即时通讯应用,以及可向任何应用发送富媒体内容的键盘。Google 键盘和 Google Messenger 等应用在 Android 7.1 中支持 Commit Content API(参见图 1)。
本页介绍了如何在 IME 和应用中实现 Commit Content API。
工作原理
键盘图片插入需要 IME 和应用的参与。以下序列描述了图片插入流程中的各个步骤:
-
当用户点按
EditText时,编辑器会发送其在EditorInfo.contentMimeTypes中接受的 MIME 内容类型列表。 -
IME 会读取支持的类型列表,并在编辑器可以接受的软键盘中显示内容。
-
当用户选择一张图片时,IME 会调用
commitContent(),并将InputContentInfo发送到编辑器。commitContent()调用类似于commitText()调用,但适用于富媒体内容。InputContentInfo包含用于识别内容提供程序中的内容的 URI。然后,您的应用可以请求权限并从 URI 中读取内容。

为应用添加图片支持
要接受来自 IME 的富媒体内容,应用必须告知 IME 它所接受的内容类型,并指定在接收到内容时执行的回调方法。以下示例展示了如何创建接受 PNG 图片的 EditText:
EditText editText = new EditText(this) { @Override public InputConnection onCreateInputConnection(EditorInfo editorInfo) { final InputConnection ic = super.onCreateInputConnection(editorInfo); EditorInfoCompat.setContentMimeTypes(editorInfo, new String [] {"image/png"}); final InputConnectionCompat.OnCommitContentListener callback = new InputConnectionCompat.OnCommitContentListener() { @Override public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts) { // read and display inputContentInfo asynchronously if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { try { inputContentInfo.requestPermission(); } catch (Exception e) { return false; // return false if failed } } // read and display inputContentInfo asynchronously. // call inputContentInfo.releasePermission() as needed. return true; // return true if succeeded } }; return InputConnectionCompat.createWrapper(ic, editorInfo, callback); } };
此过程较为复杂,下面我们来详细说明一下。
-
该示例使用了支持库,因此存在一些对
android.support.v13.view.inputmethod(而非android.view.inputmethod)的引用。 -
该示例创建了一个
EditText,并替换了其onCreateInputConnection(EditorInfo)方法,以修改InputConnection。InputConnection 是 IME 与正在接收其输入的应用之间的通信渠道。 -
调用
super.onCreateInputConnection()会保留内置行为(发送和接收文本)并提供对 InputConnection 的引用。 -
setContentMimeTypes()将支持的 MIME 类型列表添加到EditorInfo。请务必在setContentMimeTypes()之前调用super.onCreateInputConnection()。 -
每当 IME 提交内容时,系统便会执行
callback。方法onCommitContent()引用了包含内容 URI 的InputContentInfoCompat。- 如果您的应用搭载 API 级别 25 或更高级别,且
INPUT_CONTENT_GRANT_READ_URI_PERMISSION标记由 IME 设置,则您应请求和发布权限。否则,您应该已经可以访问内容 URI,要么因为它是 IME 所授予的,要么内容提供程序不限制访问。如需了解详情,请参阅为 IME 添加图片支持。
- 如果您的应用搭载 API 级别 25 或更高级别,且
-
createWrapper()将 inputConnection、修改后的 editorInfo 及回调封装到新的 InputConnection 中,并将其返回。
下面是一些推荐做法:
-
不支持富媒体内容的编辑器不应调用
setContentMimeTypes(),应将它们的EditorInfo.contentMimeTypes设置为null。 -
如果
InputContentInfo中指定的 MIME 类型与编辑器接受的所有类型均不匹配,则该编辑器应忽略此内容。 -
富媒体内容不会影响文本光标的位置,也不会受其影响。使用内容时,编辑器可以忽略光标位置。
-
在编辑器的
OnCommitContentListener.onCommitContent()方法中,您甚至可以在加载内容之前以异步方式返回true。 -
跟可于提交前在 IME 中修改的文本不同,富媒体内容会立即提交。请注意,如果您希望使用户能够修改或删除内容,则您必须自行实现逻辑。
要测试应用,请确保您的设备或模拟器具有能够发送富媒体内容的键盘。您可以在 Android 7.1 或更高版本中使用 Google 键盘。
为 IME 添加图片支持
想要向应用发送富媒体内容的 IME 必须实现 Commit Content API,如下所示:
- 替换
onStartInput()或onStartInputView(),并从目标编辑器中读取支持的内容类型列表。以下代码段展示了如何检查目标编辑器是否接受 GIF 图片。
@Override public void onStartInputView(EditorInfo info, boolean restarting) { String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo); boolean gifSupported = false; for (String mimeType : mimeTypes) { if (ClipDescription.compareMimeTypes(mimeType, "image/gif")) { gifSupported = true; } } if (gifSupported) { // the target editor supports GIFs. enable corresponding content } else { // the target editor does not support GIFs. disable corresponding content } }
- 当用户选择图片时,向应用提交内容。如果用户正在撰写文本,则避免调用
commitContent(),否则可能导致编辑器失去焦点。以下代码段展示了如何提交 GIF 图片。
/** * Commits a GIF image * * @param contentUri Content URI of the GIF image to be sent * @param imageDescription Description of the GIF image to be sent */ public static void commitGifImage(Uri contentUri, String imageDescription) { InputContentInfoCompat inputContentInfo = new InputContentInfoCompat( contentUri, new ClipDescription(imageDescription, new String[]{"image/gif"}), null ); InputConnection inputConnection = getCurrentInputConnection(); EditorInfo editorInfo = getCurrentInputEditorInfo(); Int flags = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION; } InputConnectionCompat.commitContent( inputConnection, editorInfo, inputContentInfo, flags, null); }
-
作为 IME 的创建者,您很可能需要实现自己的内容提供程序来响应内容 URI 请求。例外情况是,如果您的 IME 支持来自
MediaStore等现有内容提供程序的内容,则无需实现自己的内容提供程序。如需了解如何构建内容提供程序,请参阅内容提供程序和文件提供程序文档。 -
如果您要构建自己的内容提供程序,我们建议您不要将其导出(将 android:exported 设置为
false),而应将 android:grantUriPermission 设置为true,以在提供程序中启用权限授予功能。然后,IME 会在内容提交时授予访问内容 URI 的权限。您可以通过以下两种方式执行此操作:-
对于 Android 7.1(API 级别 25)及更高版本,调用
commitContent()时,将标记参数设置为INPUT_CONTENT_GRANT_READ_URI_PERMISSION。然后,应用接收到的InputContentInfo对象可以通过调用requestPermission()和releasePermission()请求和发布临时读取权限。 -
对于 Android 7.0(API 级别 24)及更低版本,
INPUT_CONTENT_GRANT_READ_URI_PERMISSION会被忽略,因此您需要手动向内容授予权限。其中一种方式是使用grantUriPermission(),但您可以实现满足您的要求的自有机制。
-
要测试您的 IME,请确保您的设备或模拟器具有能够接收富媒体内容的应用。您可以在 Android 7.1 或更高版本中使用 Google Messenger 应用。

浙公网安备 33010602011771号