Android(Java)

Android 11 이상 버전에서 외부 저장소 이미지 삭제하기

E.I.T.U 2022. 4. 6. 11:45

Android R(API 30) 이상 버전부터는 WRITE_EXTERNAL_STORAGE 권한을 받을 수 없게되었다.

 

이에 따라 기존의 파일 저장 방식이나 삭제 방식을 사용할 수 없게 되었는데

 

이번 포스트에서는 그 해결법을 공유하고자 한다.

 

https://codechacha.com/ko/android11-storage-updates/ 

 

Android11 - Storage(저장소) 정책 변경사항 정리

Android11(R)의 Preview에서 Storage(저장소) 변경사항을 정리하였습니다. 이번 업데이트는 Android10의 Scoped storage를 보완한 것들이 대부분입니다. All Files Access이 추가되고, 퍼미션들의 정책도 조금 변경

codechacha.com

 

이제는 MediaStore 를 통해 DeleteRequest를 보내는 방식으로 사용자에게 삭제 허가를 받도록 바뀌었다.

 

[주의] 이 방법은 Android R 이상에서만 사용한다. 버전 검사를 필수로 하자.

 

먼저 File Path를 Uri로 변환해주는 작업이 필요하다.

 

private Uri getImageUri(String path) {
        File file = new File(path);
        if (file.exists()) {
            long id = 0;
            ContentResolver CR = activity.getContentResolver();
            String selection = MediaStore.Images.Media.DATA;
            String[] args = new String[]{file.getAbsolutePath()};
            String[] projection = new String[]{MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA};
            String sortOrder = MediaStore.Images.Media.TITLE + " ASC";
            Cursor cursor = CR.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection + "=?", args, null);

            if (cursor != null) {
                while (cursor.moveToNext()) {
                    int idIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID);
                    id = Long.parseLong(cursor.getString(idIndex));

                    try {
                        return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
                    } catch (Exception e) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            ((RecoverableSecurityException)e).getUserAction().getActionIntent().getIntentSender();
                        }
                    }
                }
                cursor.close();
            }
        }
        return null;
    }

 

이어서 변환된 Uri들을 List에 담아준다.

 

List<Uri> uris = new ArrayList<>();
for (String path : paths) {
    Uri uriFromFile = getImageUri(path);
    if (uriFromFile != null) uris.add(uriFromFile);
}

 

Uri List를 담은 IntentSenderRequest를 만들어준다

 

if (uris.size() > 0) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      IntentSender intentSender = MediaStore.createDeleteRequest(activity.getContentResolver(), uris).getIntentSender();
      if (intentSender != null) return new IntentSenderRequest.Builder(intentSender).build();
   }
}

 

만들어진 Request를 요청할 ActivityResultLauncher 를 선언한다

 

launcher = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), result -> {
    if (result.getResultCode() == RESULT_OK) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Toast.makeText(this, "삭제 성공", Toast.LENGTH_SHORT).show();
            DeleteFinish();
        }
    }
});

 

이제 분기처리를 통해 Android R 이상일 때 실행하도록 해주면 끝이다

 

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    launcher.launch(GFA.DeleteAfterAndroid11(deleteList));
} else {
    GFA.DeleteFileList(deleteList);
}

 

실행해보면 다이얼로그를 통해 사용자에게 앱에서 사진을 지우는것을 허가하시겠습니까? 라며 요청한다

 

참... 이래저래 힘들게 한다 안드로이드