1. android.os.FileUriExposedException
: file:///storage/~~.jpg exposed beyond app through ClipData.Item.getUri()
간단한 예제를 따라하며 안드로이드 개발을 하던 중 예외가 발생해서 문제점을 찾아서 올립니다!
버튼을 누르면 카메라를 실행하는 부분을 구현하고 있었습니다...
세부적으로 말하자면 프래그먼트 상에 ImageButton을 생성하고 OnClick 메서드에 카메라를 실행하는 인텐트를 호출하는 그런 작업중이었어요
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_camera, container, false);mPhotoButton = (ImageButton)v.findViewById(R.id.camera);
final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.fromFile(mPhotoFile); // --------①
captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri); // --------②
mPhotoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(captureImage,REQUEST_PHOTO); // --------③
}
});
mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);
}
저는 맨 처음 에러메시지와 표시해주는 코드라인을 따라가보니 ③에서 문제가 생겼다고 생각이 들었습니다.
일단 어떤 에러때문에 어플리케이션이 작동을 안했는지 봐볼까요?
라는 메시지와 함께 그 아래로 쭉쭉.. 메시지를 출력해주더라고요 ㅠㅠ
다음의 내용들이 중요해보이는 메시지에요 세부 디렉토리는 잘라냈습니다
그런데 자세히 볼수록 ①, ②에서 문제가 있다는 생각이 들었고 찾아보니 FileUri 부분이 문제였습니다.
2. 해결
Android 7.0 부터 API정책의 변경
안드로이드 7.0 (누가) 부터 앱사이의 공유가 더 엄격해져서 file:// URI 가 직접 노출되지 않도록 content:// URI를 보내고
이에 대해서 임시 액세스 권한을 부여하는 방식으로 변경되었다고 합니다.
이에 대한 자세한 설명은 밑에 공식참고문서(구글번역기로 번역된 글입니다)를 보시됩니다.
앱 사이의 파일 공유
Android 7.0을 대상으로 하는 앱의 경우, Android 프레임워크는 앱 외부에서 file://
URI의 노출을 금지하는 StrictMode
API 정책을 적용합니다. 파일 URI를 포함하는 인텐트가 앱을 떠나면 FileUriExposedException
예외와 함께 앱에 오류가 발생합니다.
애플리케이션 간에 파일을 공유하려면 content://
URI를 보내고 이 URI에 대해 임시 액세스 권한을 부여해야 합니다. 이 권한을 가장 쉽게 부여하는 방법은 FileProvider
클래스를 사용하는 방법입니다. 권한과 파일 공유에 대한 자세한 내용은 파일 공유를 참조하세요.
https://developer.android.com/about/versions/nougat/android-7.0-changes.html#accessibility
위에 설명에서와 같이 FileProvider클래스를 사용해서 content:// URI에 권한을 부여하는 방법을 보면 다음과 같습니다.
1. AndroidManifest.xml 수정
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.bignerdranch.android.test.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
2. res/xml/filepaths.xml 생성
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="storage/emulated" path="."/>
</paths>
3. Uri.fromFile(File mFile) 코드 대체
Uri uri = Uri.fromFile(mPhotoFile);
-> Uri uri = FileProvider.getUriForFile(getContext(), "com.bignerdranch.android.test.fileprovider", mPhotoFile);
*com.bignerdranch.android.test 부분은 개인의 도메인을 입력하시고 mPhotoFile 대신 생성한 파일 객체를 넣으시면 됩니다!
참고로 filepaths.xml과 AndroidManifest.xml 내부의 meta-data, android:resource="@xml/filepaths"가 일치해야합니다.
'Mobile 개발 > 재미있는 Android' 카테고리의 다른 글
[Android] WebView 설정 모아보기 (1) | 2020.11.20 |
---|---|
[Android] Retrofit을 쓰자 - 기본적인 사용 방법 (0) | 2020.11.19 |
[Android] RecyclerView 이해하기 (2) - ViewHolder는 무엇인가 (0) | 2020.09.17 |
[Android] RecyclerView 이해하기 (1) - Adapter는 무엇인가 (0) | 2020.09.09 |
[Android] 이벤트 쉽게 풀어서 이해하기 (0) | 2020.02.13 |