解决uniapp离线打包安卓,高版本权限适配问题

835 阅读1分钟

开发环境

  • 框架: uniapp-x
  • 版本: vue3
  • 系统: Android
  • 打包方式: 离线包(可能云打包没有这类问题)
  • 打包工具: Hbuilder 4.29 (最新版本)

场景

uniapp官方提供了本地选择图片的Api uni.chooseImage,APP中,需要用户手动选择相册/相机中上传图片,再进行后续操作...

Android 版本 >= 13 时,会出现没有系统授权弹框,而默认认为拒绝授权的情况,用户无法进入相册选择本地图片。

真机预览

呈现结果

动画1.gif

<无法访问图库>是程序内自定义的弹框,不要感到奇怪,后续会分析代码

预期结果

动画2.gif

分析代码

  • 找到调用相册/相机方法入口 onAddImage

Snipaste_2024-11-01_11-52-38.png

// 检查相册/相机权限
if (type === 'album') {
    if (!await Permissions.requestAlbumPermission()) {
        return
    }
} else if (type === 'camera') {
    if (!await Permissions.requestCameraPermission()) {
        return
    }
}

App.feedTap() // 震动提示
let path
try {
    // 封装的 uni.chooseImage 方法
    path = await App.chooseImage([type]) 
} catch (e) {
    // 忽略
    console.error(e)
    return
}
// 安静的忽略
if (!path) {
    return
}

// 上传图片
const progress = (uploadTask, uploadProgress) => {
    App.updateLoading({
        progress: uploadProgress?.progress || 0,
    })
}

App.showLoading({title: $t('work.uploading')})
try {
    const userImage = await $work.uploadUserImage({path, progress})
    onChooseImage(userImage)
    // emits('close')
} catch (e) {
    App.showError(e)
} finally {
    App.hideLoading()
}

Snipaste_2024-11-01_11-53-19.png

  • 重点看Permissions这个类的静态方法 requestAlbumPermission
  • 根据 Platform.os.IOS系统来区别 操作系统

Snipaste_2024-11-01_11-54-02.png

  • 最后触发校验弹框的方法是在 PermissionsAndroid 类的 #requestPermission实例
  • 通过plus.android.requestPermissions检验,用Promise返回结果
  • Messages.confirmAppSettings({perm})是封装的通用提示框
  • openAppAuthorizeSetting()是封装的打开应用设置页面 Snipaste_2024-11-01_11-54-4a6.png

核心代码

static requestAlbumPermission() {
    return this.#requestPermission(
        ['android.permission.READ_EXTERNAL_STORAGE'],
        $t('permission.album'),
    )
}
  • 当用户点击相册时,会验证 android.permission.READ_EXTERNAL_STORAGE这条权限

改动

查阅了很久的文档,请教了公司安卓工作经验比较充足的前辈得知:

Android 13 之后,访问特定文件类型需要更细分的权限:

  • 读取图片android.permission.READ_MEDIA_IMAGES
  • 读取视频android.permission.READ_MEDIA_VIDEO
  • 读取音频android.permission.READ_MEDIA_AUDIO

android.permission.READ_EXTERNAL_STORAGE 这条权限不支持了,我们需要根据android版本去请求不同的权限

static requestAlbumPermission() {
    if(Platform.os.VERSION_MAJOR >= 13){
        return this.#requestPermission(
            ['android.permission.READ_MEDIA_IMAGES'],
            $t('permission.album'),
        )
    }else{
        return this.#requestPermission(
            ['android.permission.READ_EXTERNAL_STORAGE'],
            $t('permission.album'),
        )
    }
}

类似

和读取权限类似,app内还有一个保存图片到相册的功能,在 Android13 也做了升级。 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限,在 Android 13 中不再推荐这种方式,且逐步失效。

  • Android 13 以上的方式
    • 使用应用专属目录(无需权限)