在Android 11中,为了实现图片的保存和分享功能,我们避免使用MANAGE_EXTERNAL_STORAGE权限。

访客 204 0

一、其实Android11(targetSdkVersion 30)及以上在AndroidManifest.xml声明MANAGE_EXTERNAL_STORAGE权限(不在AndroidManifest.xml声明获得“所有文件访问权限”按钮为灰色不能授权)在加上下面的判断就能基本解决问题:

    //获取存储权限    private void getPermissions() {//        普通权限:只需要在清单文件中注册即可//        危险权限(Android 6.0 之后):需要在代码中动态申请,以弹系统 Dialog 的形式进行请求//        特殊权限(Android 11(含) 之后):需要在代码中动态申请,以跳系统 Activity 的形式进行请求        //android版本大于等于11        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {//必须要MANAGE_EXTERNAL_STORAGE权限,但Google Play Console审核不通过            // 先判断有没有权限            if (Environment.isExternalStorageManager()) {                new Thread(saveFileRunnable).start();            } else {                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);                intent.setData(Uri.parse("package:" + getPackageName()));                startActivityForResult(intent, 0);            }        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {            if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {                //存储空间权限                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);            } else {                //有权限后需要处理的功能            }        } else {            //有权限后需要处理的功能        }    }    // 提示是否獲取存储空间权限    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case 0:                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {// 取得权限                    //有权限后需要处理的功能                } else {// 未取得权限                    Toast.makeText(getApplicationContext(), getString(R.string.language_noPermissions), Toast.LENGTH_SHORT).show();                }                break;        }    }    //Android 11以上(含)同意存储权限直接保存图片    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {            if (Environment.isExternalStorageManager()) {                //有权限后需要处理的功能            } else {                Toast.makeText(getApplicationContext(), getString(R.string.language_noPermissions), Toast.LENGTH_SHORT).show();            }        }    }

二、但问题是应用发布到Google Play Console因为声明了MANAGE_EXTERNAL_STORAGE权限,说这个权限有安全隐患,不是非必要权限就有了这篇文章;

三、如何在Android 11上保存图片

1.获取位图(BitMap),我这是通过ImageLoaader获取bitmap对象

//ImageLoader获取bitmap对象mBitmap = ImageLoader.getInstance().loadImageSync(listImage.get(indexImage));//保存圖片SaveImageUtil.saveFile(mBitmap, listImage.get(indexImage), getApplicationContext());

2.saveFile()保存图片的方法

//保存图片到相册public static void saveFile(Bitmap bm, String url, Context context) throws IOException {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { //android 11及以上版本保存圖片方法        String mImageFileName = url.substring(url.lastIndexOf("/") + 1).toLowerCase();        final ContentValues values = new ContentValues();        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + "station_image"); //图库中显示的文件夹名。        values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/*");        values.put(MediaStore.MediaColumns.IS_PENDING, 1);        ContentResolver resolver = context.getContentResolver();        final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);        try {            // 写下我们截图的实际数据            try (OutputStream out = resolver.openOutputStream(uri)) {                if (!bm.compress(Bitmap.CompressFormat.PNG, 100, out)) {                    throw new IOException("Failed to compress");                }            }            // 一切都很顺利、            values.clear();            values.put(MediaStore.MediaColumns.IS_PENDING, 0);            values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);            resolver.update(uri, values, null, null);        } catch (IOException e) {            Toast.makeText(context, context.getString(R.string.language_pictureSavedFailed), Toast.LENGTH_SHORT).show();        }    } else {        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/";        // 判断sd卡是否存在        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {            // 判断文件夹是否存在            File dirFile = new File(path);            if (!dirFile.exists()) {                dirFile.mkdirs();//创建此抽象路径指定的目录,包括所有必须但不存在的父目录。(及可以创建多级目录,无论是否存在父目录)            }            String fileName = url.substring(url.lastIndexOf("/") + 1, url.length()).toLowerCase();            File file = new File(path + fileName);            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));            bm.compress(Bitmap.CompressFormat.PNG, 100, bos);            bos.flush();            bos.close();            // 通知图库更新            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file)));        } else {            Toast.makeText(context, context.getString(R.string.language_notSDCard), Toast.LENGTH_SHORT).show();        }    }}

四、适配Android11分享图片到微信,微博,FaceBoook等平台

1.首先需要在AndroidManifest.xml中配置FileProvider,通过FileProvider,就允许第三方应用读取你的应用所分享的文件,而不会受到分区存储的限制

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
  
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_provider_paths" />
</provider>

2.在res/xml目录下,添加文件file_provider_paths.xml,并添加如下内容:

3.使用Bitmap保存文件和分享

 Bitmap mBitmap = ImageLoader.getInstance().loadImageSync(listImage.get(0));android 11//分享图片到其他APPSaveShareImageUtil.shareToOtherApp(mContext, mBitmap, listImage.get(0), packageName, isWeChat);

4.packageName是要分享到各应用的包名

在Android 11中,为了实现图片的保存和分享功能,我们避免使用MANAGE_EXTERNAL_STORAGE权限。-第1张图片-谷歌商店上架

5.保存图片的方法

/** * bitmap保存为文件 * * @param bm       bitmap * @param filePath 文件路径 * @return 返回保存结果 true:成功,false:失败 */5.private static Boolean saveBitmapToFile(Bitmap bm, String filePath) {    try {        File file = new File(filePath);        file.deleteOnExit();        if (!file.getParentFile().exists()) {            file.getParentFile().mkdirs();        }        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));        Boolean b = false;        if (filePath.toLowerCase().endsWith(".png")) {            b = bm.compress(Bitmap.CompressFormat.PNG, 100, bos);        } else {            b = bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);        }        bos.flush();        bos.close();        return b;    } catch (IOException e) {    }    return false;}

6.分享图片的方法

//分享图片到各平台    public static void shareToOtherApp(Context context, Bitmap bitmap, String url, String packageName, int isWeChat) {        String mImageFileName = url.substring(url.lastIndexOf("/") + 1).toLowerCase();        String filePath = context.getExternalFilesDir(null).toString() + "/shareData/" + mImageFileName;        // 该filePath对应于xml/file_provider_paths里的第一行配置:,因此才可被共享        Boolean saveBitmap = saveBitmapToFile(bitmap, filePath);        if (saveBitmap) {            File file = new File(filePath);            if (file == null || !file.exists()) {                file.mkdirs();            }            //使用FileProvider,要与`AndroidManifest.xml`里配置的`authorities`一致,假设你的应用包名为com.example.app            Uri contentPath = FileProvider.getUriForFile(context, "com.example.app.fileprovider", file);            Intent intent = new Intent(Intent.ACTION_SEND);            intent.setPackage(packageName);//自己选择分享到好友还是朋友圈            switch (isWeChat) {                case 0:                    //com.tencent.mm.ui.tools.ShareImgUI   直接分享到微信好友,                    intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI"));                    break;                case 1:                    //com.tencent.mm.ui.tools.ShareToTimeLineUI  直接分享到微信朋友圈,最多可以分享九张图片到微信朋友圈                    intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareToTimeLineUI"));                    break;//                case 2://                    //com.sina.weibo.page.ProfileInfoActivity 直接跳转到微博我的(简况)界面//                    intent.setComponent(new ComponentName("com.sina.weibo", "com.sina.weibo.page.ProfileInfoActivity"));//                    break;            }            intent.setType("image/*");            intent.putExtra(Intent.EXTRA_STREAM, contentPath);            context.startActivity(intent);        }

7.功能图片展示

在Android 11中,为了实现图片的保存和分享功能,我们避免使用MANAGE_EXTERNAL_STORAGE权限。-第2张图片-谷歌商店上架

标签: 权限 图片 文件 功能

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~