用户通常希望使用表情符号、贴纸和其他类型的 内容。在之前的 Android 版本中,软键盘(也称为 输入法,或 IME - 只能向应用发送 Unicode 表情符号。对于富媒体内容, 这些特定于应用的 API,不能在其他应用中使用,或者使用了 通过简单的分享操作发送图片 或剪贴板。
从 Android 7.1(API 级别 25)开始,Android SDK 包含 Commit Content API:为 IME 提供了一种通用方式, 直接将富媒体内容发布到应用中的文本编辑器。此 API 还适用于以下语言: v13 支持库(从修订版 25.0.0 开始)。我们建议使用 库,因为它包含可简化实现的辅助方法。
借助此 API,您可以构建即时通讯应用,以便接收来自任何来源的富媒体内容 以及可向任何应用发送丰富内容的键盘。Google 键盘 以及诸如Android 信息 Google 在 Android 7.1 中支持 Commit Content API,如图 1 所示。
本文档介绍了如何在 IME 和 。
工作原理
键盘图片插入需要 IME 和应用的参与。通过 以下序列介绍了图片插入过程中的各个步骤:
当用户点按
EditText
时, 编辑器会发送EditorInfo.contentMimeTypes
。IME 会读取支持的类型列表,并在编辑器可以接受的软键盘中显示内容。
当用户选择图片时,IME 会调用
commitContent()
并发送InputContentInfo
修改。commitContent()
调用类似于commitText()
调用,但适用于富媒体内容。InputContentInfo
包含一个 URI, 标识内容中的内容 provider。
此过程如图 2 所示:
为应用添加图片支持
若要接受来自 IME 的富媒体内容,应用必须告知 IME 它包含的内容类型。
接受并指定当收到内容时执行的回调方法。
以下示例演示了如何创建接受 PNG 的 EditText
图片:
Kotlin
var editText: EditText = object : EditText(this) { override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { var ic = super.onCreateInputConnection(outAttrs) EditorInfoCompat.setContentMimeTypes(outAttrs, arrayOf("image/png")) val mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this) if (mimeTypes != null) { EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes) ic = InputConnectionCompat.createWrapper(this, ic, outAttrs) } return ic } }
Java
EditText editText = new EditText(this) { @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { InputConnection ic = super.onCreateInputConnection(outAttrs); EditorInfoCompat.setContentMimeTypes(outAttrs, new String[]{"image/png"}); String[] mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this); if (mimeTypes != null) { EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes); ic = InputConnectionCompat.createWrapper(this, ic, outAttrs); } return ic; } };
以下是进一步说明:
本示例使用了支持库,因此其中有一些对
android.support.v13.view.inputmethod
而非android.view.inputmethod
。本示例创建了一个
EditText
,并替换了其onCreateInputConnection(EditorInfo)
方法修改InputConnection
。InputConnection
是 IME 与 在接收输入数据的应用。通话
super.onCreateInputConnection()
保留内置行为(发送和接收文本),并且 提供对InputConnection
的引用。setContentMimeTypes()
将支持的 MIME 类型列表添加到EditorInfo
。致电super.onCreateInputConnection()
,setContentMimeTypes()
之前。每当 IME 提交内容时,系统便会执行
callback
。方法onCommitContent()
引用了InputContentInfoCompat
, 该字段包含一个内容 URI。- 如果您的应用在 API 级别 25 上运行,则请求和发布权限
或更高版本的
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
标志由 IME 设置。否则,你已有权访问相应内容 URI,因为它是由 IME 或 content provider 授予的 不限制访问权限。如需了解详情,请参阅向 IME。
- 如果您的应用在 API 级别 25 上运行,则请求和发布权限
或更高版本的
createWrapper()
封装InputConnection
、修改后的EditorInfo
以及回调 放入新的InputConnection
并将其返回。
以下是推荐的做法:
不支持富媒体内容的编辑器不会调用
setContentMimeTypes()
,并且该用户保留自己的EditorInfo.contentMimeTypes
设置 发送至null
。如果
InputContentInfo
中指定的 MIME 类型,则编辑器会忽略此内容 都不匹配。富媒体内容不会影响文本位置,也不会受其影响 光标。使用内容时,编辑器可以忽略光标位置。
在编辑器的
OnCommitContentListener.onCommitContent()
方法,您可以异步返回true
,即使 然后再加载内容与在提交前可以在 IME 中修改的文本不同,富文本 立即提交。如果您要允许用户修改或删除 您需要自行实现逻辑
如需测试您的应用,请确保您的设备或模拟器具有可以 富媒体内容。您可以在 Android 7.1 或更高版本中使用 Google 键盘。
为 IME 添加图片支持
想要向应用发送富媒体内容的 IME 必须实现提交内容 API,如以下示例所示:
- 替换
onStartInput()
或onStartInputView()
并从目标中读取支持的内容类型列表 编辑器。以下代码段展示了如何检查目标编辑器是否接受 GIF 图片。
Kotlin
override fun onStartInputView(editorInfo: EditorInfo, restarting: Boolean) { val mimeTypes: Array<String> = EditorInfoCompat.getContentMimeTypes(editorInfo) val gifSupported: Boolean = mimeTypes.any { ClipDescription.compareMimeTypes(it, "image/gif") } if (gifSupported) { // The target editor supports GIFs. Enable the corresponding content. } else { // The target editor doesn't support GIFs. Disable the corresponding // content. } }
Java
@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 the corresponding content. } else { // The target editor doesn't support GIFs. Disable the corresponding // content. } }
- 当用户选择图片时,将内容提交到应用。避免调用
commitContent()
。 可能导致编辑器失去焦点。以下代码段展示了如何 来提交 GIF 图片。
Kotlin
// 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. fun commitGifImage(contentUri: Uri, imageDescription: String) { val inputContentInfo = InputContentInfoCompat( contentUri, ClipDescription(imageDescription, arrayOf("image/gif")), null ) val inputConnection = currentInputConnection val editorInfo = currentInputEditorInfo var flags = 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { flags = flags or InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION } InputConnectionCompat.commitContent(inputConnection, editorInfo, inputContentInfo, flags, null) }
Java
// 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 的创建者,您很可能必须实现自己的 content provider 才能
响应内容 URI 请求。例外情况是,如果您的 IME 支持内容,
来自现有内容提供方
MediaStore
。如需了解
构建内容提供程序时,请参阅内容
provider 和 file
provider 文档。
如果您要构建自己的 content provider,我们建议您不要将其导出
按设置
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,请确保您的设备或模拟器具有可以接收 IME 的应用 富媒体内容。您可以在 Android 7.1 或更高版本中使用 Google Messenger 应用。