openInputStream导致SecurityException:Permission Denial(Android N +)

时间:2017-10-11 09:09:50

标签: android permission-denied android-7.0-nougat securityexception

我需要帮助解决这个问题,因为我是Android新手。

我的应用支持 JellyBean(16),直至 Oreo(26)

我有一个 UploadService ,需要openInputStream()才能上传数据,因为Nougat中的新行为。

此代码在Marshmallow及以下版本中运行良好,但总是让我{Nougat SecurityException崩溃。并且在使用错误调用openInputStream()的行上崩溃:

  

java.lang.SecurityException:Permission Denial:read com.miui.gallery.provider.GalleryOpenProvider uri content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FDCIM%2FCamera%2FIMG_20171008_182834。 jid来自pid = 30846,uid = 10195要求提供者被导出,或者grantUriPermission()

文件uri可以来自各种应用程序(图库,相机等)。我已经将问题缩小到来自ACTION_GET_CONTENT意图的uri(任何来自相机意图或MediaRecorder的工作正常)。

我认为这是因为uri在传入服务时失去了权限,但添加Intent.FLAG_GRANT_WRITE_URI_PERMISSIONIntent.FLAG_GRANT_READ_URI_PERMISSION并没有帮助。

还尝试添加FLAG_GRANT_PERSISTABLE_URI_PERMISSION标记,但它仍然崩溃,而getContentResolver().takePersistableUriPermission()导致另一个SecurityException崩溃,说该uri还没有被授予可持续的uri ...

UploadService.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

提前谢谢你。

编辑(附加信息) 如果这很重要。在将所有必需数据发送到服务后,调用该服务的活动正在调用finish(),允许用户使用该应用程序,同时在后台恢复上载(通知告诉用户)。而且,上传基于队列工作,用户可以选择上传活动中的多个文件。第一个文件总是被上传,但是文件总是在崩溃后返回。

2 个答案:

答案 0 :(得分:2)

我终于设法解决了这个问题。显然它,因为只要接收活动处于活动状态,给定uri的权限才有效。因此,将uri发送到后台服务(上传服务)将导致SecurityException达到预期,除非uri是可持久的uri(即来自ACTION_OPEN_DOCUMENT)。

所以我的解决方案是将文件复制到我的应用创建的文件中并使用FileProvider.getUriForFile()函数获取uri并将其发送到后台服务并在我的服务上传完成后删除副本。即使在调用活动完成后,这也可以正常工作。

答案 1 :(得分:1)

以下代码在我的设备(android 7)中正常工作:

public void pickImage(View view) {
    try {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        photoPickerIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
        startActivityForResult(photoPickerIntent, RC_PICK_IMAGE);
    } catch (ActivityNotFoundException e) {
        e.printStackTrace();
    }
}

<强> onActivityResult:

Uri uri = data.getData();
InputStream in = getContentResolver().openInputStream(uri);