SingmyAaronLan
SingmyAaronLan
  • 发布:2023-07-14 15:02
  • 更新:2024-07-21 11:53
  • 阅读:1531

【报Bug】Android配置 targetSdkVersion设为33后调用 uni.saveImageToPhotosAlbum()报错

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: 22621.1992

HBuilderX类型: Alpha

HBuilderX版本号: 3.8.7

手机系统: Android

手机系统版本号: Android 13

手机厂商: vivo

手机机型: vivo Y77e

页面类型: vue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

示例代码:
saveImg(imgurl) {  
    // #ifdef APP-PLUS  
    uni.downloadFile({  
        url: imgurl,  
        success: function(res) {  
            uni.saveImageToPhotosAlbum({  
                filePath: res.tempFilePath,  
                success: (f) => {  
                    getApp().showToast("已保存至" + f.path.split(  
                        'file:///storage/emulated/0')[1])  
                                        console.log('保存成功')  
                },  
                fail: (err) => {  
                    console.error(err)  
                    getApp().showToast('保存失败')  
                }  
            })  
        }  
    })  
    // #endif  
}

操作步骤:
  1. 新建项目,设置mainfest.json Android配置的targetSdkVersion为33。
  2. 新建页面,将代码示例中的方法复制至methods中,调用方法。

预期结果:
保存成功

实际结果:
保存失败  
{"errMsg":"saveImageToPhotosAlbum:fail No Permission","code":12}

bug描述:

原本是没有设置 targetSdkVersion的,打包出来运行一切正常。

因项目需要使用UTS插件,将mainfest.json中Android配置 targetSdkVersion设为33。

在Android 13系统中,同样的代码,调用 uni.saveImageToPhotosAlbum() 无法保存图片至相册,报错信息:

{"errMsg":"saveImageToPhotosAlbum:fail No Permission","code":12}

检查过应用权限,确认照片与视频、管理所有文件权限均已打开,依旧报错。

**示例项目:
下载地址

2023-07-14 15:02 负责人:无 分享
已邀请:
SingmyAaronLan

SingmyAaronLan (作者)

emmm...决定放弃uni.saveImageToPhotosAlbum()了

项目没准备适配iOS,所以直接用plus的 Downloader模块 加上 Android 的 MediaScanner库(用来解决保存文件不能立刻被其他应用发现的问题,不想写插件的可以直接参考 Ba-MediaUtil

示例代码

const mediaUtil = uni.requireNativePlugin('Ba-MediaUtil');  

let dtask = plus.downloader.createDownload(url, {  
  filename: "file:///storage/emulated/0/Pictures/xx.png"  //这里注意一定是三个“/”  
},  
  function (d, status) {  
​    if (status == 200) {  
​      let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);  
​      mediaUtil.refreshFile({  
​        path: fileSaveUrl  
​      }, (ret) => {  
​        console.log('媒体库刷新:', ret)  
​      });  
​      getApp().showToast('成功保存至' + fileSaveUrl.replace('/storage/emulated/0', ''))  
​    } else {  
​      getApp().showToast('下载失败')  
​      plus.downloader.clear();  
​    }  
  })  
dtask.start();

相册权限问题的话可以写uts插件或者原生插件,

因为 比较懒 没精力,直接用uts了

参考 Android平台uts开发指南 - 系统权限管理
经测试,官网的demo代码出现许多报错,
大概为:
1.错误的关键字:val -> var

  1. 错误的数据类型: MutableList<String> -> Array<string>

  2. 错误的非空断言:!! -> !(kotlin中的非空断言是!!,ts中是一个!)

  3. 错误的注释:用户拒绝了部分权限,仅允许了grantedList中的权限 -> 用户拒绝了grantedList中的权限

    以下为修复后的 uts 代码

import { UTSAndroid } from "io.dcloud.uts";  

export function checkSystemPermissionGranted(permissions : Array<string>) : boolean {  
    var grant = UTSAndroid.checkSystemPermissionGranted(UTSAndroid.getUniActivity()!, permissions);  
    return grant  
}  

export function getSystemPermissionDenied(permissions : Array<string>) : Array<string> {  
    var denied = UTSAndroid.getSystemPermissionDenied(UTSAndroid.getUniActivity()!, permissions)  
    return denied  
}  

export function requestSystemPermission(permissions : Array<string>) : void {  
    UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissions, function (allRight : boolean, grantedList : string[]) {  
        if (allRight) {  
            console.log('用户同意了全部权限')  
        } else {  
            console.log(`用户仅同意了如下权限:${grantedList}`)  
        }  
    }, function (doNotAskAgain : boolean, grantedList : string[]) {  
        if (doNotAskAgain) {  
            console.log('用户拒绝了权限,并且选择不再询问')  
        } else {  
            console.log(`用户拒绝了如下权限:${grantedList}`)  
        }  
    })  
}  

export function gotoSystemPermissionActivity(permissions : Array<string>) : void {  
    UTSAndroid.gotoSystemPermissionActivity(UTSAndroid.getUniActivity()!, permissions);  
}  

使用示例

import * as sinlePerm from "../../uni_modules/sinle-perm";  

// 检查权限是否被允许  
console.log(sinlePerm.checkSystemPermissionGranted(["android.permission.READ_MEDIA_IMAGES",  
    "android.permission.READ_MEDIA_VIDEO",  
    "android.permission.READ_MEDIA_AUDIO"  
]))  

// 获取被禁止权限列表  
console.log(sinlePerm.getSystemPermissionDenied(["android.permission.READ_MEDIA_IMAGES",  
    "android.permission.READ_MEDIA_VIDEO", "android.permission.READ_MEDIA_AUDIO"  
]))  

// 请求指定权限  
sinlePerm.requestSystemPermission(["android.permission.READ_MEDIA_IMAGES",  
    "android.permission.READ_MEDIA_VIDEO", "android.permission.READ_MEDIA_AUDIO"  
])
  • SingmyAaronLan (作者)

    另外,uts的权限管理用的是XXPermissions,

    根据文档



    分区存储



    • 如果项目已经适配了 Android 10 分区存储特性,请在 AndroidManifest.xml 中加入


    <manifest>  

    <application>

    <!-- 表示当前项目已经适配了分区存储特性 -->
    <meta-data
    android:name="ScopedStorage"
    android:value="true" />

    </application>

    </manifest>


    • 如果当前项目没有适配这特性,那么这一步骤可以忽略

    • 需要注意的是:这个选项是框架用于判断当前项目是否适配了分区存储,需要注意的是,如果你的项目已经适配了分区存储特性,可以使用 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 来申请权限,如果你的项目还没有适配分区特性,就算申请了 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限也会导致无法正常读取外部存储上面的文件,如果你的项目没有适配分区存储,请使用 MANAGE_EXTERNAL_STORAGE 来申请权限,这样才能正常读取外部存储上面的文件,你如果想了解更多关于 Android 10 分区存储的特性,可以点击此处查看和学习




    参考官网 Android原生应用清单文件和资源,在根目录新建AndroidManifest.xml文件(注意大小写敏感),在<application>下写入 <meta-data android:name="ScopedStorage" android:value="true" />


    <?xml version="1.0" encoding="utf-8"?>  
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    package="io.dcloud.nativeresouce">
    <!--permissions-->

    <application>
    <!--meta-data-->
    <!-- 表示当前项目已经适配了分区存储特性 -->
    <meta-data android:name="ScopedStorage" android:value="true" />
    </application>

    </manifest>

    以此来声明适配了Android 10 及以上版本的分区存储特性,否则可能会在请求部分权限时报错:


    Error: targetMethod error::java.lang.IllegalArgumentException: The storage permission application is abnormal. If you have adapted the scope storage, please register the <meta-data android:name="ScopedStorage" android:value="true" /> attribute in the AndroidManifest.xml file. If there is no adaptation scope storage, please use android.permission.MANAGE_EXTERNAL_STORAGE to apply for permission

    除了以上方法,如果你的项目未适配分区存储的话,可以声明android.permission.MANAGE_EXTERNAL_STORAGE权限。当然如果你的项目面对Android较高版本时,尽量使用第一种方法

    2023-08-16 16:28

1***@qq.com

1***@qq.com

请问一下有人解决吗

  • SingmyAaronLan (作者)

    可以参考一下我上面的回复

    2023-10-15 16:50

  • 1***@qq.com

    回复 2***@qq.com: 大佬,是写原生插件吗,一定要开启分区存储吗,是咋解决的,没接触过app原生,不太明白,可以指条明路吗,写个大致的思路哈,感谢

    2023-10-16 15:33

SingmyAaronLan

SingmyAaronLan (作者)

HBuilder X 3.94.2023102311-alpha 版本已修复

爱豆豆

爱豆豆 - 办法总比困难多

可以参考一下这篇问答 跟你的问题类似:https://ask.dcloud.net.cn/question/160879

  • SingmyAaronLan (作者)

    这篇之前看过,

    "<uses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\"/>",

    "<uses-permission android:name=\"android.permission.READ_MEDIA_VIDEO\"/>",

    两个权限都已经加入,但仍然无效

    2023-07-14 16:16

  • 爱豆豆

    回复 2***@qq.com: 你是Android 几?我来试试

    2023-07-14 16:33

  • SingmyAaronLan (作者)

    回复 爱豆豆: Android 13

    2023-07-15 09:07

  • SingmyAaronLan (作者)

    回复 爱豆豆: 我传下示例项目源码,你看看

    2023-07-15 09:27

  • SingmyAaronLan (作者)

    回复 2***@qq.com: 附件过大,就直接上链接了

    https://mp-cc3f25eb-d6ea-44a4-8c91-70c11cd03d7b.cdn.bspapp.com/resources/errors/permission.zip

    2023-07-15 09:33

  • 爱豆豆

    回复 2***@qq.com: 我试过了 把所有的权限打开后还是不能保存 确实是个问题 只能邀请官方的人回答一下 哈哈

    2023-07-17 22:06

SingmyAaronLan

SingmyAaronLan (作者)

恋上蓝白

恋上蓝白

这问题官方也不解决吗?

  • 1***@qq.com

    请问一下,你解决了吗

    2023-10-17 23:19

w***@baolidegroup.com

w***@baolidegroup.com

小米 android 13 从相册选择 2次权限弹窗。bug连接 请问有碰到过吗?

nopilot

nopilot

我也遇到targetSdkVersion=34后无法从相册选择图片、无法保存图片到相册的问题了,前者试了增加READ_MEDIA_IMAGES权限生效了,后者试了增加MANAGE_EXTERNAL_STORAGE没生效,而且这个权限太宽泛容易被google play拒审。是需要增加其它权限吗?还是uni.saveImageToPhotosAlbum本身就不支持android api 33?谢谢分享!

也希望官方能集中回复一下安卓33以上版本的代码改动。例如:通知权限的获取、相册的读取、保存图片到相册用之前的permission.js和权限设置都出问题了。

要回复问题请先登录注册