当我试图打开一个文件时,应用程序崩溃了。它可以在Android Nougat下运行,但在Android Nougat上它会崩溃。只有当我试图从SD卡,而不是从系统分区打开文件时,它才会崩溃。权限问题?
示例代码:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
日志:
android.os.FileUriExposedException:
///storage/emulated/0/test.txt
Intent.getData ()
编辑:
当针对Android Nougat时,file:// uri不再被允许。我们应该使用content:// uri。但是,我的应用程序需要打开根目录下的文件。什么好主意吗?
要从服务器下载pdf,请在您的服务类别中添加以下代码。希望这对你有帮助。
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName + ".pdf");
intent = new Intent(Intent.ACTION_VIEW);
//Log.e("pathOpen", file.getPath());
Uri contentUri;
contentUri = Uri.fromFile(file);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24) {
Uri apkURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
intent.setDataAndType(apkURI, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent.setDataAndType(contentUri, "application/pdf");
}
是的,不要忘记在您的清单中添加权限和提供者。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
<provider
android:name="android.support.v4.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>
如果你的应用程序目标API 24+,你仍然想要/需要使用file:// intents,你可以使用hack方法禁用运行时检查:
if(Build.VERSION.SDK_INT>=24){
try{
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
}catch(Exception e){
e.printStackTrace();
}
}
StrictMode方法。disableDeathOnFileUriExposure被隐藏并记录为:
/**
* Used by lame internal apps that haven't done the hard work to get
* themselves off file:// Uris yet.
*/
问题是我的应用程序不是蹩脚的,而是不想被使用内容://意图所削弱,这是许多应用程序无法理解的。例如,以content:// scheme打开mp3文件,提供的应用程序比打开相同的over file:// scheme时少得多。我不想为谷歌的设计缺陷买单,限制我的应用程序的功能。
谷歌希望开发者使用内容方案,但系统并没有为此做好准备,多年来应用程序都是使用文件而不是“内容”,文件可以编辑和保存,而通过内容方案提供的文件则不能(可以吗?)
我的答案是“乌里”。解析文件路径为字符串,而不是使用Uri.fromFile()。
String storage = Environment.getExternalStorageDirectory().toString() + "/test.txt";
File file = new File(storage);
Uri uri;
if (Build.VERSION.SDK_INT < 24) {
uri = Uri.fromFile(file);
} else {
uri = Uri.parse(file.getPath()); // My work-around for SDKs up to 29.
}
Intent viewFile = new Intent(Intent.ACTION_VIEW);
viewFile.setDataAndType(uri, "text/plain");
startActivity(viewFile);
似乎fromFile()使用了一个文件指针,当内存地址暴露给所有应用程序时,我认为这可能是不安全的。但是文件路径字符串不会伤害任何人,所以它不会抛出FileUriExposedException异常。
测试API等级9至29!在另一个应用程序中成功打开文本文件进行编辑。不需要FileProvider,也不需要Android支持库。这将不能在API级别30(Android 11)或更新版本上正常工作,因为getExternalStorageDirectory()已弃用。
要从服务器下载pdf,请在您的服务类别中添加以下代码。希望这对你有帮助。
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName + ".pdf");
intent = new Intent(Intent.ACTION_VIEW);
//Log.e("pathOpen", file.getPath());
Uri contentUri;
contentUri = Uri.fromFile(file);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24) {
Uri apkURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
intent.setDataAndType(apkURI, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent.setDataAndType(contentUri, "application/pdf");
}
是的,不要忘记在您的清单中添加权限和提供者。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
<provider
android:name="android.support.v4.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>
我知道这是一个相当老的问题,但这个答案是给未来的观众的。所以我遇到过类似的问题,经过研究,我找到了这种方法的替代方案。
你的意图
从Kotlin中的路径查看您的图像
val intent = Intent()
intent.setAction(Intent.ACTION_VIEW)
val file = File(currentUri)
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val contentURI = getContentUri(context!!, file.absolutePath)
intent.setDataAndType(contentURI,"image/*")
startActivity(intent)
主要功能如下
private fun getContentUri(context:Context, absPath:String):Uri? {
val cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf<String>(MediaStore.Images.Media._ID),
MediaStore.Images.Media.DATA + "=? ",
arrayOf<String>(absPath), null)
if (cursor != null && cursor.moveToFirst())
{
val id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, Integer.toString(id))
}
else if (!absPath.isEmpty())
{
val values = ContentValues()
values.put(MediaStore.Images.Media.DATA, absPath)
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
}
else
{
return null
}
}
同样地,除了图像,你可以使用任何其他文件格式,比如pdf,在我的例子中,它工作得很好
我不知道为什么,我所做的一切与Pkosta (https://stackoverflow.com/a/38858040)完全相同,但一直得到错误:
Permission Denial:从ProcessRecord{reacted} (reacted)打开提供者,而不是从uid reacted导出
我在这个问题上浪费了好几个小时。罪魁祸首吗?芬兰湾的科特林。
val playIntent = Intent(Intent.ACTION_VIEW, uri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent实际上是设置getIntent()。addFlags而不是在我新声明的playIntent上操作。