我正在研究将 Gboard 图像支持添加到我们的应用程序中。
我有以下三个具体问题。
已在https://developer.android.com/guide/topics/text/image-keyboard.html上查看官方文档
不过,有些奇怪的事情正在发生。
当用户点击 EditText 时,编辑器会发送在 EditorInfo.contentMimeTypes 中接受的 MIME 内容类型列表。
IME 读取支持的类型列表,并在软键盘中显示编辑器可接受的内容。
我读到此内容还意味着,如果应用程序未设置 EditorInfo.contentMimeType,则键盘将无法启用用于插入图像的 UI。
但实际情况并非如此。
首先,我看到的是 GBoard 显示了几乎所有 EditText 的插入图像 UI,大概是基于其 inputType。
我尝试创建一个 EditText 子类,重写 onCreateInputConnection 并确保 EditorInfo.contentMimeType -> 插入图像 UI 确实显示。
我们的应用程序中有数十个 EditText 输入字段(可能更多),位于不同的屏幕上。对于绝大多数人来说,插入动画 GIF 没有任何意义。
问题#1 - 如何才能阻止这种情况(如果可以的话)?
顺便说一下,这很容易在几乎任何应用程序、几乎任何输入字段中进行检查。例如,在 Gmail 应用程序的搜索栏中。或者在 Google Chrome 中的 URL 输入栏中。
这对于大多数应用程序来说是无害的 - 如果您在不支持图像输入的输入字段中选择 GIF(例如上面的示例,Gmail 和 Chrome),GBoard 会显示一条“类似于吐司”的消息,指出“此文本字段不支持图像输入”。不支持从键盘插入 GIF”。
好的但是:
作为后备方案,当 GBoard 无法通过 InputConneciton 发送选定的 GIF 时 -> 它会尝试启动仅限于应用程序包的 ACTION_SEND 意图,并使用表示图像的 URL。
我们的应用程序(电子邮件应用程序)在其 ACTION_SEND 清单中确实有一个意图过滤器,使用户能够通过电子邮件共享“内容”。像图库图像、文件管理器中的文件之类的东西,任何东西。
因此,GBoard 最终启动了带有 ACTION_SEND 和图像 URL 的“电子邮件撰写屏幕”。
这会导致另外两个问题:
首先,它会让用户感到困惑
假设他/她尝试将 GIF 插入应用程序中的“某些”EditText 中。
然后,由于 ACTION_SEND - “哇,发生了什么”,他/她将被带到应用程序的“消息撰写”屏幕。
问题#2 - 如何才能阻止这种情况(如果可以的话)?
其次,据我所知,无法使用任何方法打开图像的 URI。
我试过了:
cr.openFileDescriptor(uri, "r");
cr.openAssetFileDescriptor(uri, "r");
cr.openInputStream(uri);
cr.query(uri, null, null, null, null);
Run Code Online (Sandbox Code Playgroud)
所有这些都会因“无效 URI”等变体而失败。
我确实明白,通过为我们想要支持 GIF 的一个或几个输入字段实现一个 InputConnectionWrapper,我们可以直接从 inputContentInfo 请求权限,如文档中所述。
我正在谈论一种不同的情况 - 我会重申 - 当用户尝试将 GIF 插入我们应用程序中的“其他”EditText 时,GBoard 使用 GIF 的 URI 和 ACTION_SEND 启动我们的“消息撰写”活动。
目前,我们的代码尝试以与其他任何方式相同的方式处理此 URI(例如,当用户将 Google Photos 中的照片分享到我们的应用程序中时),但打开此 URI 失败,因此用户不仅会意外地出现在撰写屏幕上,但随后也出现错误,表明我们无法打开/复制“附件”。
问题 #3 - 使用 ACTION_SEND 发送的 GBoard 图像 URI 是否可以使用“标准”ContentResolver 方法打开?
4 月 12 日,更新“问题#3”(无法打开直播)。
我们的应用程序在其清单中使用sharedUserId。
删除sharedUserId并且不进行其他更改,这样这些动画图像URI现在可以在输入连接回调和ACTION_SEND中使用cr.openInputStream正常打开。
虽然可能有理由不使用sharedUserId,但我们的应用程序自2012年左右就开始使用,并且不可能仅因为此功能而删除它(因为这会阻止更新)。
URI 如下所示,应用程序的包名称编码在参数中:
内容://com.google.android.inputmethod.latin.inputcontent/inputContent?fileName=%2Fdata%2Fuser_de%2F0%2Fcom.google.android.inputmethod.latin%2Ffiles%2Fgif20152912710254894520&packageName=org.kman.AquaMail&mimeType=image%2Fgif
所以问题#3现在被替换为
问题 #4 - 我们如何向 Google 报告此错误(sharedUserId 导致图像 URI 无法打开)?
SEND正如您所说,当视图不接受时,Gboard 会发送意图Gifs。问题是,我测试的其他键盘也发生了同样的情况,所以这似乎不是 Gboard 的错误。
所以我想出的解决方案是忽略当前键盘的 SEND 意图。
当我在接收器活动中收到意图时,我会检查数据是否来自键盘,为此我使用以下方法,它也可能对您有所帮助:
private boolean isClipDataAuthorityValid(@NonNull ClipData clipData) {
if (clipData.getItemCount() == 0) {
return true;
}
Uri uri = clipData.getItemAt(0).getUri();
if (uri == null) {
return true;
}
String authority = uri.getAuthority();
if (TextUtils.isEmpty(authority)) {
return true;
}
String defaultInputMethod = Settings.Secure.getString(getContentResolver(), "default_input_method");
if (TextUtils.isEmpty(defaultInputMethod)) {
return true;
}
String keyboardPackage = defaultInputMethod.split("/")[0];
try {
ProviderInfo[] providers = getPackageManager().getPackageInfo(keyboardPackage, PackageManager.GET_PROVIDERS).providers;
if (providers == null || providers.length == 0) {
return true;
}
//Check if the authority of the given clipdata's uri matches any of the keyboards's provider authority
for (ProviderInfo provider : providers) {
if (TextUtils.equals(authority, provider.authority)) {
return false;
}
}
} catch (PackageManager.NameNotFoundException e) {
//Do nothing
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
该方法接收一个剪辑数据,可以使用 轻松从意图中提取该剪辑数据intent.getClipData()。它获取当前键盘,检查其提供程序,将其权限与剪辑数据的 Uri 权限进行匹配,如果剪辑数据来自键盘,则返回 false。
目前,我无法找到另一个通用解决方案,因为我测试的键盘显示了不同的结果。
我希望这有帮助 :)
| 归档时间: |
|
| 查看次数: |
2463 次 |
| 最近记录: |