본문 바로가기
앱 제작/SSAFY 서명 앱

#7 일부 기기에서 사진이 저장되지 않는 문제와 권한 설정

by Kim Juhwan 2021. 12. 14.

1. 증상
2. 미디어 스캐닝
   2-1. 라떼는 말이야...
   2-2. 킷캣 이전의 방법

   2-3. 킷캣 이후의 방법
3. 권한 설정
   3-1. 권한을 허용하지 않았는데...
   3-2. 권한 요청 및 거부

 

 

 


 

 

2021/12/13 개발 내용

1. 증상

내가 가지고 있는 스마트폰과 태블릿에서는 앱에서 저장한 사진이 갤러리에도 들어가고 파일 탐색기에서도 보이는데

팀원의 스마트폰과 여분 스마트폰에서는 갤러리에도 저장이 안되고 파일 탐색기에서도 보이지 않는 문제가 발생했다.

똑같은 코드인데 다른 결과가 나와서 굉장히 당황스러웠다.

 

결과부터 말하자면 굉장히 어이없는 실수를 해서 생긴 일이였는데

그 과정에서 배운 것들이 있어 기록을 남겨두려고 한다.

 

2. 미디어 스캐닝

2-1. 라떼는 말이야...

과거의 스마트폰

 

내가 스마트폰을 처음 사용했던 게 2011년이던가...

그때 당시의 스마트폰은 전원을 껐다키면 항상 저렇게 "미디어 파일 스캐닝 중..."이라는 표시가 떴다.

오늘날에는 이 스캐닝 과정이 워낙 빨라서 안 보여주는 건지

사용자한테 굳이 보여줄 필요가 없는 정보라고 생각해서 안 보여주는 건지 모르겠지만

이 스캐닝 작업이 끝나야 갤러리의 사진을 확인할 수 있었다.

 

여러 블로그에 올라와 있는 사진 파일을 저장하는 코드들 중에서

저장 작업이 끝난 후 미디어 스캐닝 작업을 하는 코드들이 더러 있어서

혹시 이 작업이 필요한 걸까?라고 의심을 해보았다.

 

2-2. 킷캣 이전의 방법

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+Environment.getExternalStorageDirectory())));

킷캣 이전 버전에서는 broadcast를 날리는 방법으로 미디어 스캐닝을 했다고 한다.

킷캣이 4.4 버전인가...? 그러니까 어휴 굉장히 오래된 방법이다.

 

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file);
sendBroadcast(intent);

킷캣 이후에도 broadcast를 사용할 수 있는 방법이 있긴한데

이마저도 API 29(= 안드로이드 10) 이상에서는 더 이상 사용할 수 없다고 한다.

그냥 그렇구나 하고 다음 목차를 보면 된다.

 

2-3. 킷캣 이후의 방법

MediaScannerConnection.scanFile( getApplicationContext(),
	new String[]{file.getAbsolutePath()}, // 추가할 파일의 경로
	null, // Mime type
	new OnscanCompletedListener(){
		@Override
		public void onScanCompleted(String path, Uri uri) {
			// 스캔이 완료된 경우
		}
	});

여기서 Mime type은 null로 줘도 된다는 블로거도 있고 파일의 타입을 지정해줘야 한다는 블로거도 있어서 뭐가 맞는 건지 혼란스럽다.

null을 넣어보고 안된다면 여기를 참고해서 파일의 Mime type을 넣어주면 될 것 같다.

 

+) Mime type이 null이면 파일 확장자로 알아서 추정한다고 한다. 특별한 확장자가 아닌 이상 null 값 줘도 알아서 잘 찾을듯싶다.

 

그렇게 미디어 스캐닝을 하려고 한참 열심히 공부하던 도중에 내가 겪고 있는 문제가 미디어 스캐닝 때문이 아니란 걸 깨달았다. 미디어 스캐닝 때문에 갤러리에 사진이 보이지 않는 거라면 최소한 파일 탐색기에는 파일이 저장됐어야 하는 게 정상이다. 스마트폰을 껐다키면 자동으로 미디어 스캐닝을 하므로 사진이 떠야 하는데 사진이 뜨지도 않고 파일 탐색기에도 존재하지 않았다. 그리고 그 이유는 정말 너무나도 허무했다...

 

이 이후로는 권한 이야기로 넘어갑니다.
혹시나 미디어 스캐닝에 대해 더 자세한 정보가 필요하신 분들은 블로그 1블로그 2를 추천드립니다.

 

3. 권한 설정

3-1. 권한을 허용하지 않았는데...

        if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            // 권한이 이미 있는 경우
        } else {
            val permissionLauncher =
                registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
                    if(isGranted) {
                        // 사용자가 권한을 허용한 경우
                    } else {
                        // 사용자가 권한을 거부한 경우
                    }
                }
            val permission = Manifest.permission.READ_EXTERNAL_STORAGE
            permissionLauncher.launch(permission)
        }

원인은 바로 WRITE_EXTERNAL_STORAGE를

READ_EXTERNAL_STORAGE로 적은 나의..... 참 어이없고도 어이없는 실수였다.

 

근데 내가 이걸 눈치채지 못한 이유가

팀원의 핸드폰에서는 READ 권한만 있고 WRITE 권한이 없으니 당연히 파일 저장이 안 됐는데

내 핸드폰에서는 READ 권한밖에 없는데 파일 저장이 됐다는 것이다. 😲

대체 이걸 어떻게 해석해야 하지?

심지어 혹시 몰라 테스트해본 태블릿에서도 마찬가지였다.

안드로이드 버전에 따라 차이가 있는 걸까...?

 

권한이 없는데도 파일 저장이 가능한 이유를 열심히 분석해봤지만 결국 찾아내지 못하였다.

샤오미라 그런가...? 이걸 짱깨 폰이? 🤔

아무튼 내가 맞닥트린 문제는 WRITE를 READ로 잘못 씀 + READ 권한밖에 없는데 어떤 폰은 저장이 되고 어떤 폰은 저장이 안됨이 만들어낸... 문제였다. (멍청)

 

3-2. 권한 요청 및 거부

권한이 없을때 보여질 페이지

 

처음에는 파일을 저장하는 그 시점에 권한 허용 팝업창을 띄울까 했다.

근데 곰곰이 생각해보니 요즘 앱들은 앱 설치하고 실행하면 처음에 모조리 권한 요청을 하기도 하고

특히 우리 앱은 이 저장 권한이 없으면 무용지물인 앱이라서 우리도 이 방식을 따르기로 했다.

 

로고가 정해지면 페이지 상단에 배치할 예정이다.

지금은 다소 UI가 밋밋하다.

 

권한 허용 팝업창과 거부시 보여질 페이지

 

사용자가 만약 권한을 거부하면 어떻게 할까 고민을 해봤는데

꼭 필요한 권한이라 앱 사용을 계속할 수 있도록 진행시키는 건 안되고

앱을 종료시켜버릴까 생각했는데 그건 너무 싹퉁바가지 유저에게 불친절한 것 같았다.

 

그래서 안내 메시지가 있는 페이지를 하나 만들었다.

만약 사용자가 2회 이상 거부를 누르거나 다시 묻지 않음을 선택하면 앱에서는 더 이상 요청 팝업을 띄우지 않기 때문에

이런 경우는 앱 설정에 들어가서 수동으로 설정해 달라는 메시지를 적어두었다. (친절) (친절) 🤗

 

 


💡 느낀 점

  • 잠깐 어디서 지나가듯 들은 기억으로는 요즘은 미디어 스캐닝을 직접 해줄 필요가 없다고 들은 것 같은데... 파일을 저장하면 알아서 스캐닝을 한다고 들은 것 같은데 관련 내용을 찾아보고 싶었지만 구글에서 찾아볼 수가 없었다. 내 기억이 잘못된 걸까?
  • 권한에 대해서 공부하다가 EXTERNAL_CONTENT... 는 권한이 필요하지만 INTERNAL_CONTENT는 권한이 필요 없다는 걸 리마인드 할 수 있었다.
  • 아 빨리 다 만들고 싶다...

📘 참고한 자료


 

 

반응형

댓글