이미지를 서버에 업로드후에 삭제해야 하는 이슈.
* 이미지를 업로드 후에 다른 Task(runnable)에서 파일을 삭제 시켜주는 로직이 들어가 있음.(해당 액티비티에서 삭제가 아님)
나의 삽질을 적어둔 것 하단에 결론만 보셔도 됩니다.
1. SAF로 Uri를 가져옴.
: content://com.android.providers.media.documents/document/image%3A328
2. DocumentsContract.deleteDocument를 이용해 삭제 시도. - 실패
: NullPointerException: authority 익셉션 떨어짐.
처음에 가져온 경로를 File(path)하여 삭제 중 이었음. (content:// Uri였기 때문에 경로가 바뀐듯.)
바뀐 경로 : /content:/com.android.providers.media.documents/document/image%3A328
맞는 경로 : content://com.android.providers.media.documents/document/image%3A328
File()로 만들어서 제대로 된 테스트가 되지 않은듯.
3. File로 하지않고 Uri로 바로 접근하여 삭제 시도. - 실패
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord
4. ContentResolver로 다시 query를 해서 uri를 가져와서 삭제 해보면 어떨까 해서 query해 봄. - 실패
Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord
: 뭔가 권한 문제인가.. 의심
5. 이미지를 가져온 액티비티에서 삭제를 해보니 삭제가 된다. (Activity - onActivityResult)
: 하지만 Task(runnable)에서 삭제는 안됌
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord
6. DocumentFile.fromSingleUri(MyApp.get(), Uri.parse(fileOriginPath))로 DocumentFile얻어와서 delete해도 안된다..
: Activity에선 삭제가 되고, UploadTask에서 삭제하는건 안된다.
*그래서 액티비티로 한번 경로를 줘보기로 함
7. EventBus를 이용하여 FileUtil -> Activity로 fileUri를 전달.
: contentResolver.delete -> Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord
: DocumentsContract.deleteDocument -> java.lang.SecurityException: Permission Denial
: 뭔가 해당 이미지를 가져온 액티비티에서만 삭제가 가능한듯(?)
7-1) Android Q이상 에서는 SecurityException가 발생하면서 RecoverableSecurityException로 사용자에게 파일 삭제 할건지 직접 허용 받는 것이 있는데, 이 문제인줄 알고 해봤지만 안되었음!
8. 검색!!!
검색 : Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord
참조 : https://stackoverflow.com/questions/43430743/permission-denial-opening-provider-com-android-providers-media-mediadocumentspr
: takePersistableUriPermission 이런걸 발견
9. 검색!!!
검색 : takePersistableUriPermission
참조 : https://www.python2.net/questions-1265076.htm
https://dnight.tistory.com/entry/Storage-Access-Framwork-%EB%8B%A4%EB%A3%A8%EA%B8%B0-Android-ScopedStorage
: SAF로 사용자가 선택한 파일 또는 폴더를 Root로하여 uri를 onActivityResult로 응답.
응답받은 uri는 사용자가 선택한 파일 또는 폴더의 uri 이며 해당 uri 상위로는 접근이 불가능 합니다.
*파일 삭제의 경우 삭제하고자하는 uri를 contentResolver 를 통해서 삭제 할수 있습니다.
다만 파일읽기/탐색에서 지정한 범위를 벗어나거나 앱에서 생성한 파일 이외에는 하위의 에러가 발생합니다.
java.lang.SecurityException: Permission Denial: writing com.android.externalstorage.ExternalStorageProvider uri content://co
[파일 권한 저장]
파일을 생성하거나 열거나 할 경우 매번 Intent를 통해서 System UI를 표시할경우 사용자가 앱을 이용하는데 불편할수 있습니다.
그래서 최초에 사용자가 SystemUI를 통해서 지정한 뒤 onActivityResult 를 통해서 응답받은 Uri를
contentResolver.takePersistableUriPermission 통해서 권한을 얻은뒤 SharedPreferences 등의 저장소에 Uri를 저장하여
매번 Intent 요청없이 파일을 제어할 수 있습니다.
*contentResolver.takePersistableUriPermission(directoryUri,Intent.FLAG_GRANT_READ_URI_PERMISSION)
라는데 뭐가 어려움..
10. 검색!!!
검색 : No persistable permission grants found for UID 10164
참조 : https://www.python2.net/questions-279643.htm
https://www.python2.net/questions-1265076.htm
Android 파일 트리를 볼 수 있으며, 주 저장소를 선택한 상태에서 클릭하여 권한을 부여 할 수 있습니다.
"앱 이름-이 위치에 현재 저장된 모든 파일과 여기에 저장된 향후 콘텐츠에 대한 전체 액세스 권한을 가질 수 있습니다."-> 허용하다
느낌이 SAF로 가져온 onActivityResult에서 받아온 Uri에 takePersistableUriPermission로 권한 부여를 하는듯 하다.
추후 앱에서 권한을 가질 수 있도록(?) 앱을 삭제하고 다시 설치하면 그 권한은 사라지는 듯
결론 : takePersistableUriPermission로 권한을 부여하니 Task(Runnable)에서 삭제가 된다.
Uri uri = data.getData();
int takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getContentResolver().takePersistableUriPermission(uri, takeFlags);
}
궁금 :
1. SAF로 가져온 이미지는
- contentResolver.delete로 는 삭제가 되지 않았다.
: java.lang.UnsupportedOperationException: Delete not supported 발생
-DocumentsContract.deleteDocument, DocumentFile.fromSingleUri를 이용하니 삭제는 되었다.
2. ScopeStorage적용하면서
SecurityException 발생하면 RecoverableSecurityException으로 intent 허용 받는 처리가 있는데,
SAF로 가져온것은 적용이 안되는건가(?)
아직도 잘 모르겠다.. 공부 해야지..
삽질 이후..
드디어 RecoverableSecurityException가 발생 했다.
contentResolver로 가져온 uri : content://media/external/images/media/249
uri로 contentResolver로 '_data'로 파일경로 가져오기 : /storage/emulated/0/DCIM/Camera/JPEG_20210628_153320_.jpg
contentResolver로 가져온 uri를 통하여 contentResolver.delete()를 실행하면 SecurityException가 발생하면서 Android Q이상에서 RecoverableSecurityException작업을 할 수 있다.
1. Intent(Intent.ACTION_PICK, null).setType("video/*")를 통하여 가져 왔을 경우
가져온 uri : content://com.google.android.apps.photos.contentprovider/-1/2/content%3A%2F%2Fmedia%2Fexternal%2Fvideo%2Fmedia%2F32/ORIGINAL/NONE/2117276171
Intent.ACTION_PICK으로 가져온 uri로 contentResolver.delete()하면 Permission Denied가 발생
그래서, contentResolver로 전체 검색 후 DisplayName이 같은 것으로 가져와 다시 content://Uri로 작업해줌.
2. 사진 삭제 하기(contentResolver로 가져온 uri)
try{
//여기서 contentResolver.delete()실행
} catch (securityException: SecurityException) {
//Android Q이상으로 분기하여 RecoverableSecurityException로 처리.
.
.
val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender
//startActivityForResult deprecate로 인한 launch작업.
checkFilePermissionLauncher.launch(
IntentSenderRequest.Builder(intentSender).build()
)
}
3. 사진 여러장 삭제하기
상황) 사진 여러장 삭제할 경우 여러장의 파일 권한을 받아야 하는 상황.
나는 listUri를 만들어서 권한을 확인해야 하는 uri를 add 시켰다.
이것 또한 try/catch로 감싸서 작업.
- 파일 권한 체크
context.contentResolver
?.openFileDescriptor(uri, "w", null).use {
}
: for문으로 권한 체크를 하나씩 해줌 exception이 떨어지면 listUri 권한 허용 팝업 띄우기
: 처음에 5번으로 권한 허용 팝업을 띄우면서 했는데 소스진행이 exception으로 안떨어지고 진행이 되어 위의소스로 권한 확인함. - 파일 권한 여러개 띄우기
: 처음에 createDeleteRequest로 띄웠었는데 이건 허용이나 거부시 바로 파일이 삭제되는 것 같다.
: createWriteRequest로 교체하여 권한을 허용함.
문제가 생겼다.. createWriteRequest로 여러개의 파일 권한을 허용하는 것은 성공 했는데 API LEVEL 30에서 새로 추가된 함수이다..
Android 29에선 NosuchMethod(?)Exception이 발생..
그래서 WRITE_EXTERNAL_STORAGE를 주고
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
권한을 준뒤에 삭제하니깐 되었다.
'안드로이드' 카테고리의 다른 글
[Android] DiffUtil에 대해 알아보자 (0) | 2024.03.20 |
---|---|
[Android] MediaStore에서 미디어 파일 정보 읽는 방법 (0) | 2024.03.20 |
[Android] FCM을 사용해서 메시지를 보내는 과정 (FCM 추가) (0) | 2024.03.19 |
[Android] Exoplayer란? (0) | 2024.03.18 |
[Android] WorkManager (0) | 2024.03.18 |