티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

How to use support FileProvider for sharing content to other apps?

다른 앱과 콘텐츠를 공유하기 위해 지원되는 FileProvider 사용 방법?

 문제 내용 

I'm looking for a way to correctly share (not OPEN) an internal file with external application using Android Support library's FileProvider.

Android Support 라이브러리의 FileProvider를 사용하여 내부 파일을 외부 애플리케이션과 올바르게 공유(OPEN 아님)하는 방법을 찾고 있습니다.

 

Following the example on the docs,

문서의 예제를 따라하고,
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.android.supportv4.my_files"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/my_paths" />
</provider>

 

and using ShareCompat to share a file to other apps as follows:

ShareCompat를 사용하여 파일을 다른 앱과 공유하려는 경우:
ShareCompat.IntentBuilder.from(activity)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

 

does not work, since the FLAG_GRANT_READ_URI_PERMISSION only grants permission for the Uri specified on the data of the intent, not the value of the EXTRA_STREAM extra (as was set by setStream).

setStream에 의해 설정된 EXTRA_STREAM 추가 값이 아닌, 인텐트의 데이터에 지정된 Uri에 대해서만 FLAG_GRANT_READ_URI_PERMISSION 권한이 부여되기 때문에 작동하지 않습니다.

 

I tried to compromise security by setting android:exported to true for the provider, but FileProvider internally checks if itself is exported, when so, it throws an exception.

제공자에 대해 android:exported를 true로 설정하여 보안을 억압하려 시도했지만, 제공자 자체가 내보내기 상태인지 확인하는 FileProvider 내부 체크가 있기 때문에 예외가 발생합니다.

 

 

 

 높은 점수를 받은 Solution 

Using FileProvider from support library you have to manually grant and revoke permissions(at runtime) for other apps to read specific Uri. Use Context.grantUriPermission and Context.revokeUriPermission methods.

지원 라이브러리의 FileProvider를 사용하는 경우, 특정 Uri를 읽을 수 있도록 다른 앱에 대해 수동으로 권한을 부여하거나 취소해야 합니다. 이를 위해 Context.grantUriPermission 및 Context.revokeUriPermission 메소드를 사용합니다.

 

For example:

예를 들면:
//grant permision for app with package "packegeName", eg. before starting other app via intent
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

//revoke permisions
context.revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

 

As a last resort, if you can't provide package name you can grant the permission to all apps that can handle specific intent:

마지막 수단으로 패키지 이름을 제공할 수 없는 경우 특정 인텐트를 처리할 수 있는 모든 앱에 대한 권한을 부여할 수 있습니다.
//grant permisions for all apps that can handle given intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
...
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

 

Alternative method according to the documentation:

문서에 따르면 대안 방법:

 

  • Put the content URI in an Intent by calling setData().
  • Next, call the method Intent.setFlags() with either FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION or both.
  • Finally, send the Intent to another app. Most often, you do this by calling setResult().
  • Permissions granted in an Intent remain in effect while the stack of the receiving Activity is active. When the stack finishes, the
    permissions are automatically removed. Permissions granted to one
    Activity in a client app are automatically extended to other
    components of that app.
  • setData()를 호출하여 콘텐츠 URI를 Intent에 넣습니다.
  • 다음으로 Intent.setFlags() 메서드를 호출하여 FLAG_GRANT_READ_URI_PERMISSION 또는FLAG_GRANT_WRITE_URI_PERMISSION 또는 둘 다를 설정합니다.
  • 마지막으로 setResult()를 호출하여 인텐트를 다른 앱에 보냅니다.
  • 인텐트에서 부여된 권한은 수신 Activity의 스택이 활성화된 동안 유지됩니다. 스택이 완료되면 권한이 자동으로 제거됩니다. 클라이언트 앱의 한 Activity에 부여된 권한은 해당 앱의 다른 구성 요소에 자동으로 확장됩니다.

Btw. if you need to, you can copy source of FileProvider and change attachInfo method to prevent provider from checking if it is exported.

참고로, 공급자가 내보내는지 확인하는 것을 방지하기 위해 FileProvider의 소스 코드를 복사하고 attachInfo 메서드를 변경할 수 있습니다.

 

 

 

 가장 최근 달린 Solution 

If you get an image from camera none of these solutions work for Android 4.4. In this case it's better to check versions.

카메라에서 이미지를 가져오는 경우 Android 4.4에서는 이러한 해결책이 모두 작동하지 않습니다. 이 경우 버전을 확인하는 것이 좋습니다.
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getContext().getPackageManager()) != null) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        uri = Uri.fromFile(file);
    } else {
        uri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".provider", file);
    }
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, CAMERA_REQUEST);
}

 

 

출처 : https://stackoverflow.com/questions/18249007/how-to-use-support-fileprovider-for-sharing-content-to-other-apps

반응형
댓글
공지사항
최근에 올라온 글