Java Android:如何使用 grantUriPermission 创建和发送带有位图附件的电子邮件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24730581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 14:32:54  来源:igfitidea点击:

Android: How to use grantUriPermission to be able to create and send an email with a bitmap attachment

javaandroidbitmap

提问by user3835673

From within my application, I'm trying to create an email that contains an image contained in a bitmap object.

在我的应用程序中,我试图创建一封电子邮件,其中包含位图对象中包含的图像。

private void sendEmailWithBitmapAttached(){ 

    final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
    emailIntent.setType("plain/text");
    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Email Subject");
    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Email Body");
    emailIntent.setType("image/png");
    ContentResolver cr = getContentResolver();

    // insert the image and create a path
    String imageBitmapPath = MediaStore.Images.Media.insertImage(cr, bitmapForEmail,"title", "description");

    // create a uri
    Uri imageUri = Uri.parse(imageBitmapPath);
    emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    emailIntent.putExtra(Intent.EXTRA_STREAM, imageUri);

    // send the email
    startActivity(Intent.createChooser(emailIntent, "Send mail..."));
}

This works fine in Android 2.3.

这在 Android 2.3 中运行良好。

But using later versions, it produces the following error:

但是使用更高版本,它会产生以下错误:

07-13 23:01:01.252: E/MediaStore(5194): Failed to insert image
 07-13 23:01:01.252: E/MediaStore(5194): java.lang.SecurityException: 
     Permission Denial: 
         writing com.android.providers.media.MediaProvider 
         uri content://media/external/images/media from 
             pid=5194, uid=10151 requires 
             android.permission.WRITE_EXTERNAL_STORAGE, 
             or grantUriPermission()

So, taking the suggestion of the error message, I tried to grantUriPermission.

因此,根据错误消息的建议,我尝试授予 UriPermission。

grantUriPermission(String toPackage, Uri uri, int modeFlags)

But I am not sure what to put for toPackage or uri

但我不确定要为 toPackage 或 uri 放什么

But again, using the error message, I modified the code as follows:

但是再次使用错误消息,我将代码修改如下:

private void sendEmailWithBitmapAttached(){ 

    final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
    emailIntent.setType("plain/text");
    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Email Subject");
    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Email Body");
    emailIntent.setType("image/png");
    ContentResolver cr = getContentResolver();

    // create a Uri for the content provider suggested by the error message
    Uri uri = Uri.parse("content://media/external/images/media");

    // create a package provider string suggested by the error messge.
    String provider = "com.android.providers.media.MediaProvider";


    // grant all three uri permissions!
    grantUriPermission(provider, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    grantUriPermission(provider, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    grantUriPermission(provider, uri, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);

    // insert the image and create a path
    String imageBitmapPath = MediaStore.Images.Media.insertImage(cr, bitmapForEmail,"title", "description");

    // create a uri
    Uri imageUri = Uri.parse(imageBitmapPath);
    emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    emailIntent.putExtra(Intent.EXTRA_STREAM, imageUri);

    // send the email
    startActivity(Intent.createChooser(emailIntent, "Send mail..."));
}

And I get the exact same error.

我得到了完全相同的错误。

Can a kind soul please give me a hint as how to take care of grantUriPermission's uri and provider items? Is this the correct approach?

好心人能否给我一个提示,告诉我如何处理 grantUriPermission 的 uri 和 provider 项目?这是正确的方法吗?

Thank you very much for ANY help, hint, guides, or suggestion, you can provide!

非常感谢您提供的任何帮助、提示、指南或建议!

回答by Badrul

Try including this in your AndroidManifest.xml.

尝试将其包含在您的 AndroidManifest.xml 中。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

On Android 6.0+ the permission must be granted by the user to the application otherwise this will throw the SecurityException.

在 Android 6.0+ 上,权限必须由用户授予应用程序,否则会抛出 SecurityException。

To do this go into Settings/Apps/[AppName]/Permissions and allow the Storage Permission.

为此,请进入 Settings/Apps/[AppName]/Permissions 并允许存储权限。

回答by Lee Hounshell

I had a similar issue. Below is how I solved the problem for my project. You should be able to adapt this for your solution. This solution also has some Firebase code, which you can ignore. The key points are ActivityCompat.requestPermissions and ActivityCompat.checkSelfPermission:

我有一个类似的问题。以下是我如何为我的项目解决问题。您应该能够针对您的解决方案进行调整。此解决方案还有一些 Firebase 代码,您可以忽略它们。关键点是 ActivityCompat.requestPermissions 和 ActivityCompat.checkSelfPermission:

private void shareViaEmail() {
    int permissionCheck = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
            LayoutInflater inflater = this.getLayoutInflater();
            final ViewGroup nullParent = null;
            final View dialogView = inflater.inflate(R.layout.alert_dialog, nullParent);
            alertBuilder.setView(dialogView);

            alertBuilder.setCancelable(true);
            alertBuilder.setTitle("Permission request");

            String message = "\n\n" + getString(R.string.email_images);
            AppCompatTextView notice = (AppCompatTextView) dialogView.findViewById(R.id.notice);
            if (notice != null) {
                notice.setText(message);
                notice.setTextSize(getResources().getInteger(R.integer.dialog_text_size));
            }
            else {
                alertBuilder.setMessage(message);
            }

            alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

                @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
                public void onClick(DialogInterface dialog, int which) {
                    mShowingAlert = false;
                    ActivityCompat.requestPermissions(baseActivity(), new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_TARGET_WRITE_PERMISSION_REQUEST);
                }
            });

            mAlertDialog = alertBuilder.create();
            mAlertDialog.show();
            return;
        }
    }
    ActivityCompat.requestPermissions(this,
            new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
            MY_TARGET_WRITE_PERMISSION_REQUEST);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == MY_TARGET_WRITE_PERMISSION_REQUEST) {
            doShareViaEmail();
        } else {
            failWriteImage();
        }
    }
}

protected void failWriteImage() {
    getHandler().post(new Runnable() {
        @Override

        public void run() {
            String email_failed = getResources().getString(R.string.fail_email_attach);
            @SuppressLint("ShowToast") Toast toast = Toast.makeText(getApplicationContext(), email_failed, Toast.LENGTH_SHORT);
            new CustomToast(toast).invoke();
        }
    });
}

protected void doShareViaEmail() {
    FireUtilities fireUtilities = FireUtilities.getInstance();
    fireUtilities.logEvent(mFirebaseAnalytics, "option_item", "share", "share_string");

    Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.string_share));

    String appStoreLink = getString(R.string.app_store_link);

    String emailText = getString(R.string.share_string_body1)
            + " " + appStoreLink
            + " " + getString(R.string.share_string_body2);

    emailText = emailText + "<br><br>" + getTitleOfSegment(true, mCurrentSegment, mCurrentSegmentIndex);

    Bitmap targetImage = screenShot(mTargetImageView);
    if (targetImage != null) {
        ArrayList<Uri> files = new ArrayList<Uri>();
        String path = MediaStore.Images.Media.insertImage(getContentResolver(), targetImage, "string", null);
        Uri targetUri = Uri.parse(path);
        files.add(targetUri);
        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files);
    }

    intent.setType("message/rfc822");

    Spanned htmlText = fromHtml(getString(R.string.share_score_head1)
            + emailText + getString(R.string.share_score_head2));
    intent.putExtra(Intent.EXTRA_TEXT, htmlText);

    try {
        startActivityForResult(Intent.createChooser(intent, "Email:"), 1234);
    } catch (final android.content.ActivityNotFoundException e) {
        String no_email_client = getResources().getString(R.string.no_email_client);
        @SuppressLint("ShowToast") Toast toast = Toast.makeText(getApplicationContext(), no_email_client, Toast.LENGTH_LONG);
        new CustomToast(toast).invoke();
    }
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1234) {
        LogHelper.v(TAG, "e-mail successfully sent");
    }
}

public Bitmap screenShot(View view) {
    if (view != null) {
        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
                view.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);
        return bitmap;
    }
    return null;
}

回答by brunaru

I solved my issue by also adding permission flags to the intent, like this:

我还通过向意图添加权限标志来解决我的问题,如下所示:

intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

More details can be found in documentation: https://developer.android.com/reference/android/support/v4/content/FileProvider.html#Permissions

更多细节可以在文档中找到:https: //developer.android.com/reference/android/support/v4/content/FileProvider.html#Permissions