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

    //获取存储权限private void getPermissions() {
//        普通权限:只需要在清单文件中注册即可
//        危险权限(Android 6.0 之后):需要在代码中动态申请,以弹系统 Dialog 的形式进行请求
//        特殊权限(Android 11(含) 之后):需要在代码中动态申请,以跳系统 Activity 的形式进行请求//android版本大于等于11if (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 {//有权限后需要处理的功能}}// 提示是否獲取存储空间权限@Overridepublic 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以上(含)同意存储权限直接保存图片@Overrideprotected 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权限,说这个权限有安全隐患,不是非必要权限就有了这篇文章;

三、适配Android11保存图片的方法;

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,并添加如下内容:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="sharedata" path="shareData/"/>
</paths>

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

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

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

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.appUri 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.功能图片展示

不使用MANAGE_EXTERNAL_STORAGE权限,适配Android11保存图片和分享图片相关推荐

  1. 【Android】【版本适配】Android11权限适配终极解决方案

    Android11有了哪些改动 Android11主要是进一步收缩了应用权限,在权限管理方面比以前更加严格 最主要,影响最大的,就是存储卡访问权限的调整 从Android11开始,应用将只能访问自己的 ...

  2. 这也许是Android一句话权限适配的更优解决方案

    SoulPermission Android一行代码权限的更优解决方案: 解耦Activity和Fragment.不再需要Context.不再需要onPermissionResult 内部涵盖版本判断 ...

  3. Android6.0权限适配及兼容库的实现

    从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图: 本文并不关心权限适配的原理,原理可以参 ...

  4. android 6.0 短信权限,Android6.0权限适配

    Code4Android .jpg 前言 现在谈论Android权限适配可能有点没必要,因为网上关于权限适配的文章很多,搜一下Android6.0权限适配关键词能搜到一堆文章,而且很多写的还很不错.不 ...

  5. Android M版本和非M版本动态权限适配方案

    动态权限适配方案 1.  背景 目前在Google官方推出的最新的AndroidM版本上,对于应用权限的调用做了大大的修改.在M版本之前,应用App需要用到什么权限只需要在AndroidManifes ...

  6. 安卓棉花糖动态权限适配

    Android 6.0 运行时权限管理最佳实践 转载在严振杰大神的博客,带你学习安卓棉花糖的动态权限适配. 首先来句名言静下心 = = 人类看不见的世界,并不是空想的幻影,而是被科学的光辉照射的实际存 ...

  7. 解决Android11上分享图片失败

    解决Android11上分享图片失败 1.先分析问题原因 ​ 首先分享应用数据给第三方应用需要在用到文件共享,就需要在AndroidManifest.xml中配置FileProvider,但是配置了只 ...

  8. 小程序权限设置:小程序下载图片保存到相册拒绝权限后,再次打开权限的解决方案

    小程序下载图片保存到相册功能,首次操作会提示:保存图片或视频到你的相册,有'拒绝'和'允许'两个选项,如果选择了拒绝就会保存失败:saveImageToPhotosAlbum:fail auth de ...

  9. android qq分享失败,请检查读写权限,android 友盟QQ分享失败

    QQ图片存储失败,请检查图片或者检查是否有读写权限 1.设置AndroidManifest.xml android.permission.WRITE_EXTERNAL_STORAGE android. ...

最新文章

  1. python3菜鸟教程中文-Python3 字符串
  2. SpringBoot响应Json数据乱码通过配置解决
  3. eof怎么结束输入_SimRobot算法社第二次活动圆满结束啦!
  4. C语言简易行编辑器,简单的行编辑器C语言.doc
  5. PAT_B_1059_Java(14分)_C++(20分)
  6. Java开发高性能网站需要关注的事
  7. Debian11安装VLC Media Player视频播放器
  8. 论__AlertDialog自定义布局回调修改的正确方式
  9. xml文件的创建和插入节点【原创】
  10. 设计模式(1)单例模式(Singleton)
  11. Unable to start debugging The Silverlight Developer Runtime is not installed
  12. UNICODE与ASCII码的关系(MTK)
  13. C语言中数字转换成字符,c语言中数字转换成字符串的方法
  14. 数据结构与算法之迷宫回溯
  15. LLC谐振变换器学习二
  16. 【Photoshop】常用快捷键记录—持续记录
  17. java like查询 mongodb_java MongoDB查询(一)简单查询
  18. nowcoder:[编程题] 头条校招(贪心)
  19. 频率学派与贝叶斯学派(先验分布与后验分布,MLE和MAP)
  20. 简单实用的Linux可视化监控工具——WGCLOUD

热门文章

  1. [gdc16]《星球大战:前线》的美术制作技术
  2. [sig14gdc14]crytek的《罗马之子》的渲染技术
  3. 用ssh时 提示WARNING:
  4. 如何实现一个楼中楼的评论系统?
  5. 如何从国外快速下载软件
  6. 不一样的显卡,在Pytorch中跑相同的网络,配置文件、参数、数据集完全相同,为什么训练结果相差特别多?
  7. 经典量化策略——做市商交易(期货)
  8. 山寨布斯们的爱情故事
  9. 织梦CMS安装的时候出现安全警告:Safe Alert: Request Error step 2 解决办法。
  10. wps图片与图片间距怎么调整_wps文档插入图片怎样中间空隙 具体方法介绍