programing tip

비트 맵에 대한 Android 공유 의도-공유 전에 저장하지 않을 수 있습니까?

itbloger 2020. 11. 29. 10:01
반응형

비트 맵에 대한 Android 공유 의도-공유 전에 저장하지 않을 수 있습니까?


임시 위치에 대한 파일을 저장하지 않고 공유 의도를 사용하여 내 앱에서 비트 맵을 내보내려고합니다. 내가 찾은 모든 예제는 2 단계입니다. 1) SD 카드에 저장하고 해당 파일에 대한 Uri를 만듭니다. 2)이 Uri로 인 텐트를 시작합니다.

WRITE_EXTERNAL_STORAGE 권한을 요구하지 않고 파일을 저장하고 나중에 제거하는 것이 가능합니까? ExternalStorage없이 장치 주소를 지정하는 방법은 무엇입니까?


나는 이와 같은 문제가 있었다. 외부 저장소 읽기 및 쓰기 권한을 요청하고 싶지 않았습니다. 또한 때로는 휴대폰에 SD 카드가 없거나 카드가 마운트 해제 될 때 문제가 발생합니다.

다음 메서드는 FileProvider 라는 ContentProvider를 사용합니다 . 기술적으로 공유하기 전에 비트 맵 (내부 저장소에)을 저장하지만 권한을 요청할 필요가 없습니다. 또한 비트 맵을 공유 할 때마다 이미지 파일을 덮어 씁니다. 내부 캐시에 있기 때문에 사용자가 앱을 제거하면 삭제됩니다. 그래서 제 생각에는 이미지를 저장하지 않는 것만 큼 좋습니다. 이 방법은 외부 저장소에 저장하는 것보다 더 안전합니다.

문서는 꽤 훌륭하지만 (아래의 추가 자료 참조) 일부 부분은 약간 까다 롭습니다. 다음은 나를 위해 일한 요약입니다.

매니페스트에서 FileProvider 설정

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>
        ...
    </application>
</manifest>

com.example.myapp앱 패키지 이름으로 바꿉니다 .

res / xml / filepaths.xml 생성

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="shared_images" path="images/"/>
</paths>

이것은 FileProvider에게 공유 할 파일을 가져올 위치를 알려줍니다 (이 경우 캐시 디렉토리 사용).

내부 저장소에 이미지 저장

// save bitmap to cache directory
try {

    File cachePath = new File(context.getCacheDir(), "images");
    cachePath.mkdirs(); // don't forget to make the directory
    FileOutputStream stream = new FileOutputStream(cachePath + "/image.png"); // overwrites this image every time
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    stream.close();

} catch (IOException e) {
    e.printStackTrace();
}

이미지 공유

File imagePath = new File(context.getCacheDir(), "images");
File newFile = new File(imagePath, "image.png");
Uri contentUri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", newFile);

if (contentUri != null) {
    Intent shareIntent = new Intent();
    shareIntent.setAction(Intent.ACTION_SEND);
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
    shareIntent.setDataAndType(contentUri, getContentResolver().getType(contentUri));
    shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
    startActivity(Intent.createChooser(shareIntent, "Choose an app"));
}

추가 읽기


임시 위치에 대한 파일을 저장하지 않고 공유 의도를 사용하여 내 앱에서 비트 맵을 내보내려고합니다.

이론적으로 이것은 가능합니다. 실제로는 불가능할 것입니다.

이론적으로 공유해야하는 Uri것은 비트 맵으로 해석되는 것입니다. 가장 간단한 방법은 외부 저장소와 같이 다른 응용 프로그램에서 직접 액세스 할 수있는 파일 인 경우입니다.

플래시에 전혀 쓰지 않으려면 자체 ContentProvider를 구현 openFile()하고 메모리 내 비트 맵을 반환 하도록 구현하는 방법을 파악한 다음 Uri해당 비트 맵을 ACTION_SEND Intent. openFile()를 반환해야하기 때문에 ParcelFileDescriptor디스크에 표시하지 않으면 어떻게 할 수 있을지 모르겠지만 검색하는 데 많은 시간을 소비하지 않았습니다.

WRITE_EXTERNAL_STORAGE 권한을 요구하지 않고 파일을 저장하고 나중에 제거하는 것이 가능합니까?

단순히 외부 저장소에 저장하지 않으려면 ContentProvider내부 저장소의 파일을 사용하여 경로를 이동할 수 있습니다 . 이 샘플 프로젝트 는 장치의 PDF 뷰어를 ContentProvider통해 PDF 파일을 제공하는를 보여줍니다 ACTION_VIEW. 동일한 접근 방식을 ACTION_SEND.


CardView를 이미지로 공유 한 다음 앱 내부 저장 영역의 캐시 하위 디렉터리에 저장하기위한 것입니다. 도움이 되길 바랍니다.

        @Override
        public void onClick(View view) {

            CardView.setDrawingCacheEnabled(true);
            CardView.buildDrawingCache();
            Bitmap bitmap = CardView.getDrawingCache();

            try{
                File file = new File(getContext().getCacheDir()+"/Image.png");
                bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));
                Uri uri = FileProvider.getUriForFile(getContext(),"com.mydomain.app", file);

                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
                shareIntent.setType("image/jpeg");
                getContext().startActivity(Intent.createChooser(shareIntent, "Share"));

            }catch (FileNotFoundException e) {e.printStackTrace();}

        }
    });

저장 권한 없이도 쉽고 짧은 솔루션 찾는 분이라면 누구든지 (누가 7.0도 지원합니다). 여기있어.

매니페스트에 추가

<provider
     android:name="android.support.v4.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>

이제 provider_paths.xml 생성

<paths>
    <external-path name="external_files" path="."/>
</paths>

마지막으로이 메서드를 활동 / 조각에 추가합니다 (rootView는 공유하려는보기입니다).

 private void ShareIt(View rootView){
        if (rootView != null && context != null && !context.isFinishing()) {
            rootView.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache());
            if (bitmap != null ) {
                 //Save the image inside the APPLICTION folder
                File mediaStorageDir = new File(AppContext.getInstance().getExternalCacheDir() + "Image.png");

                try {
                    FileOutputStream outputStream = new FileOutputStream(String.valueOf(mediaStorageDir));
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    outputStream.close();

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (ObjectUtils.isNotNull(mediaStorageDir)) {

                    Uri imageUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", mediaStorageDir);

                    if (ObjectUtils.isNotNull(imageUri)) {
                        Intent waIntent = new Intent(Intent.ACTION_SEND);
                        waIntent.setType("image/*");
                        waIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
                        startActivity(Intent.createChooser(waIntent, "Share with"));
                    }
                }
            }
        }
    }

여기에 방법을 작동하는 것은 할 자신의 응용 프로그램의 스크린 샷을 확인 하고 공유하는 모든 메신저 또는 이메일 클라이언트를 통해 이미지로.

수정하려면 업데이트되지 비트 맵을 내가 개선 문제를 Suragch '사용의 대답을 Gurupad Mamadapur 의 의견과 추가 자신의 수정'.


Here is code in Kotlin language:

private lateinit var myRootView:View // root view of activity
@SuppressLint("SimpleDateFormat")
private fun shareScreenshot() {
    // We need date and time to be added to image name to make it unique every time, otherwise bitmap will not update
    val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
    val currentDateandTime = sdf.format(Date())
    val imageName = "/image_$currentDateandTime.jpg"       

    // CREATE
    myRootView = window.decorView.rootView
    myRootView.isDrawingCacheEnabled = true
    myRootView.buildDrawingCache(true) // maybe You dont need this
    val bitmap = Bitmap.createBitmap(myRootView.drawingCache)
    myRootView.isDrawingCacheEnabled = false

    // SAVE
    try {
        File(this.cacheDir, "images").deleteRecursively() // delete old images
        val cachePath = File(this.cacheDir, "images")
        cachePath.mkdirs() // don't forget to make the directory
        val stream = FileOutputStream("$cachePath$imageName")
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream) // can be png and any quality level
        stream.close()
    } catch (ex: Exception) {
        Toast.makeText(this, ex.javaClass.canonicalName, Toast.LENGTH_LONG).show() // You can replace this with Log.e(...)
    }

    // SHARE
    val imagePath = File(this.cacheDir, "images")
    val newFile = File(imagePath, imageName)
    val contentUri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", newFile)
    if (contentUri != null) {
        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // temp permission for receiving app to read this file
        shareIntent.type = "image/jpeg" // just assign type. we don't need to set data, otherwise intent will not work properly
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
        startActivity(Intent.createChooser(shareIntent, "Choose app"))
    } 
}

참고URL : https://stackoverflow.com/questions/9049143/android-share-intent-for-a-bitmap-is-it-possible-not-to-save-it-prior-sharing

반응형