ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 13에서 갤러리에서 사진 선택 크러시
    프로그래밍/ 안드로이드어플만들기 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
    반응형
Designed by Tistory.