티스토리 뷰
Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.
Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.
아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.
android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData()
android.os.FileUriExposedException 수정하는 방법
문제 내용
The app is crashing when I'm trying to open a file. It works below Android Nougat, but on Android Nougat it crashes. It only crashes when I try to open a file from the SD card, not from the system partition. Some permission problem?
파일을 열려고 할 때 앱이 다운됩니다. Android Nougat 이하에서는 작동하지만 Android Nougat에서는 작동하지 않습니다. 시스템 파티션이 아닌 SD 카드에서 파일을 열려고 할 때만 충돌합니다. 허가 문제?
Sample code:
샘플 코드:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Log:
로그:
android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData()
Edit:
수정:
When targeting Android Nougat, file://
URIs are not allowed anymore. We should use content://
URIs instead. However, my app needs to open files in root directories. Any ideas?
Android Nougat을 대상으로 할 때 file://URI는 더 이상 허용되지 않습니다. 대신 content://URIs를 사용해야 합니다. 그러나 내 앱은 루트 디렉터리에서 파일을 열어야 한다. 아이디어 있어요?
높은 점수를 받은 Solution
If your targetSdkVersion >= 24
, then we have to use FileProvider
class to give access to the particular file or folder to make them accessible for other apps. We create our own class inheriting FileProvider
in order to make sure our FileProvider doesn't conflict with FileProviders declared in imported dependencies as described here.
대상 SdkVersion >= 24인 경우 FileProvider 클래스를 사용하여 특정 파일 또는 폴더에 액세스하여 다른 앱에서 액세스할 수 있도록 해야 합니다. 파일 공급자를 상속하는 고유 클래스를 만들어 파일 공급자가 여기에 설명된 대로 가져온 종속성에 선언된 파일 공급자와 충돌하지 않도록 합니다.
Steps to replace file://
URI with content://
URI:
file://URI를 content://URI로 바꾸는 단계:
- Add a FileProvider
<provider>
tag inAndroidManifest.xml
under<application>
tag. Specify a unique authority for theandroid:authorities
attribute to avoid conflicts, imported dependencies might specify${applicationId}.provider
and other commonly used authorities.
AndroidManifest.xml의 태그 아래에 FileProvider 태그를 추가합니다. 충돌을 방지하기 위해 Android:authorities 특성에 대한 고유한 권한을 지정하십시오. 가져온 종속성은 ${applicationId}.provider 및 기타 일반적으로 사용되는 권한을 지정할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
- Then create a
provider_paths.xml
file inres/xml
folder. A folder may be needed to be created if it doesn't exist yet. The content of the file is shown below. It describes that we would like to share access to the External Storage at root folder(path=".")
with the name external_files.
그런 다음 res/xml 폴더에 provider_paths.xml 파일을 생성합니다. 폴더가 아직 없는 경우 폴더를 만들어야 할 수도 있습니다. 파일의 내용은 아래와 같습니다. root 폴더(path=".")의 외부 스토리지에 대한 액세스를 external_files라는 이름으로 공유하고자 함을 설명합니다.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
- The final step is to change the line of code below into
Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());
Uri photoURI = Uri.fromFile(createImageFile());
- Edit: If you're using an intent to make the system open your file, you may need to add the following line of code:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
마지막 단계는 아래 코드 라인을 변경하는 것입니다.
편집: 시스템에서 파일을 열도록 하려면 다음 코드 줄을 추가해야 할 수 있습니다.
Please refer to the full code and solution that have been explained here.
여기에 설명된 전체 코드와 솔루션을 참조하십시오.
가장 최근 달린 Solution
I spent almost a day trying to figure out why I was getting this exception. After lots of struggle, this config worked perfectly (Kotlin):
저는 왜 이런 예외가 생기는지 알아내려고 거의 하루를 보냈습니다. 많은 노력 끝에 이 구성은 완벽하게 작동했습니다(코틀린).
AndroidManifest.xml
Android Manifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.lomza.moviesroom.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
file_paths.xml
file_timeout.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="movies_csv_files" path="."/>
</paths>
Intent itself
Intent 코드
fun goToFileIntent(context: Context, file: File): Intent {
val intent = Intent(Intent.ACTION_VIEW)
val contentUri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
val mimeType = context.contentResolver.getType(contentUri)
intent.setDataAndType(contentUri, mimeType)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
return intent
}
I explain the whole process here.
나는 여기서 모든 과정을 설명한다.
출처 : https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed
'개발 > 안드로이드' 카테고리의 다른 글
Android WebView & 로컬 스토리지 (0) | 2022.11.30 |
---|---|
Eclipse로 프로젝트를 가져온 후 'Must Override a Superclass Method'' 오류 (0) | 2022.11.30 |
intent를 사용하여 다른 액티비티로 object를 보내는 방법 (0) | 2022.11.30 |
Android에서 액티비티가 시작될 때 EditText에 포커스 가는 것 막기 (0) | 2022.11.30 |
onActivityResult가 Fragment에서 호출되지 않습니다 (0) | 2022.11.30 |