FileUriExposedException: file:///storage/emulated/0/Acquisition/storage exposed beyond app through Intent.getData()
时间: 2023-11-19 21:53:45 浏览: 331
FileUriExposedException是Android N(7.0)及以上版本中的一个安全特性,它会在你的应用程序中使用file:// URI时抛出异常。这是因为在Android N中,应用程序之间的访问权限更加严格,如果你使用file:// URI来共享文件,那么你的应用程序将会抛出FileUriExposedException异常。为了解决这个问题,你需要使用FileProvider来共享文件。FileProvider是一个特殊的ContentProvider,它允许你共享文件和私有目录,同时保护你的应用程序不受其他应用程序的攻击。
相关问题
20:22:12.333/E: 方法 "app.startActivity" 调用失败. file:///storage/emulated/0/Movies/1f490abdf275d320320ca508dad19b1d.mp4 exposed beyond app through Intent.getData(). android.os.FileUriExposedException: file:///storage/emulated/0/Movies/1f490abdf275d320320ca508dad19b1d.mp4 exposed beyond app through Intent.getData() (/data/user/0/org.autojs.autojs6/cache/tmp-scripts/tmp-1753446132164.js#17) 方法 "app.startActivity" 调用失败. file:///storage/emulated/0/Movies/1f490abdf275d320320ca508dad19b1d.mp4 exposed beyond app through Intent.getData(). android.os.FileUriExposedException: file:///storage/emulated/0/Movies/1f490abdf275d320320ca508dad19b1d.mp4 exposed beyond app through Intent.getData() at /data/user/0/org.autojs.autojs6/cache/tmp-scripts/tmp-1753446132164.js:17:0
<think>我们注意到用户的问题是关于在Auto.js6中使用app.startActivity打开视频文件时出现FileUriExposedException异常。根据引用[1]和引用[2]的内容,这个异常通常发生在Android 7.0(API 24)及以上版本中,因为Google禁止使用file://URI跨应用共享文件,而需要使用FileProvider生成content://URI。
在Auto.js6中,我们可以通过以下步骤解决:
1. 在项目中配置FileProvider。
2. 在脚本中根据Android版本使用不同的方式生成URI。
但是,Auto.js6环境并没有提供直接使用FileProvider的方法,因此我们需要自己实现。我们可以参考引用[2]中的Java代码,将其转换为Auto.js的JavaScript代码。
具体步骤:
1. 检查Android版本,如果大于等于24(Android 7.0),则使用FileProvider生成URI;否则,使用普通的Uri.fromFile。
2. 设置Intent的action为Intent.ACTION_VIEW,并设置数据和类型(视频类型为"video/*")。
3. 对于Android 7.0及以上,需要授予URI读取权限(FLAG_GRANT_READ_URI_PERMISSION)。
然而,在Auto.js中,我们无法直接使用FileProvider.getUriForFile,因为我们需要在Auto.js的AndroidManifest.xml中声明FileProvider,而Auto.js并没有提供这样的接口。因此,我们可以尝试使用Auto.js内置的app.viewFile方法,它内部已经处理了FileProvider的问题。
但是,如果用户坚持使用app.startActivity,我们可以尝试另一种方法:使用Auto.js提供的FileProvider的authority(根据Auto.js的源码,其authority为"org.autojs.autojs.fileprovider")。不过,这依赖于Auto.js内部实现,可能不是官方推荐做法。
另一种方法是使用MediaStore获取视频的Content URI,但这需要查询媒体库,且视频文件可能不在媒体库中。
因此,我们推荐两种方法:
方法一:使用app.viewFile(内部已经处理了FileProvider),简单可靠。
方法二:自己构造Intent,并使用Auto.js的FileProvider(authority为"org.autojs.autojs.fileprovider")。
下面分别给出两种方法的代码:
方法一(推荐):
```javascript
// 指定视频文件路径
var videoPath = "/sdcard/DCIM/Camera/example.mp4";
app.viewFile(videoPath);
```
方法二:使用app.startActivity并处理FileProvider
```javascript
// 指定视频文件路径
var videoPath = "/sdcard/DCIM/Camera/example.mp4";
var intent = new Intent(Intent.ACTION_VIEW);
var file = new java.io.File(videoPath);
// 判断Android版本
if (android.os.Build.VERSION.SDK_INT >= 24) {
// 使用FileProvider,authority为Auto.js的FileProvider
var uri = androidx.core.content.FileProvider.getUriForFile(
context,
"org.autojs.autojs.fileprovider",
file
);
intent.setDataAndType(uri, "video/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent.setDataAndType(android.net.Uri.fromFile(file), "video/*");
}
// 启动Activity
app.startActivity(intent);
```
注意:方法二中的authority字符串"org.autojs.autojs.fileprovider"是Auto.js内部使用的,如果Auto.js版本更新可能会改变,但当前版本(4.1.1)和6.x版本都是这个值。
另外,需要确保已经获取了存储权限。
完整脚本示例(包含权限请求):
```javascript
auto.waitFor();
// 请求存储权限
if (!runtime.isGranted()) {
runtime.requestPermissions(["android.permission.READ_EXTERNAL_STORAGE"]);
}
var videoPath = "/sdcard/DCIM/Camera/example.mp4";
// 检查文件是否存在
if (!files.exists(videoPath)) {
toast("视频文件不存在");
exit();
}
// 方法一:使用app.viewFile(推荐)
// app.viewFile(videoPath);
// 方法二:使用自定义Intent
var context = context || $autojs.androidContext;
var Intent = android.content.Intent;
var intent = new Intent(Intent.ACTION_VIEW);
var file = new java.io.File(videoPath);
if (android.os.Build.VERSION.SDK_INT >= 24) {
// 使用FileProvider
var FileProvider = androidx.core.content.FileProvider;
var uri = FileProvider.getUriForFile(context, "org.autojs.autojs.fileprovider", file);
intent.setDataAndType(uri, "video/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent.setDataAndType(android.net.Uri.fromFile(file), "video/*");
}
// 启动Activity
app.startActivity(intent);
```
注意:方法二需要Auto.js Pro版本(因为使用了androidx)?实际上,Auto.js6已经内置了androidx支持。
如果运行方法二时出现FileProvider相关的错误,可能是因为Auto.js的FileProvider在AndroidManifest.xml中配置的路径与你的文件路径不匹配。Auto.js的FileProvider配置如下(在源码中):
```
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="org.autojs.autojs.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
```
而file_provider_paths.xml中配置了多个路径,包括外部存储根目录:
```xml
<paths>
<external-path name="external" path="." />
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-files-path name="external-files" path="." />
<external-cache-path name="external-cache" path="." />
</paths>
```
因此,对于存储在/sdcard/下的文件,我们可以使用external-path,所以上述方法二应该是可行的。
如果仍然遇到问题,请使用推荐的方法一(app.viewFile)。
最后,我们给出一个完整的脚本,使用推荐的方法一:
```javascript
auto.waitFor();
// 请求存储权限
if (!runtime.isGranted()) {
runtime.requestPermissions(["android.permission.READ_EXTERNAL_STORAGE"]);
}
var videoPath = "/sdcard/DCIM/Camera/example.mp4";
if (files.exists(videoPath)) {
app.viewFile(videoPath);
} else {
toast("视频文件不存在: " + videoPath);
}
```
这样,就可以避免FileUriExposedException异常。
注意:在Android 10及以上,可能还需要在脚本开头加上以下代码以适配作用域存储:
```javascript
// 对于Android 10及以上,使用作用域存储
if (device.sdkInt >= 29) {
// 如果文件在外部存储的公共目录(如DCIM)下,则不需要特别处理,因为app.viewFile内部会处理
}
```
如果视频文件在非公共目录(例如应用私有目录),则需要使用MediaStore扫描或者使用FileProvider,但app.viewFile方法已经处理了这些情况。
因此,我们推荐使用app.viewFile方法。
相关问题:
1. 如何在Auto.js6中处理Android 10的作用域存储?
2. Auto.js6的FileProvider支持哪些路径?
3. 如何通过Intent打开其他类型的文件(如PDF)?</think>在 Auto.js6 中使用 `app.startActivity()` 打开视频文件时出现 `FileUriExposedException` 异常,是由于 Android 7.0+ 的安全限制导致的。以下是完整解决方案:
### 解决方案代码
```javascript
auto.waitFor();
// 请求存储权限
if (!runtime.isGranted()) {
runtime.requestPermissions(["android.permission.READ_EXTERNAL_STORAGE"]);
}
// 指定视频文件路径
var videoPath = "/sdcard/DCIM/Camera/example.mp4";
// 检查文件是否存在
if (!files.exists(videoPath)) {
toast("视频文件不存在");
exit();
}
// 创建 Intent
var Intent = android.content.Intent;
var intent = new Intent(Intent.ACTION_VIEW);
// 处理不同 Android 版本
if (device.sdkInt >= 24) { // Android 7.0+
// 使用 FileProvider
var FileProvider = androidx.core.content.FileProvider;
var context = $autojs.androidContext;
// 获取 URI (使用 Auto.js 内置的 FileProvider)
var uri = FileProvider.getUriForFile(
context,
"org.autojs.autojs.fileprovider", // Auto.js 的默认 authority
new java.io.File(videoPath)
);
// 添加权限标志
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "video/*");
} else {
// Android 7.0 以下版本
intent.setDataAndType(
android.net.Uri.parse("file://" + videoPath),
"video/*"
);
}
// 启动 Activity
try {
app.startActivity(intent);
} catch (e) {
toast("打开失败: " + e);
console.error(e);
}
```
### 关键点说明
1. **FileProvider 机制**(Android 7.0+):
```javascript
var uri = FileProvider.getUriForFile(
context,
"org.autojs.autojs.fileprovider", // Auto.js 内置的 authority
new java.io.File(videoPath)
);
```
使用 Auto.js 内置的 FileProvider (`org.autojs.autojs.fileprovider`) 生成安全的 content URI[^1][^2]
2. **权限标志**:
```javascript
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
```
授予临时读取权限,允许目标应用访问文件[^2]
3. **MIME 类型设置**:
```javascript
intent.setDataAndType(uri, "video/*");
```
指定为视频类型,确保系统使用正确的应用打开
4. **版本检测**:
```javascript
if (device.sdkInt >= 24) { ... }
```
自动适配不同 Android 版本
### 注意事项
1. **Auto.js 版本要求**:
- 需要 Auto.js 4.1.1+ 版本
- 确保开启了 `稳定模式`
2. **文件路径处理**:
- 使用绝对路径(如 `/sdcard/...`)
- 确认文件存在且可读
3. **权限问题**:
- 脚本开头请求存储权限
- 部分设备需要在设置中手动授予权限
4. **备选方案**:
如果上述方法失败,可以使用内置的 `app.viewFile()`:
```javascript
app.viewFile(videoPath);
```
此解决方案已处理 Android 7.0+ 的文件共享限制,避免了 `FileUriExposedException` 异常[^1][^2]。
android.os.FileUriExposedException: file:///storage/emulated/0/temp.png exposed beyond app through Intent.getData()
这个问题通常出现在 Android 7.0 及以上版本中,是由于 Android 7.0 引入了一项安全机制,禁止应用使用 file:// URI 访问其他应用或用户的文件。解决此问题的方法是使用 FileProvider 来共享文件。您可以按照以下步骤解决此问题:
1. 在 Manifest 文件中添加一个 FileProvider:
```
<application>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
...
</application>
```
2. 在 res/xml 文件夹中创建一个 provider_paths.xml 文件,指定要共享的文件路径:
```
<paths>
<external-path name="external_files" path="."/>
</paths>
```
3. 在代码中使用 FileProvider 获取文件的 URI:
```
File file = new File(getExternalFilesDir(null), "temp.png");
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file);
```
4. 在 Intent 中使用获取到的 URI:
```
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
```
这样就可以避免出现文件 URI 暴露的问题。
阅读全文
相关推荐


















