1

由於我是Android新手,因此需要有關此問題的幫助。openInputStream cause SecurityException:權限拒絕(Android N +)

我的應用程序支持果凍豆(16)高達奧利奧(26)

我有一個上傳服務,需要openInputStream()上傳數據,因爲牛軋糖的新行爲。

此代碼在棉花糖及以下工作正常,但總是讓我012b崩潰牛軋糖。而且它崩潰在哪裏openInputStream()被稱爲與錯誤行:

java.lang.SecurityException異常:權限拒絕:閱讀com.miui.gallery.provider.GalleryOpenProvider URI內容://com.miui.gallery 。開/原料/%2Fstorage%2Femulated%2f0的%2FDCIM%2FCamera從PID = 30846%2FIMG_20171008_182834.jpg,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(),讓用戶使用應用程序,同時在後臺繼續上傳(通知告訴用戶)。而且,上傳工作基於隊列,用戶可以選擇在活動中上傳多個文件。第一個文件總是被上傳,但文件總是在崩潰後返回。

+0

某些設備不允許從相機或圖片目錄中讀取文件的權限。如果您從其他目錄上傳文件,問題是否存在? –

+0

感謝您的建議!我現在沒有牛軋糖設備,但當我這樣做時我會嘗試。哦,我可以得到mime(該功能也使用ContentResolver和相同的uri),這是否意味着讀/寫uri權限在當時處於啓用狀態,但不知何故需要其他權限才能直接讀取文件? –

+0

所以,我嘗試了你的建議@NabinBhandari,但它仍然給我同樣的例外。爲了以防萬一,我還編輯了我的帖子以添加更多信息。 –

回答

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); 
+0

嗨,所以它適用於activityresult。但是我需要將uri從活動發送到UploadService(後臺服務)。奇怪的是,只有第一個項目才能成功。把我的'ACTION_GET_CONTENT'改成'ACTION_OPEN_DOCUMENT'並持續uri許可,並且它在所有uri發送的服務中工作正常,所以它肯定是uri本身或者uri的許可。我如何將此權限傳遞給服務?正如我在我的問題中所述,我已經將讀/寫uri標誌添加到服務的意圖中,但它什麼都沒做......謝謝。 –

+0

我不確定這是不是一個好主意,但可以將Uri轉換爲路徑,並將路徑傳遞給您的服務。 –

+0

如果我從'ACTION_GET_CONTENT'(那裏)發送內容URI的路徑,Nougat會拋出另一個異常。但是,也許,如果我將文件'onActivityResult()'複製到文件我的應用程序控制並使用該文件uri /路徑,它將工作正常工作正常。我會嘗試一下並在這裏發佈結果。謝謝 :) –

0

我終於設法解決這個問題。顯然它,因爲只要接收活動處於活動狀態,給定uri的權限就是有效的。因此,將uri發送到後臺服務(上傳服務)將導致SecurityException與預期的一樣,除非uri是可持久的uri(即從ACTION_OPEN_DOCUMENT)。

所以我的解決方案是將文件複製到我的應用程序創建的文件,並使用FileProvider.getUriForFile()函數獲取uri並將其發送到後臺服務,並在服務完成上傳時刪除副本。即使在調用活動完成後,這也可以正常工作。