不使用MANAGE_EXTERNAL_STORAGE权限,适配Android11保存图片和分享图片
一、其实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保存图片和分享图片相关推荐
- 【Android】【版本适配】Android11权限适配终极解决方案
Android11有了哪些改动 Android11主要是进一步收缩了应用权限,在权限管理方面比以前更加严格 最主要,影响最大的,就是存储卡访问权限的调整 从Android11开始,应用将只能访问自己的 ...
- 这也许是Android一句话权限适配的更优解决方案
SoulPermission Android一行代码权限的更优解决方案: 解耦Activity和Fragment.不再需要Context.不再需要onPermissionResult 内部涵盖版本判断 ...
- Android6.0权限适配及兼容库的实现
从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图: 本文并不关心权限适配的原理,原理可以参 ...
- android 6.0 短信权限,Android6.0权限适配
Code4Android .jpg 前言 现在谈论Android权限适配可能有点没必要,因为网上关于权限适配的文章很多,搜一下Android6.0权限适配关键词能搜到一堆文章,而且很多写的还很不错.不 ...
- Android M版本和非M版本动态权限适配方案
动态权限适配方案 1. 背景 目前在Google官方推出的最新的AndroidM版本上,对于应用权限的调用做了大大的修改.在M版本之前,应用App需要用到什么权限只需要在AndroidManifes ...
- 安卓棉花糖动态权限适配
Android 6.0 运行时权限管理最佳实践 转载在严振杰大神的博客,带你学习安卓棉花糖的动态权限适配. 首先来句名言静下心 = = 人类看不见的世界,并不是空想的幻影,而是被科学的光辉照射的实际存 ...
- 解决Android11上分享图片失败
解决Android11上分享图片失败 1.先分析问题原因 首先分享应用数据给第三方应用需要在用到文件共享,就需要在AndroidManifest.xml中配置FileProvider,但是配置了只 ...
- 小程序权限设置:小程序下载图片保存到相册拒绝权限后,再次打开权限的解决方案
小程序下载图片保存到相册功能,首次操作会提示:保存图片或视频到你的相册,有'拒绝'和'允许'两个选项,如果选择了拒绝就会保存失败:saveImageToPhotosAlbum:fail auth de ...
- android qq分享失败,请检查读写权限,android 友盟QQ分享失败
QQ图片存储失败,请检查图片或者检查是否有读写权限 1.设置AndroidManifest.xml android.permission.WRITE_EXTERNAL_STORAGE android. ...
最新文章
- python3菜鸟教程中文-Python3 字符串
- SpringBoot响应Json数据乱码通过配置解决
- eof怎么结束输入_SimRobot算法社第二次活动圆满结束啦!
- C语言简易行编辑器,简单的行编辑器C语言.doc
- PAT_B_1059_Java(14分)_C++(20分)
- Java开发高性能网站需要关注的事
- Debian11安装VLC Media Player视频播放器
- 论__AlertDialog自定义布局回调修改的正确方式
- xml文件的创建和插入节点【原创】
- 设计模式(1)单例模式(Singleton)
- Unable to start debugging The Silverlight Developer Runtime is not installed
- UNICODE与ASCII码的关系(MTK)
- C语言中数字转换成字符,c语言中数字转换成字符串的方法
- 数据结构与算法之迷宫回溯
- LLC谐振变换器学习二
- 【Photoshop】常用快捷键记录—持续记录
- java like查询 mongodb_java MongoDB查询(一)简单查询
- nowcoder:[编程题] 头条校招(贪心)
- 频率学派与贝叶斯学派(先验分布与后验分布,MLE和MAP)
- 简单实用的Linux可视化监控工具——WGCLOUD
热门文章
- [gdc16]《星球大战:前线》的美术制作技术
- [sig14gdc14]crytek的《罗马之子》的渲染技术
- 用ssh时 提示WARNING:
- 如何实现一个楼中楼的评论系统?
- 如何从国外快速下载软件
- 不一样的显卡,在Pytorch中跑相同的网络,配置文件、参数、数据集完全相同,为什么训练结果相差特别多?
- 经典量化策略——做市商交易(期货)
- 山寨布斯们的爱情故事
- 织梦CMS安装的时候出现安全警告:Safe Alert: Request Error step 2 解决办法。
- wps图片与图片间距怎么调整_wps文档插入图片怎样中间空隙 具体方法介绍