⛏️ | 개발 기록/📂 | 텍스트 추출기

[Android, Kotlin] 모든 파일에 대한 접근 권한 부여 방법(모든 Android 버전 대응)

immgga 2025. 5. 28. 16:21
반응형

출처: unsplash.com

모든 파일 접근 권한 설정 부여(Android 11 이상 대응)

 

 

서론

지난 포스팅에서 언급한 대로 이번 포스팅은 미리 사용하게 될 기술들을 간단히 개발하면서 검증하는 과정에서 블로그에 올리면 좋을 것 같아서 포스팅으로 올리게 되었다.

이번 포스팅에서는 저장소 권한 부여 기능을 검증하면서 겪은 시행착오와 적용 방법에 대해 설명해 보겠다.

 

 

저장소 권한

텍스트 추출기 앱은 txt를 합성하는 게 핵심 기능이 될 듯해서 기존에 사용자가 가지고 있던 txt까지 불러와 합성할 수 있도록 하는 게 매우 중요했다.

그래서 모든 파일을 불러올 수 있는 권한이 필요하게 되었는데, 이 권한이 Android 10(API 29)에 올라오면서 변경되게 되었다고 한다.

 

기존에는 개발자가 WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE 권한을 부여해 자유롭게 미디어에 대한 읽기 쓰기가 가능했었다.

Android 10으로 올라오면서 Scoped Storage 개념이 처음 들어오게 되었다.

Scoped Storage의 도입으로 앱에서 명시적 권한 없이 개발자가 사용자 미디어 데이터를 접근할 수 없어졌다.

또한 도입을 위한 유예기한이 주어진 버전이기도 하다.

Android 10에서 기존의 방식을 적용하고자 한다면 Manifest 파일에 requestLegacyExternalStorage 속성을 true로 설정해 주면 된다.

<application
    android:requestLegacyExternalStorage="true"
    . . .

 

Android 11(R) 버전 이상부터는 Scoped Storage가 강제되어 무조건 대응하는 방법으로 코드를 짜야한다.

그래서 Android 11부터 모든 파일에 접근하기 위해서는 직접 사용자의 허가를 받아야 권한이 생기게 된다.

 

Android 11 이상에서 모든 파일에 접근하기 위해서는

Manifest에 MANAGE_EXTERNAL_STORAGE 권한을 선언 후,

Intent 작업으로 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION을 실행해 앱의 모든 파일 관리 권한을 허용해야 한다.

 

간단하게 요약해 보자면

  • Android 10 이하 버전에서는 기존의 저장소 쓰기, 읽기 권한을 허용해서 모든 파일에 접근이 가능하다.
  • Android 11 이상 버전에서는 MANAGE_EXTERNAL_STORAGE 권한을 선언 후, Intent 작업을 통해 모든 파일 접근 권한을 얻어내야 한다. 

 

모든 파일 관리 권한 허용(Android 11 이상)

Android 11부터는 위에 언급했다시피 사용자가 직접 설정에서 모든 파일 관리 권한을 허용하도록 유도해야 한다.

먼저 Manifest에 MANAGE_EXTERNAL_STORAGE 권한을 선언한다.

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>

 

우선 app 단계의 build.gradle.kts에서 buildConfig를 true로 설정해 준다.

buildFeatures {
    buildConfig = true
}

 

그다음 Intent를 이용해 설정 화면을 띄워 보자.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    val intent = Intent().apply {
        action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
        data = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
    }
    manageAllFilesLauncher.launch(intent)
}

Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION은 Android 11 이후부터 사용이 가능하기 때문에 11 이전 버전도 타깃하고 있다면 조건부 처리가 필수이다.

 

설정 화면에서 권한을 허용했는지 확인하려면 Environment.isExternalStorageManager의 존재 여부로 확인할 수 있다.

StartActivityForResult 코드에서 확인해 주는 코드를 넣어 주었다.

val manageAllFilesLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
    hasPermission.value = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
        Environment.isExternalStorageManager()
    else permissionState.allPermissionsGranted
}

Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION이랑 마찬가지로 isExternalStorageManager 또한 Android 11 이후부터 사용 가능하기 때문에 처리를 해주자.

 

모든 파일 관리 권한 허용(Android 10 이하)

Android 10 이전 버전들은 기존의 방식인 저장소 읽기, 쓰기 권한으로 Manifest에 선언 후 앱에서 권한 요청을 받으면 된다.

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

30 이상부터는 위 권한이 필요 없어지기 때문에 maxSdkVersion으로 29 버전까지의 기기에서만 권한이 활성화되도록 한다.

 

compose에서 권한 요청은 accompanist permission 라이브러리를 사용했다.

먼저 허용받을 권한을 정의해 놓고 기기 버전이 Android 10 이하인 경우에는 저장소 권한을 요청할 수 있도록 제작하겠다.

val permissionState = rememberMultiplePermissionsState(
    permissions = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
        listOf(
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
        )
    } else emptyList()
)

 

Android 11부터는 요청할 권한이 없기 때문에 빈 리스트를 반환한다.

 

현재 저장소 권한이 허용되었는지 확인하기 위한 state 변수를 생성한다.

이 변수가 true이면 이후 화면이 뜨게 하도록 설정하기 위함이다.

val hasPermission = remember {
    mutableStateOf(
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
            Environment.isExternalStorageManager()
        else permissionState.allPermissionsGranted
    )
}

모든 권한이 허용되었는지 확인하려면 allPermissionsGranted를 이용하면 된다.

 

이제 버전 체크를 통해 Android 10 이하 버전일 때, 권한 요청을 진행한다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // 설정으로 intnet하는 작업
} else {
    permissionState.launchMultiplePermissionRequest()
}

 

시행착오 & 정리

이 과정을 알아내기까지 상당한 시행착오를 거쳤다.Android 10 이전 버전 처리는 쉬웠지만, 11 이후 버전 처리가 어려웠다.

 

파일을 탐색했을 때에도 다른 파일들은 불러와지지 않았고, 폴더들만 불러와졌다.그리고 어쩌다 파일이 불러와지던 경우도 있었는데, 파일이 내가 검증 중이었던 다른 작업인 앱에서 다운로드된 txt 파일이었기 때문이었다.MediaStore을 이용해 탐색을 했을 때도 결과가 같아서 열심히 찾아봤는데, 앱에 권한이 부족해서 이런 상황이 발생했다는 것을 알게 되었는데 어떤 권한이 없는 건지 알 수 없었다.

 

그러다 우연히 MANAGE_EXTERNAL_STORAGE 권한과 ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION Intent 작업을 알게 되어서 적용 결과 모든 파일을 불러올 수 있었다.그리고 Intent 작업 진행 중 Android 11 이상에서만 코드를 사용할 수 있어서 Android 9 이하 버전일 때는 상관없지만, 딱 Android 10 버전일 때는 권한이 적용되지 않아서 난감했었는데, 이를 Manifest에 requestLegacyExternalStorage 속성을 부여해서 Android 9 이하 버전과 동일하게 작업하도록 해서 해결할 수 있었다.

 

 

다양한 시행착오를 거치면서 쓸 기술들에 대한 검증은 얼추 마무리했다.이제 본격적인 개발을 시작해 볼 생각이다.언젠가 올라올 개발 포스팅을 기대해 주면 고맙겠다.

728x90
반응형