본문 바로가기

나의 플랫폼/안드로이드

[Android] FileProvider :: android.os.FileUriExposedException

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

File 경로를 Uri로 변경하고자 할 경우 아래와 같이 이용한다.


Uri.parse(File 경로)


앱 내부로 이용하는 것은 문제가 없지만,

MediaPlayer나 Intent로써 다른 앱으로 값을 전달하고자 할 경우,

아래와 같은 Exception이 발생한다.


android.os.FileUriExposedException


이 Exception은

build.gradle에 targetSdkVersion이 24 이상으로 설정 되어 있을 경우 발생 한다.


그 이유는 앱과 앱간의 파일 공유를 진행할 시, 보안이 강화 되었기 때문이다.

이 문제를 해결하기 위해선 FileProvider를 이용하여 임시 권한을 할당해줘야 한다.


1. res/xml/provider_paths.xml


xml을 통하여 권한을 주고자 하는 폴더를 지정할 수가 있습니다.

기본 형태는 아래와 같습니다.

내장인지 외장인지, 데이터 영역인지 캐쉬영역인지 기본 위치를 지정하고,

path를 통하여 세세한 경로를 지정할 수가 있습니다.

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="name" path="path" /> <!-- Context.getFilesDir(). -->
    <cache-path name="name" path="path" /> <!-- getCacheDir(). -->
    <external-path name="name" path="path" /> <!-- Environment.getExternalStorageDirectory(). -->
    <external-files-path name="name" path="path" /> <!-- Context#getExternalFilesDir(String) Context.getExternalFilesDir(null). -->
    <external-cache-path name="name" path="path" /> <!-- Context.getExternalCacheDir(). -->
</paths>
cs

https://developer.android.com/reference/android/support/v4/content/FileProvider.html


아래는 내장캐쉬영역에 images 폴더에 권한을 준다는 설정이다.

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path name="images" path="./images" /> <!-- getCacheDir(). -->
</paths>
cs



2. AndroidManifest.xml


xml로 지정한 path를 AndroidManifest에 지정 시켜 줍니다.

1
2
3
4
5
6
7
8
9
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>
cs


3. FileProvider 사용


이 소스는 참고용으로 중요한 부분은 FileProvider.getUriForFile 함수이다. 

이전에는 이 부분을 말했듯이 Uri.parse를 이용하였었다.


audio 파일을 다른 앱에서 실행하도록 던지는 소스이다.

val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(
FileProvider.getUriForFile(this, applicationContext.packageName + ".fileprovider", File(filePath))
, "audio/*")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)


보시면 하시겠지만 또한 중요한 부분은 FLAG_GRANT_READ_URI_PERMISSION 권한을 줘야지만 사용할 수 있다.

"너에게는 이 파일을 읽을 수 있게 해줄께!" 라는 의미인거죠.

당연히 쓰기 권한도 있구요. (FLAG_GRANT_WRITE_URI_PERMISSION )


참조 : https://stackoverflow.com/a/38858040