Android FileProvider

윤예은·2022년 9월 2일

FileProvider란

파일 프로바이더는 ContentProvider의 자손으로,
파일 Uri를 "file:///"대신 "content://"으로 만들어 관리하기 위해 사용되는 친구이다.

contentUri를 사용하는 이유는, 파일을 Uri로 공유하면서 다른 앱에 권한을 주려고 할 때, 파일의 권한을 바꿔버리면 내가 원했던 그 앱 말고도 다른 앱들에게도 권한이 주어지기 때문이라고 한다. Content Uri를 사용하게 되면, Intent의 flag를 설정하여 일시적인 권한을 줄 수 있게 된다. 또한 해당 권한은 전달받은 Activity가 스택에 존재할 동안 혹은 전달받은 Service가 running인 동안만 유지된다.

보안:: 앱 간 파일 공유 시 무조건 강제

Android 7.0(24)부터 Intent로 FileUri를 보내는 것이 금지되었다(FileUriExposedException).

FileProvider 만들기

별다른 필요가 없다면 androidx에서 제공하는 FileProvider클래스를 그대로 사용하여도 되지만, 커스터마이징이 필요하다면 FileProvider의 자손 클래스를 만들어서 필요한 함수들을 override하여 사용할 수 있다.

class CustomFileProvider : FileProvider(R.xml.file_paths){
	...
}

Manifest에 FileProvider 등록하기

FileProvider를 사용하기 위해 Manifest에 등록할 필요가 있다.

<provider
    android:name="com.sample.CustomFileProvider"
    android:authorities="com.mydomain.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data 
 	android:name="android.support.FILE_PROVIDER_PATHS" 
 	android:resource="@xml/file_paths" /> 
</provider>

android:exported="false"는 무조건 명시하여야 하는 변수이다. 왜냐하면 true가 기본값으로 설정된 버전도 있기 때문이다.

File경로 명시하기

res/xml 폴더를 만든 후 해당 폴더에 "file_paths"라는 xml파일을 만들어서 사용한다. 어디 예시를 보든 다 그렇게 되어 있는 것으로 보아 국룰인 것으로 보인다. (안드로이드 공식마저 이렇게 되어 있다.)

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <!--Context.getFilesDir()-->
   <files-path name="name" path="." />
   
   <!--getCacheDir()-->
   <cache-path name="name" path="." />

   <!--Environment.getExternalStorageDirectory()-->
   <external-path name="name" path="." />
   
   <!--Context.getExternalFilesDir(null)-->
   <external-files-path name="name" path="."/>
   
   <!--Context.getExternalCacheDir()-->
   <external-cache-path name="name" path="."/>
   
   <!--only available on API 21+ devices.-->
   <!--Context.getExternalMediaDirs()-->
   <external-media-path name="name" path="."/>
   ...
</paths>

Content Uri 만들기

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(
getContext(),"
com.mydomain.fileprovider", 
newFile
);

[출처] https://aroundck.tistory.com/7287

File Uri에 대한 퍼미션 주기

//support Android (4.1(16) ~ 5.1(22))
intent.setClipData(ClipData.newRawUri("", contentUri)); 

// set flag to grant permission
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
); 
 

[참고자료]
https://developer.android.com/reference/androidx/core/content/FileProvider
https://aroundck.tistory.com/7287
https://mixup.tistory.com/98

profile
안녕하세요!!

0개의 댓글