我刚接触安卓系统,需要帮助解决这个问题。
我的应用程序支持果冻豆(16)至奥利奥(26)。
我有一个uploadservice,它需要openInputStream()
来上传数据,因为nougat中的新行为。
这段代码在棉花糖和下面的代码中工作得很好,但是总是在nougat上给我SecurityException
崩溃。它在调用openInputStream()
时出错的行上崩溃:
java.lang.SecurityException:权限拒绝:从PID=30846、uid=10195中读取com.miui.gallery.provider.galleryOpenProvider uri content://com.miui.gallery.open/raw/%2fstorage%2fsemulated%2f0%2fdcim%2fcamera%2fimg_.jpg需要导出提供程序,或granturipermission()
文件uri可以来自不同的应用程序(库、相机等)。我已经将问题缩小到来自ACTION_GET_CONTENT
intent的uri(任何来自camera intent或mediarecorder的都可以工作)。
我认为这是因为uri在传入服务时失去了它的权限,但是添加Intent.FLAG_GRANT_WRITE_URI_PERMISSION
和Intent.FLAG_GRANT_READ_URI_PERMISSION
没有帮助。
也尝试添加FLAG_GRANT_PERSISTABLE_URI_PERMISSION
标志,但它仍然崩溃,并导致另一个getContentResolver().takePersistableUriPermission()
崩溃,说所说的uri没有被授予持久uri…
上传服务.java
//.......... code to prepare for upload
if ( contentResolver != null && schemeContentFile ) {
mMime = UtilMedia.getMime(this, uri);
try {
InputStream is = contentResolver.openInputStream(uri);
byte[] mBytes = getBytes(is);
Bundle fileDetail = UtilMedia.getFileDetailFromUri(this, uri);
Log.d("AndroidRuntime", TAG + " " + mMime + " " + UtilToString.bundleToString(fileDetail) + " imageFile " + mFile);
currTitle = fileDetail.getString(OpenableColumns.DISPLAY_NAME, "");
MediaType type = MediaType.parse(mMime);
requestFile = RequestBody.create(type, mBytes);
} catch ( IOException e ) {
e.printStackTrace();
} catch ( SecurityException e ) {
e.printStackTrace();
}
}
//............continue to upload
提前谢谢你。
编辑(附加信息)
万一这很重要。调用服务的活动在将所有必需的数据发送到服务后调用
SecurityException
,允许用户使用应用程序,而在后台继续上载(通知用户)。而且,上传是基于队列的,用户可以选择在活动中上传多个文件。第一个文件总是被上传,但是之后的文件总是随着崩溃而返回。 最佳答案
我终于解决了这个问题。显然,这是因为给定uri的权限只有在接收活动处于活动状态时才有效。因此,将uri发送到后台服务(上传服务)将导致SecurityException
如预期的那样,除非uri是一个可持久的uri(即fromACTION_OPEN_DOCUMENT
)。
因此,我的解决方案是将文件复制到我的应用程序创建的文件中,并使用FileProvider.getUriForFile()
函数获取uri并将其发送到后台服务,并在我的服务完成上载时删除副本。即使在调用活动完成后,此操作也可以正常工作。