HarmonyOS鸿蒙Next中如何为应用配置应用权限说明?

HarmonyOS鸿蒙Next中如何为应用配置应用权限说明? 应用使用敏感权限需要在隐私政策中说明用途,本文介绍需要说明的权限类型、说明内容要求、以及如何正确配置权限说明。

4 回复

更多关于HarmonyOS鸿蒙Next中如何为应用配置应用权限说明?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


一、权限配置基础

1. manifest.json 中的权限声明

你的项目(manifest.json)中的权限配置:

{
    "app-harmony": {
        "distribute": {
            "bundleName": "com.ysy.coms",
            "permissions": [
                "ohos.permission.INTERNET",
                "ohos.permission.READ_MEDIA",
                "ohos.permission.WRITE_MEDIA",
                "ohos.permission.CAMERA",
                "ohos.permission.LOCATION",
                "ohos.permission.NOTIFICATION_CONTROLLER",
                "ohos.permission.INSTALL_BUNDLE"
            ],
            "reqPermissions": [
                {
                    "name": "ohos.permission.INTERNET",
                    "reason": "用于获取健康资讯、同步数据等网络功能",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    }
                },
                {
                    "name": "ohos.permission.READ_MEDIA",
                    "reason": "用于读取用户选择的图片,用于头像设置、健康报告分享等功能",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    }
                },
                {
                    "name": "ohos.permission.WRITE_MEDIA",
                    "reason": "用于保存健康报告图片、分享图片到相册等功能",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    }
                },
                {
                    "name": "ohos.permission.CAMERA",
                    "reason": "用于扫描二维码、拍摄健康记录照片等功能",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    }
                },
                {
                    "name": "ohos.permission.LOCATION",
                    "reason": "用于获取位置信息,提供基于位置的健康建议(可选功能)",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    },
                    "optional": true
                },
                {
                    "name": "ohos.permission.NOTIFICATION_CONTROLLER",
                    "reason": "用于发送健康提醒、任务提醒等通知功能",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "always"
                    }
                },
                {
                    "name": "ohos.permission.INSTALL_BUNDLE",
                    "reason": "用于应用内更新功能,下载并安装新版本",
                    "usedScene": {
                        "ability": [
                            "com.ysy.coms.MainAbility"
                        ],
                        "when": "inuse"
                    }
                }
            ]
        }
    }
}

二、权限说明配置

2. 创建权限说明文件(privacy-permissions.json)

{
    "appName": "养生源",
    "bundleName": "com.ysy.coms",
    "version": "1.0.0",
    "permissions": [
        {
            "name": "ohos.permission.INTERNET",
            "displayName": "网络访问权限",
            "description": "用于获取健康资讯、同步数据、检查更新等网络功能",
            "usage": [
                "获取健康资讯和养生知识",
                "同步健康数据到云端(可选)",
                "检查应用更新",
                "获取个性化推荐内容"
            ],
            "required": true,
            "optional": false
        },
        {
            "name": "ohos.permission.READ_MEDIA",
            "displayName": "读取媒体文件权限",
            "description": "用于读取用户选择的图片,用于头像设置、健康报告分享等功能",
            "usage": [
                "设置用户头像",
                "上传健康记录照片",
                "分享健康报告图片"
            ],
            "required": false,
            "optional": true
        },
        {
            "name": "ohos.permission.WRITE_MEDIA",
            "displayName": "写入媒体文件权限",
            "description": "用于保存健康报告图片、分享图片到相册等功能",
            "usage": [
                "保存健康报告为图片",
                "保存分享图片到相册",
                "导出健康数据图表"
            ],
            "required": false,
            "optional": true
        },
        {
            "name": "ohos.permission.CAMERA",
            "displayName": "相机权限",
            "description": "用于扫描二维码、拍摄健康记录照片等功能",
            "usage": [
                "扫描健康设备二维码",
                "拍摄健康记录照片",
                "识别健康数据"
            ],
            "required": false,
            "optional": true
        },
        {
            "name": "ohos.permission.LOCATION",
            "displayName": "位置信息权限",
            "description": "用于获取位置信息,提供基于位置的健康建议(可选功能)",
            "usage": [
                "获取天气信息用于健康建议",
                "基于位置的健康提醒",
                "附近健康服务推荐(可选)"
            ],
            "required": false,
            "optional": true
        },
        {
            "name": "ohos.permission.NOTIFICATION_CONTROLLER",
            "displayName": "通知权限",
            "description": "用于发送健康提醒、任务提醒等通知功能",
            "usage": [
                "健康数据异常提醒",
                "每日任务提醒",
                "签到提醒",
                "健康建议推送"
            ],
            "required": true,
            "optional": false
        },
        {
            "name": "ohos.permission.INSTALL_BUNDLE",
            "displayName": "安装应用权限",
            "description": "用于应用内更新功能,下载并安装新版本",
            "usage": [
                "应用内更新功能",
                "自动安装新版本"
            ],
            "required": false,
            "optional": true
        }
    ],
    "privacyPolicy": {
        "url": "https://your-domain.com/privacy-policy",
        "version": "1.0",
        "updateTime": "2024-01-01"
    },
    "dataCollection": {
        "personalInfo": [
            {
                "type": "健康数据",
                "purpose": "用于提供健康分析和建议",
                "storage": "本地存储,可选择同步到云端",
                "retention": "用户主动删除或卸载应用"
            },
            {
                "type": "设备信息",
                "purpose": "用于应用适配和问题诊断",
                "storage": "本地存储",
                "retention": "应用卸载时删除"
            }
        ],
        "thirdPartySharing": [
            {
                "name": "不共享",
                "description": "应用不会将用户数据共享给第三方"
            }
        ]
    }
}

三、权限使用说明页面

3. 创建权限说明页面(pages/profile/permissions.vue)

<template>
    <view class="permissions-page" :class="pageClass">
        <view class="page-header">
            <text class="page-title">权限使用说明</text>
        </view>
        
        <scroll-view class="page-content" scroll-y>
            <!-- 权限说明列表 -->
            <view class="permission-section" v-for="permission in permissions" :key="permission.name">
                <view class="permission-header">
                    <view class="permission-icon">
                        <text>{{ getPermissionIcon(permission.name) }}</text>
                    </view>
                    <view class="permission-info">
                        <text class="permission-name">{{ permission.displayName }}</text>
                        <text class="permission-status" :class="permission.status">
                            {{ permission.status === 'granted' ? '已授权' : '未授权' }}
                        </text>
                    </view>
                </view>
                
                <view class="permission-content">
                    <text class="permission-description">{{ permission.description }}</text>
                    
                    <view class="usage-list">
                        <text class="usage-title">使用场景:</text>
                        <view 
                            v-for="(usage, index) in permission.usage" 
                            :key="index"
                            class="usage-item"
                        >
                            <text class="usage-bullet">•</text>
                            <text class="usage-text">{{ usage }}</text>
                        </view>
                    </view>
                    
                    <view class="permission-actions" v-if="permission.optional">
                        <button 
                            class="action-btn"
                            :class="permission.status === 'granted' ? 'btn-revoke' : 'btn-grant'"
                            @tap="handlePermissionAction(permission)"
                        >
                            {{ permission.status === 'granted' ? '撤销权限' : '申请权限' }}
                        </button>
                    </view>
                </view>
            </view>
            
            <!-- 隐私政策链接 -->
            <view class="privacy-section">
                <view class="privacy-header">
                    <text class="privacy-title">隐私政策</text>
                </view>
                <view class="privacy-content">
                    <text class="privacy-text">
                        我们重视您的隐私保护,详细说明请查看
                    </text>
                    <text class="privacy-link" @tap="openPrivacyPolicy">
                        《隐私政策》
                    </text>
                </view>
            </view>
        </scroll-view>
    </view>
</template>

<script>
import { themeMixin } from '@/mixins/themeMixin.js'
import permissionsConfig from '@/privacy-permissions.json'
export default {
    mixins: [themeMixin],
    data() {
        return {
            permissions: []
        }
    },
    onLoad() {
        this.loadPermissions()
    },
    methods: {
        /**
         * 加载权限信息
         */
        loadPermissions() {
            // 从配置文件加载
            const configPermissions = permissionsConfig.permissions || []
            
            // 检查权限状态
            this.permissions = configPermissions.map(permission => {
                return {
                    ...permission,
                    status: this.checkPermissionStatus(permission.name)
                }
            })
        },
        
        /**
         * 检查权限状态
         */
        checkPermissionStatus(permissionName) {
            // #ifdef APP-HARMONY
            try {
                // 使用 plus API 检查权限
                const result = plus.android.checkPermission(permissionName)
                return result === 0 ? 'granted' : 'denied'
            } catch (error) {
                console.error('检查权限失败:', error)
                return 'unknown'
            }
            // #endif
            
            // #ifndef APP-HARMONY
            return 'unknown'
            // #endif
        },
        
        /**
         * 处理权限操作
         */
        async handlePermissionAction(permission) {
            if (permission.status === 'granted') {
                // 撤销权限
                this.showRevokeDialog(permission)
            } else {
                // 申请权限
                await this.requestPermission(permission)
            }
        },
        
        /**
         * 申请权限
         */
        async requestPermission(permission) {
            // #ifdef APP-HARMONY
            try {
                uni.showModal({
                    title: '申请权限',
                    content: permission.description,
                    confirmText: '允许',
                    cancelText: '拒绝',
                    success: async (res) => {
                        if (res.confirm) {
                            // 申请权限
                            const result = await this.requestSystemPermission(permission.name)
                            if (result) {
                                permission.status = 'granted'
                                uni.showToast({
                                    title: '权限已授予',
                                    icon: 'success'
                                })
                            } else {
                                uni.showToast({
                                    title: '权限被拒绝',
                                    icon: 'none'
                                })
                            }
                        }
                    }
                })
            } catch (error) {
                console.error('申请权限失败:', error)
                uni.showToast({
                    title: '申请权限失败',
                    icon: 'none'
                })
            }
            // #endif
        },
        
        /**
         * 请求系统权限
         */
        requestSystemPermission(permissionName) {
            return new Promise((resolve) => {
                // #ifdef APP-HARMONY
                plus.android.requestPermissions(
                    [permissionName],
                    (result) => {
                        resolve(result.granted && result.granted.length > 0)
                    },
                    (error) => {
                        console.error('请求权限失败:', error)
                        resolve(false)
                    }
                )
                // #endif
                
                // #ifndef APP-HARMONY
                resolve(false)
                // #endif
            })
        },
        
        /**
         * 显示撤销权限对话框
         */
        showRevokeDialog(permission) {
            uni.showModal({
                title: '撤销权限',
                content: `撤销${permission.displayName}后,相关功能将无法使用。是否继续?`,
                confirmText: '撤销',
                cancelText: '取消',
                success: (res) => {
                    if (res.confirm) {
                        // 跳转到系统设置
                        this.openSystemSettings()
                    }
                }
            })
        },
        
        /**
         * 打开系统设置
         */
        openSystemSettings() {
            // #ifdef APP-HARMONY
            plus.runtime.openURL('app.settings')
            // #endif
        },
        
        /**
         * 打开隐私政策
         */
        openPrivacyPolicy() {
            const url = permissionsConfig.privacyPolicy?.url || 'https://your-domain.com/privacy-policy'
            // #ifdef H5
            window.open(url, '_blank')
            // #endif
            
            // #ifdef APP-HARMONY
            plus.runtime.openURL(url)
            // #endif
        },
        
        /**
         * 获取权限图标
         */
        getPermissionIcon(permissionName) {
            const icons = {
                'ohos.permission.INTERNET': '🌐',
                'ohos.permission.READ_MEDIA': '📁',
                'ohos.permission.WRITE_MEDIA': '💾',
                'ohos.permission.CAMERA': '📷',
                'ohos.permission.LOCATION': '📍',
                'ohos.permission.NOTIFICATION_CONTROLLER': '🔔',
                'ohos.permission.INSTALL_BUNDLE': '📦'
            }
            return icons[permissionName] || '🔒'
        }
    }
}
</script>

<style scoped>
.permissions-page {
    min-height: 100vh;
    background: var(--bg-color);
}
.page-header {
    padding: 32rpx;
    background: var(--surface-color);
    border-bottom: 1rpx solid var(--border-color);
}
.page-title {
    font-size: 36rpx;
    font-weight: 600;
    color: var(--text-color);
}
.page-content {
    padding: 32rpx;
}
.permission-section {
    background: var(--surface-color);
    border-radius: 24rpx;
    padding: 32rpx;
    margin-bottom: 24rpx;
}
.permission-header {
    display: flex;
    align-items: center;
    margin-bottom: 24rpx;
}
.permission-icon {
    width: 80rpx;
    height: 80rpx;
    border-radius: 40rpx;
    background: var(--primary-color);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 40rpx;
    margin-right: 24rpx;
}
.permission-info {
    flex: 1;
    display: flex;
    flex-direction: column;
}
.permission-name {
    font-size: 32rpx;
    font-weight: 600;
    color: var(--text-color);
    margin-bottom: 8rpx;
}
.permission-status {
    font-size: 24rpx;
    color: var(--text-secondary);
}
.permission-status.granted {
    color: #52C41A;
}
.permission-status.denied {
    color: #F5222D;
}
.permission-content {
    margin-top: 24rpx;
}
.permission-description {
    display: block;
    font-size: 28rpx;
    color: var(--text-color);
    line-height: 1.6;
    margin-bottom: 24rpx;
}
.usage-list {
    margin-top: 24rpx;
}
.usage-title {
    display: block;
    font-size: 26rpx;
    font-weight: 500;
    color: var(--text-color);
    margin-bottom: 16rpx;
}
.usage-item {
    display: flex;
    align-items: flex-start;
    margin-bottom: 12rpx;
}
.usage-bullet {
    color: var(--primary-color);
    margin-right: 12rpx;
    font-size: 28rpx;
}
.usage-text {
    flex: 1;
    font-size: 26rpx;
    color: var(--text-secondary);
    line-height: 1.6;
}
.permission-actions {
    margin-top: 32rpx;
    padding-top: 32rpx;
    border-top: 1rpx solid var(--border-color);
}
.action-btn {
    width: 100%;
    height: 88rpx;
    line-height: 88rpx;
    text-align: center;
    border-radius: 44rpx;
    font-size: 28rpx;
    border: none;
}
.btn-grant {
    background: linear-gradient(135deg, #6BBF59 0%, #AED581 100%);
    color: #FFFFFF;
}
.btn-revoke {
    background: #F5F5F5;
    color: #666666;
}
.privacy-section {
    background: var(--surface-color);
    border-radius: 24rpx;
    padding: 32rpx;
    margin-top: 32rpx;
}
.privacy-header {
    margin-bottom: 24rpx;
}
.privacy-title {
    font-size: 32rpx;
    font-weight: 600;
    color: var(--text-color);
}
.privacy-content {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}
.privacy-text {
    font-size: 26rpx;
    color: var(--text-secondary);
    line-height: 1.6;
}
.privacy-link {
    font-size: 26rpx;
    color: var(--primary-color);
    text-decoration: underline;
    margin-left

在HarmonyOS Next中,为应用配置应用权限说明需在项目的module.json5配置文件中的abilitiesextensionAbilities字段内,为每个需要权限的Ability添加permissions数组,并声明所需权限的名称。同时,必须在module.json5requestPermissions字段中,对应用所需的所有权限进行统一声明,明确其使用场景与目的。权限名称通常遵循反向域名格式,如ohos.permission.INTERNET。配置后,系统会在应用安装或运行时根据此说明向用户请求授权。

在HarmonyOS Next中,为应用配置权限说明是上架应用市场的关键合规步骤。以下是核心配置方法:

1. 权限说明的配置位置 在应用的 module.json5 配置文件中的 module 字段下,使用 requestPermissions 数组为每个需要声明的敏感权限添加 reasonreasonId 字段。

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:reason_internet",
        "reasonId": 1
      },
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:reason_camera",
        "reasonId": 2
      }
    ]
  }
}

2. 说明内容要求

  • reason 字段:必须清晰、具体地说明该权限在应用内的使用场景和目的。例如,相机权限应说明用于“扫描二维码登录”或“拍摄用户头像”,而非笼统地写“用于拍照功能”。
  • 说明内容需与应用的《隐私政策》文档中相关描述保持一致。
  • 必须使用多语言字符串资源($string: 引用),以适应不同语言环境。

3. 需重点说明的敏感权限类型 主要包括但不限于:

  • 设备资源权限:CAMERA(相机)、MICROPHONE(麦克风)、LOCATION(位置)等。
  • 数据访问权限:READ_MEDIA(读取媒体文件)、ACTIVITY_MOTION(获取运动数据)等。
  • 其他敏感权限:如 MANAGE_EXTERNAL_STORAGE(管理外部存储)等。

4. 关联隐私政策 在应用内《隐私政策》的对应章节中,必须逐一列出所有声明的敏感权限,并给出与 reason 字段一致或更详细的使用目的说明。这是应用审核的重点。

总结:正确配置的核心是在 module.json5 中为每个敏感权限提供场景化的 reason,并确保与隐私政策内容联动。这不仅是开发规范,更是保护用户知情权的必要措施。

回到顶部