프로그래밍/ 안드로이드어플만들기

안드로이드 13에서 갤러리에서 사진 선택 크러시

kugancity 2023. 9. 2. 19:56
반응형

 

 

 

릴리즈된 앱에서 갤러리에서 사전 선택할 때 안드로이드13에서만 아래와 같은 에러 발생함. 

 

 

 

에러 발생 부분

Fatal Exception: java.lang.RuntimeException
Failure delivering result ResultInfo{who=null, request=2010, result=-1, data=Intent { flg=0x41 clip={image/* video/* {U(content)}} }} 
to activity {.MainActivity}: java.lang.IllegalArgumentException: 
Invalid URI: content://media/picker/0/com.android.providers.media.photopicker/media/1000018248

 

혹시 권한 이슈인가 해서 안드로이드 13부터 세분화된 권한을 추가하고 런타임시 권한 요청하도록 아래와 같이 수정하였다. 

 

 

 

기존 앱 권한 부분  ( manifest 파일 )

 

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">

 

안드로이드 13부터 읽기 권한이 세분화 되어서 이미지에만 따로 권한을 추가로 설정하였다. 

 

 

수정한 앱 권한 부분  ( manifest 파일 )

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="32"/>
    <!-- Required only if your app needs to access images or photos
     that other apps created. -->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

 

 

 

기존 앱 권한 체크 부분

 

public void checkPermissions(){
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED 
            ) {
                String[] permission_list = new String[]{Manifest.permission.INTERNET,
                        Manifest.permission.CAMERA,
                        Manifest.permission.ACCESS_NETWORK_STATE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.READ_EXTERNAL_STORAGE
                };
                ActivityCompat.requestPermissions(this, permission_list, 1);
            }
        }
    }

 

 

수정한 앱 권한 체크 부분

 

if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
            if (checkSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED 
            ) {
                String[] permission_list = new String[0];
                permission_list = new String[]{Manifest.permission.INTERNET,
                            Manifest.permission.CAMERA,
                            Manifest.permission.ACCESS_NETWORK_STATE,
                            Manifest.permission.READ_MEDIA_IMAGES
                };
                ActivityCompat.requestPermissions(this, permission_list, 1);
            }
        }

 

 

권한 체크하는 부분에서 안드로이드 13을 체크해서 그 이상이면 새로운 권한으로 요청하도록 조건을 추가하였다.

그러나 사진 선택시 동일한 에러코드로 종료 되어서 결국 사진 선택 코드를 수정해야 할 거 같아 

안드로이드13에 새로 추가된 PhotoPicker 기능을 사용해보기로 함.  

 

기존 코드 확인 

 

 

사진 관련 부분 코드를  수정하기 전에 기존 코드 내용을 확인해보았다.

 

 

갤러리 아이콘을 클릭했을 때 실행하는 기존 함수이다. 

 

  private void runGallery() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        startActivityForResult(intent, GALLERY_PICK_IMAGE_MULTIPLE);
    }

 

암묵적 Intent를 실행하고 그 결과를 startActivityForResult에 전달한다.

Intent는 메시징 객체로, 다른 앱 구성 요소로부터 작업을 요청하는 데 사용할 수 있다. 

참고로 startActiviry와 startActivityForResult 에 대한 차이는 아래와 같다. 

 

 

 

startActivity : 새 액티비티를 열어줌 (단방향)

 

startActivityForResult : 새 액티비티를 열어줌 + 결과값 전달 (쌍방향)

 

requestCode : 여러 액티비티를 쓰는 경우, 어떤 액티비인지 식별하는 값

 

resultCode : 새 액티비티에서 리턴하는 값 

 

 

 

수정된 코드 

 

우선 photo picker 에서 사용할 requestCode 값을 코드에 추가한다. 

requestCode는  여러 액티비티를 쓰는 경우, 어떤 액티비인지 식별하는 값이고, 

int 값으로 코드에서 설정해주면 된다. 


    public final static int PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE = 2011;

 

그리고 안드로이드 13일 경우 처리 분기를 아래와 같이 추가하였다. 

 

 private void runGallery() {
        Log.d(TAG, "runGallery: 실행 ");
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
            // Launches photo picker in multi-select mode.
            // This means that user can select multiple photos/videos, up to the limit
            // specified by the app in the extra (10 in this example).
            final int maxNumPhotosAndVideos = 10;
            Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
            intent.setType("image/*");
            intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNumPhotosAndVideos);
            startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE);
        }
        else {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
            startActivityForResult(intent, GALLERY_PICK_IMAGE_MULTIPLE);
        }
    }

 

마지막으로 호출한 액티비티가 종료될 때 실행되는 함수인 onActivityResult에 

관련 처리 부분을 위에서 설정한 requestCode와 resultCode 를 사용하여 분기로 추가한다. 

리턴된 Uri 값들을 Uri 배열로 받아서 전달하도록 수정하였다. 

 

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{

    if(requestCode == PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE && resultCode == RESULT_OK) 
    {
            // Get photo picker response for multi select
            Uri[] results = new Uri[data.getClipData().getItemCount()];
            for (int i = 0; i < data.getClipData().getItemCount(); i++) {
                results[i] = data.getClipData().getItemAt(i).getUri();
            }
            //롤리팝에서는 콜백(filePathCallbackLollipop)을 초기화 해주지 않는다면, 사진 선택 화면을 호출해도 다시 나타나지 않는다.
            filePathCallbackLollipop.onReceiveValue(results);
            filePathCallbackLollipop = null;
        }
    }
    ...
    
}

 

 

마지막으로 포토피커는 미디어 라이브러리 액세스 권한을 요구하지 않아서

위에서 추가했었던 READ_EXTERNAL_STORAGE 권한 요청하는 부분을 다시 원복하였다. 

 

 

if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
            if (checkSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED 
            ) {
                String[] permission_list = new String[0];
                permission_list = new String[]{Manifest.permission.INTERNET,
                            Manifest.permission.CAMERA,
                            Manifest.permission.ACCESS_NETWORK_STATE
                };
                ActivityCompat.requestPermissions(this, permission_list, 1);
            }
        }

 

 

이제 갤러리에서 사진 선택 시 아무 문제없이 잘 올라가는 것을 확인하였다. 

실서비스에서 문제가 발생하고 있어서 테스트를 진행하고 바로 업데이트 하려고 했는데, 

테스트 중에 안드로이드 13에서 fcm 푸시 메세지가 안되는 문제를 또 발생했다. 

 

 

안드로이드 13에서 또 관련 부분이 업뎃되었나보다... 

 

이제 그만 좀 해......

 

 

 

 

 

 

 

 

 

 

 

 

참고


https://developer.android.com/guide/components/intents-filters?hl=ko

https://jhshjs.tistory.com/49

 

https://developer.android.com/training/data-storage/shared/media?hl=ko 

https://salmonpack.tistory.com/46

 

https://developer.android.com/about/versions/13/features/photopicker?hl=ko 

 

728x90
반응형