manifest.json中permissions必须为字符串数组,如["android.permission.camera"];全限定名、字符串、数组三者缺一不可,否则云端打包忽略、真机申请失败。

manifest.json里permissions必须写成数组,不是对象
很多项目跑不起来,根源就卡在这——manifest.json里的permissions字段被写成对象格式,比如{"android.permission.CAMERA": {}}。HBuilderX不会报错,但云端打包时直接忽略,真机上plus.android.requestPermissions调用后进fail回调,控制台连错误提示都没有。
正确写法只有一种:"permissions": ["android.permission.CAMERA", "android.permission.ACCESS_FINE_LOCATION"]。全限定名、字符串、数组,三者缺一不可。
- 漏掉
android.permission.前缀(如写成CAMERA)→ 系统不识别,静默失败 - 混用大小写(如
access_fine_location)→ Android 严格区分大小写,匹配失败 - 可视化勾选后手动改了代码视图却没重新「发行」→ 配置未生效,还是旧包
哪些权限必须提前声明,哪些可以不配
不是所有权限都要写进manifest.json。Android系统只对「危险权限」强制要求运行时申请,而这些权限在manifest中也必须声明;普通权限(如android.permission.INTERNET)云端打包默认已包含,不声明也不影响使用。
常见必须声明的危险权限包括:
android.permission.CAMERAandroid.permission.RECORD_AUDIOandroid.permission.ACCESS_FINE_LOCATION-
android.permission.READ_EXTERNAL_STORAGE和android.permission.WRITE_EXTERNAL_STORAGE(Android 10+需配合requestLegacyExternalStorage临时适配) -
android.permission.NFC(注意:不能简写为NFC)
像android.permission.READ_PHONE_STATE这类默认权限,除非你明确要禁用,否则不用手动加。
动态申请时权限名必须和manifest完全一致
plus.android.requestPermissions传入的权限字符串,必须和manifest.json中声明的**逐字符一致**。哪怕多一个空格、少一个点,都会导致系统拒绝弹窗,回调直接走deniedAlways分支,你以为用户点了“不再询问”,其实是配置错了。
典型错误示例:
- manifest写了
"android.permission.ACCESS_FINE_LOCATION",但代码里传"android.permission.ACCESS_COARSE_LOCATION"→ 匹配失败 - manifest写了
"android.permission.WRITE_EXTERNAL_STORAGE",但代码里传["WRITE_EXTERNAL_STORAGE"]→ 缺前缀,静默失败 - 一次申请多个权限时,其中某一个拼错,整个数组都失效(Android机制:全成功才算成功)
建议把权限常量统一抽成变量或枚举,避免硬编码重复出错。
Android 10+ 存储权限要额外注意targetSdkVersion和作用域
如果你的目标是Android 10(API 29)及以上,READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE即使声明并申请成功,也无法访问应用外部目录的任意文件——这是Scoped Storage强制策略。此时仅靠requestLegacyExternalStorage: true只能用于调试期,正式包会被华为/小米等市场拒收。
真正合规的做法是:
- 优先用
uni.getFileSystemManager()操作沙盒路径(uni.env.USER_DATA_PATH) - 需要访问公共媒体文件时,改用
uni.saveFileToPhotosAlbum或uni.chooseImage等封装接口 - 若必须读取其他App生成的文件,走
Intent.ACTION_OPEN_DOCUMENT方式(UTS插件级实现)
别指望靠requestLegacyExternalStorage蒙混过审,它已在Android 12+被废弃,且主流应用市场明确禁止在正式版APK中启用。











