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"가 일치해야합니다.





+ Recent posts

"여기"를 클릭하면 광고 제거.