1.情况描述
targetVersion 7.0及以上的手机,Uri.fromFile()方法使用时,并通过startActivity等方式启动其他app时,会出现FileUriExposedException异常。
2.问题原因及解决方案
为了提高私有文件的安全性,Android框架执行StrictMode API政策,禁止在应用内公开file:// URL,如果一项包含文件URI的intent离开您的应用,会出现FileUriExposedException异常。
采用content:// Uri,并授予URI临时访问权限,使用FileProvider类即可。
FileProvider是contentProvider的子类,用于创建content:// Uri代替file:// Uri实现安全的应用间文件共享。
3.相关知识点
实际测试中发现,仅在startActivity时存在问题。sendBroadcast则不会产生此类问题。
Uri uri = Uri.fromFile(file);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
为什么呢?
Intent.prepareToLeaveProcess()方法中,作了说明。
/**
* Prepare this {@link Intent} to leave an app process.
*
* @hide
*/
public void prepareToLeaveProcess(boolean leavingPackage) {
setAllowFds(false);
if (mSelector != null) {
mSelector.prepareToLeaveProcess(leavingPackage);
}
if (mClipData != null) {
mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
}
if (mExtras != null && !mExtras.isParcelled()) {
final Object intent = mExtras.get(Intent.EXTRA_INTENT);
if (intent instanceof Intent) {
((Intent) intent).prepareToLeaveProcess(leavingPackage);
}
}
if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
&& leavingPackage) {
switch (mAction) {
case ACTION_MEDIA_REMOVED:
case ACTION_MEDIA_UNMOUNTED:
case ACTION_MEDIA_CHECKING:
case ACTION_MEDIA_NOFS:
case ACTION_MEDIA_MOUNTED:
case ACTION_MEDIA_SHARED:
case ACTION_MEDIA_UNSHARED:
case ACTION_MEDIA_BAD_REMOVAL:
case ACTION_MEDIA_UNMOUNTABLE:
case ACTION_MEDIA_EJECT:
case ACTION_MEDIA_SCANNER_STARTED:
case ACTION_MEDIA_SCANNER_FINISHED:
case ACTION_MEDIA_SCANNER_SCAN_FILE:
case ACTION_PACKAGE_NEEDS_VERIFICATION:
case ACTION_PACKAGE_VERIFIED:
// Ignore legacy actions
break;
default:
mData.checkFileUriExposed("Intent.getData()");
}
}
if (mAction != null && mData != null && StrictMode.vmContentUriWithoutPermissionEnabled()
&& leavingPackage) {
switch (mAction) {
case ACTION_PROVIDER_CHANGED:
// Ignore actions that don't need to grant
break;
default:
mData.checkContentUriWithoutPermission("Intent.getData()", getFlags());
}
}
}
ACTION_MEDIA_SCANNER_STARTED 属于被忽略的action,不会进行checkFileUriExposed()判定。
4.参考文献
Google api:https://developer.android.google.cn/about/versions/nougat/android-7.0-changes.html?hl=zh-cn
实例: