관리 메뉴

나만을 위한 블로그

[Android] 안드로이드 13 이상에서 미디어 권한 런타임 요청 변경사항 대응하는 법 본문

Android

[Android] 안드로이드 13 이상에서 미디어 권한 런타임 요청 변경사항 대응하는 법

참깨빵위에참깨빵 2023. 8. 12. 23:42
728x90
반응형

앱의 targetSdkVersion을 33 이상으로 설정하면 onBackPressed()가 deprecated되는 등 다양한 변경사항이 있는데, 가장 중요한 변경사항은 READ_EXTERNAL_STORAGE 권한의 변경사항이다.

 

https://developer.android.com/about/versions/13/behavior-changes-13?hl=ko 

 

동작 변경사항: Android 13 이상을 타겟팅하는 앱  |  Android 개발자  |  Android Developers

Android 13 이상을 타겟팅하는 앱에 영향을 미치는 Android 13의 변경사항을 알아봅니다.

developer.android.com

앱이 안드로이드 13 이상을 타겟팅하고 다른 앱에서 만든 미디어 파일에 접근해야 하는 경우 READ_EXTERNAL_STORAGE 권한 대신 아래와 같은 세분화된 미디어 권한을 하나 이상 요청해야 한다

- 이미지 및 사진 : READ_MEDIA_IMAGES
- 동영상 : READ_MEDIA_VIDEO
- 오디오 파일 : READ_MEDIA_AUDIO

유저가 이전에 READ_EXTERNAL_STORAGE 권한을 앱에 부여한 경우 시스템은 세분화된 미디어 권한을 앱에 자동으로 부여한다. 이전에 권한을 부여하지 않은 경우 시스템은 앱이 위의 표에 나온 권한을 요청할 때 사용자 대상 대화상자(팝업)를 표시한다. READ_MEDIA_IMAGES 권한과 READ_MEDIA_VIDEO 권한을 동시에 모두 요청하면 시스템 권한 대화상자가 하나만 표시된다

 

이 말을 안드로이드 13 이상에서 READ_EXTERNAL_STORAGE 권한이 더 이상 사용되지 않는다는 것으로 받아들이면 안 된다. 사진, 음악, 영상 파일에 대해서는 더 구체적인 권한을 유저에게 요청해 허용받도록 변경된 것이다.

또한 13 미만 버전에선 여전히 사용할 수 있는 권한이기 때문에 저 권한을 없애버릴 수도 없다. 저 권한을 없애지 않고 업데이트했다가 안드 13 이상 기기를 쓰지 않는 사람이 해당 업데이트를 적용해버리면 멀쩡히 작동하던 기능이 안 되는건 당연하고 앱 크래시가 발생할 수 있다.

그러니 적절히 if로 분기쳐서 처리해주는 로직 수정이 필요하다. 아래는 위에 나열된 3가지 권한들을 모두 허용하도록 요청하는 예시다. 권한 요청 라이브러리는 사용하지 않았다.

 

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.annotation.RequiresApi
import com.example.kotlinprac.BaseActivity
import com.example.kotlinprac.R
import com.example.kotlinprac.databinding.ActivityPermissionTestBinding

class PermissionTestActivity :
    BaseActivity<ActivityPermissionTestBinding>(R.layout.activity_permission_test) {

    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    private val permission33 = arrayOf(
        Manifest.permission.READ_MEDIA_IMAGES,
        Manifest.permission.READ_MEDIA_AUDIO,
        Manifest.permission.READ_MEDIA_VIDEO,
    )

    private val permission = arrayOf(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        bind {
            btnPermissionTest.setOnClickListener {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    if (checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED  ||
                        checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED  ||
                        checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED ) {
                        requestPermissions(permission33, 100)
                    }
                } else {
                    if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED  ||
                        checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
                        requestPermissions(permission, 101)
                    }
                }
            }
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            when (requestCode) {
                100 -> {
                    Toast.makeText(
                        this@PermissionTestActivity,
                        "33 이상에서 쓰이는 권한 허용됨",
                        Toast.LENGTH_SHORT
                    ).show()
                }
                101 -> {
                    Toast.makeText(
                        this@PermissionTestActivity,
                        "33 이전에서 쓰이는 권한 허용됨",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }
    }

}

 

위처럼 작성하고 안드로이드 12 기기에서 실행하면 아래 팝업이 표시된다.

 

 

안드로이드 13에선 아래 팝업이 표시된다.

 

 

코드를 보면 현재 앱 버전이 TIRAMISU라는 상수값 이상인 경우와 아닌 경우를 if로 확인하고 있다.

이 상수를 확인해 보면 33이라고 표시되는데, 33은 안드로이드 13의 API 레벨이다. 즉 저 상수 자체가 안드로이드 13을 가리키는 것이다.

그 외에는 평범한 권한 요청 로직들인데 필요한 예외처리들은 하지 않았다. 권한 요청 라이브러리를 쓰거나 적절히 예외처리를 추가해 사용하면 된다.

반응형
Comments