繁体   English   中英

Android - 无法打开内容:file:///storage/emulated/0

[英]Android - Unable to open content: file:///storage/emulated/0

我有一个带有九个补丁图像背景的小部件。 图像保存在 /sdcard/mydir/bgs 中。

当我尝试使用 setImageViewUri 方法加载图像时,出现此错误:

Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs

..

然后

...

open failed: EACCES (Permission denied)

这仅出现在主屏幕上,并且仅适用于 Nexus 10 和 Nexus 7(最新的启动器 4.4 不存在此错误)。 我的应用程序上也有一些 RemoteViews,并且一切正常。

我还在清单中添加了 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE。

我该如何解决?

更新:我检查了 setImageViewUri 方法,发现它改变了我的文件的路径。

if (value != null) {
            // Resolve any filesystem path before sending remotely
            value = value.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                value.checkFileUriExposed("RemoteViews.setUri()");
            }
        }

此方法接收我的值 (/sdcard/mydir/bgs) 并将其更改为 (storage/emulated/0/sdcard/mydir/bgs)。 但是这个文件不存在通过 adb 进入系统。

与 Lollipop 一样,Google 引入了一种新方法,可以明确授予应用程序您希望它们在您的设备上使用的权限,并禁用您想要拒绝该应用程序的应用程序。 如果您注意到,在您的 android 监视器中,日志会显示

java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)

EACCESS permission denied是 java 臭名昭著的FileNotFoundException的原因。

要解决此问题,只需转到您的应用权限并为您的应用启用存储

在此处输入图像描述

你需要

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

在你的清单中。

看来setImageViewUri与 file:// uris 一起使用不再安全。

为什么?

Jellybean 引入了READ_EXTERNAL_STORAGE权限。 想要从外部存储读取的应用程序必须持有此权限。 在 KitKat 之前,默认情况下没有强制执行此操作。

启动器不持有此权限。 事实上,您不能保证您附加到的任何 RemoteView 都拥有该权限。 这使得使用 setImageViewUri 变得不安全,因为您不知道远程图像视图是否能够读取给定的 uri。

现在怎么办?

选项 1:使用 setImageViewBitmap。

由于活页夹交易失败,您可能已放弃此选项。 这些技巧只是确保您的图像小于 1 MB。 这并不像听起来那么难。 您可以准确计算图像的大小。 例如,如果您使用的是 ARGB_8888 图像,这意味着每个像素需要 4 个字节。 我们可以通过以下方式计算最大尺寸:

1 Mb = 1048576 字节 = 262144 像素 = 512 x 512 图像

当然,您可以使用 RGB_565 从中挤出更多,以获得 2 倍的像素。

另请注意,如果您的小部件很小,您可能不需要大图像。 您的 appwidget 可以通过以下方式询问其特定选项:

Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetIds[i]);

int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);

int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);

请注意,返回的值是倾角而不是像素,因此您需要将它们转换为缩放位图。

选项 2:使用内容提供者

如果由于某种原因您仍然不喜欢 IPC 限制,您可以随时构建自定义内容提供程序。 将该 uri 传递到 setImageViewUri 中,您应该可以开始了。

路径切换呢?

路径切换不是真正的问题。 看起来这是一个问题,但仿真实际上工作正常。 尝试在//storage/emulated/0/sdcard/mydir/bgs中创建一个文件,该文件将创建得很好。

您会注意到,虽然异常是 FileNotFoundException,但消息是 Permission Denied。

我认为您正在手动输入 SD 卡路径。 您应该获得如下存储路径,而不是手动输入 SD 卡路径:

File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM