안드로이드 앱을 개발하다보면 기기안에있는 리소스에 접근을 해야할때가 있습니다. 예를들어 사진이라든가 문서, 비디오등이 있다고 해보죠. 이경우 해당 위치에 대한주소를 가지고 오더라고 해당 Uri가 file:// 스킴을 사용하는데, Android 7.0 (API 레벨 24)부터는 파일 시스템 경로를 직접 노출할 수 없고, 사용하더라도 FileUriExposedException이 발생합니다. 이는 보안상의 이유로 앱 간 파일 공유를 제한하기 위한 것입니다. 이 경우 우린 FileProvider를 이용할수 있습니다.
FileProvider.getUriForFile()를 사용하면 FileProvider가 제공하는 content:// 스킴을 통해 파일에 대한 안전한 접근이 가능하며, 파일 공유 규칙을 준수할 수 있습니다. 이를 통해 안드로이드 시스템은 앱 간 파일 공유를 보다 안전하게 할 수 있습니다.
사용하는 방법 알아보겠습니다.
AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="kr.xxx.insurance.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider" />
</provider>
xml/file_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="."/> <!-- 내부저장소 / Context.getFilesDir()-->
<cache-path
name="internal_cache_path"
path="." /> <!-- 내부저장소 / getCacheDir()-->
<external-path
name="external_files"
path="."/> <!-- 외부저장소 / Environment.getExternalStorageDirectory()-->
<external-files-path
name="external_files_path"
path="." /> <!-- 외부저장소 / Context.getExternalFilesDir()-->
<external-cache-path
name="external_cache_path"
path="." /> <!-- 외부캐시영역 / Context.getExternalCacheDir()-->
<external-path name="Insurance" path="/Insurance"/>
</paths>
파일 프로바이더를 이용하여 content:// 스킴을 가지는 Uri를 가져와 사용할수 있습니다.
String fileDir = String.valueOf(this.getFilesDir());
String cacheDir = String.valueOf(this.getCacheDir());
String externalStorageDir = String.valueOf(this.getExternalFilesDir(null));
String externalFilesDir = String.valueOf(this.getExternalFilesDir(null));
String externalCacheDir = String.valueOf(this.getExternalCacheDir());
String insuranceDir = String.valueOf(this.getDir("insurance", MODE_PRIVATE));
String dowloadFolder = String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
String absPath = this.getFilesDir().getAbsolutePath();
DLog.d(new Exception(), "fileDir : " + fileDir);
DLog.d(new Exception(), "cacheDir : " + cacheDir);
DLog.d(new Exception(), "externalStorageDir : " + externalStorageDir);
DLog.d(new Exception(), "externalFilesDir : " + externalFilesDir);
DLog.d(new Exception(), "externalCacheDir : " + externalCacheDir);
DLog.d(new Exception(), "insuranceDir : " + insuranceDir);
DLog.d(new Exception(), "dowloadFolder : " + dowloadFolder);
DLog.d(new Exception(), "absPath : " + absPath);
[결과]
fileDir : /data/user/0/kr.xxxx.insurance/files
cacheDir : /data/user/0/kr.xxxx.insurance/cache
externalStorageDir : /storage/emulated/0/Android/data/kr.xxxx.insurance/files
externalFilesDir : /storage/emulated/0/Android/data/kr.xxxx.insurance/files
externalCacheDir : /storage/emulated/0/Android/data/kr.xxxx.insurance/cache
insuranceDir : /data/user/0/kr.xxxx.insurance/app_XXInsurance
dowloadFolder : /storage/emulated/0/Download
absPath : /data/user/0/kr.xxxx.insurance/files
외부 저장소 사용할 수 있는지 확인
String baseFolder;
// 외부 저장소를 사용할 수 있는지 확인
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
baseFolder = String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
}
// 내부 저장소 사용으로 되돌리기(위와 동등한 것이 있는지 확실하지 않음)
else {
baseFolder = this.getFilesDir().getAbsolutePath();
}
// 파일 저장
File file = new File(baseFolder + File.separator + "test.text");
file.setWritable(true);
file.setReadable(true);
file.getParentFile().mkdirs();
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write("저장할 메세지 텍스트 String".getBytes());
fos.flush();
fos.close();
} catch (IOException e) {
DLog.e(new Exception(), e.getMessage());
}
'Android(Java)' 카테고리의 다른 글
[JAVA] RxJava / retrofit2 이용한 API 서버 연동 (1) | 2024.11.27 |
---|---|
[Java] 하이브리드앱 웹페이지 PopupView에서 스크롤 시 Y값 0으로만 나올경우 (0) | 2024.10.24 |
[Java] uses-feature 란? (0) | 2024.10.18 |
[Java] android.permission.QUERY_ALL_PACKAGES (0) | 2024.10.18 |
[Java] MutableLiveData observe 사용 (0) | 2024.10.16 |