欢迎光临
我们一直在努力

HarmonyOS 6学习:Screen Time Guard Kit实现应用时长精准管控

当数字健康成为刚需:如何优雅地管理屏幕时间

你是否也遇到过这样的情况?本打算只看10分钟短视频,结果一抬头两小时过去了;计划晚上10点前睡觉,却被手机"绑架"到凌晨;孩子沉迷游戏,每天使用时间远超约定时长。在数字设备无处不在的今天,屏幕时间管理已从"可有可无"变成了"必须要有"的功能。

上周,我的同事小李向我抱怨:"我家孩子每天玩手机超过3小时,说好的一小时根本管不住。" 我问他:"为什么不用系统自带的屏幕时间管理?" 他无奈地说:"试过了,但只能简单限制,没法针对具体应用设置,而且孩子总能找到办法绕过限制。"

今天,我就来揭秘HarmonyOS中的一个强大工具——Screen Time Guard Kit,它不仅能帮家长管控孩子的设备使用,还能帮我们这些"拖延症晚期患者"实现自我管理。更重要的是,我们可以基于这个Kit开发出更加灵活、精准的应用时长管控功能。

Screen Time Guard Kit:不仅仅是"防沉迷"

什么是Screen Time Guard Kit?

Screen Time Guard Kit是HarmonyOS提供的一套屏幕时间守护服务开发套件。与普通用户设置中的"屏幕使用时间"不同,开发者可以通过这套Kit实现:

  • 应用级精准管控:针对单个应用设置使用时长

  • 时间策略多样化:支持每日总时长、特定时间段、黑白名单等多种策略

  • 智能提醒与拦截:使用时间到达限制前的智能提醒

  • 跨设备协同:在多设备间同步屏幕时间策略

  • 核心概念解析

    在深入了解实现之前,我们先理清几个关键概念:

    // 屏幕时间管控的核心架构
    interface ScreenTimeGuardSystem {
    // 1. 策略(Policy):定义管控规则
    policies: TimeStrategy[]

    // 2. 守护服务(Guard Service):执行管控
    guardService: ScreenTimeGuardService

    // 3. 状态监控(Status Monitor):实时反馈
    statusMonitor: PolicyStatusMonitor
    }

    关键理解:Screen Time Guard Kit不是简单的"定时关闭",而是一套完整的策略执行系统。它包含策略定义、策略执行、状态反馈三个核心部分。

    实战:实现"每天只能使用1小时"的精准管控

    场景分析:家长控制模式的真实需求

    让我们从一个真实场景开始:家长希望孩子每天只能使用教育类应用1小时,但可以随时使用,不受固定时间段限制。

    传统方案的痛点:

  • 系统自带功能只能限制"每天总时长",无法分应用设置

  • 时间到了直接强制退出,没有缓冲期

  • 无法记录使用历史,难以复盘

  • 孩子可以切换账号绕过限制

  • 我们的解决方案:

  • 按应用分别设置时长限制

  • 使用前5分钟智能提醒

  • 生成详细的使用报告

  • 支持临时授权和奖励机制

  • 步骤1:权限申请——安全第一

    在HarmonyOS中,屏幕时间管理属于敏感权限,需要用户明确授权:

    // ScreenTimeGuardManager.ets
    import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
    import common from '@ohos.app.ability.common';

    export class ScreenTimeGuardManager {
    private context: common.UIAbilityContext;
    private atManager: abilityAccessCtrl.AtManager;

    constructor(context: common.UIAbilityContext) {
    this.context = context;
    this.atManager = abilityAccessCtrl.createAtManager();
    }

    // 检查并申请权限
    async checkAndRequestPermission(): Promise<boolean> {
    try {
    // 1. 检查是否已有权限
    const permissions: Array<string> = [
    'ohos.permission.MANAGE_SCREEN_TIME_GUARD'
    ];

    const grantStatus = await this.atManager.checkAccessToken(
    this.context.tokenId,
    permissions[0]
    );

    console.log(`[ScreenTime] 权限检查结果: ${grantStatus}`);

    // 2. 如果没有权限,请求权限
    if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
    console.log('[ScreenTime] 请求屏幕时间管理权限');

    // 显示权限请求弹窗
    const requestResult = await this.requestPermission();

    if (requestResult === 0) { // 用户同意
    console.log('[ScreenTime] 用户已授权');
    return true;
    } else {
    console.warn('[ScreenTime] 用户拒绝授权');

    // 显示引导提示
    await this.showPermissionGuide();
    return false;
    }
    }

    return true;
    } catch (error) {
    console.error('[ScreenTime] 权限检查失败:', error);
    return false;
    }
    }

    // 请求权限的具体实现
    private async requestPermission(): Promise<number> {
    return new Promise((resolve) => {
    // 这里需要实现权限请求逻辑
    // 实际开发中会使用系统的权限请求API
    console.log('[ScreenTime] 显示权限请求对话框');
    resolve(0); // 模拟用户同意
    });
    }

    // 显示权限引导
    private async showPermissionGuide(): Promise<void> {
    // 显示为什么需要这个权限的解释
    console.log('[ScreenTime] 显示权限引导说明');

    // 可以引导用户到设置中手动开启
    // 或者提供详细的解释说明
    }

    // 验证权限的有效性
    async validatePermission(): Promise<boolean> {
    try {
    // 在实际应用中,这里可能需要验证权限是否真的有效
    // 而不仅仅是检查grant status
    return await this.checkAndRequestPermission();
    } catch (error) {
    console.error('[ScreenTime] 权限验证失败:', error);
    return false;
    }
    }
    }

    重要说明:ohos.permission.MANAGE_SCREEN_TIME_GUARD是一个受限权限(ACL权限),这意味着:

  • 需要用户手动授权:无法在安装时静默获取

  • 需要在config.json中声明:

  • {
    "module": {
    "requestPermissions": [
    {
    "name": "ohos.permission.MANAGE_SCREEN_TIME_GUARD",
    "reason": "需要此权限来管理屏幕使用时间",
    "usedScene": {
    "ability": ["MainAbility"],
    "when": "always"
    }
    }
    ]
    }
    }

  • 需要合理的解释:在请求权限时,必须向用户清晰说明为什么需要这个权限

  • 步骤2:创建时长管控策略

    这是Screen Time Guard Kit最核心的部分。我们来实现一个"每天1小时"的策略:

    // TimePolicyManager.ets
    import screenTimeGuard from '@ohos.screenTimeGuard';

    export class TimePolicyManager {
    private screenTimeGuard: screenTimeGuard.ScreenTimeGuard;

    constructor() {
    this.screenTimeGuard = screenTimeGuard.getScreenTimeGuard();
    }

    // 创建每日时长策略
    async createDailyLimitPolicy(
    appBundleName: string, // 要管控的应用包名
    dailyLimitMinutes: number, // 每日限制分钟数
    policyName: string = '每日限制策略'
    ): Promise<string | null> {
    try {
    // 1. 创建时长策略
    const timeStrategy: screenTimeGuard.TimeStrategy = {
    // 策略类型:DURATION_TYPE 表示时长策略
    timeStrategyType: screenTimeGuard.TimeStrategyType.DURATION_TYPE,

    // 总时长限制(必填):单位毫秒
    totalDuration: dailyLimitMinutes * 60 * 1000,

    // 起止时间(非必填,对于时长策略可以不填,表示全天任意时间)
    startTime: undefined,
    endTime: undefined,

    // 限制类型:TRUSTLIST_TYPE 表示白名单,DENYLIST_TYPE 表示黑名单
    // 这里我们不需要黑白名单,所以不设置
    restrictionType: undefined,

    // 循环规则:每天生效
    recurrenceRule: {
    frequency: screenTimeGuard.RecurrenceFrequency.DAILY,
    interval: 1, // 每天
    endTime: undefined // 不设结束时间,永久有效
    }
    };

    // 2. 创建策略参数
    const policyParams: screenTimeGuard.PolicyParams = {
    policyName: policyName,
    description: `限制 ${appBundleName} 每日使用 ${dailyLimitMinutes} 分钟`,
    timeStrategy: timeStrategy,

    // 目标应用:可以指定多个应用
    targetBundleNames: [appBundleName],

    // 生效日期范围
    effectiveDate: {
    startTime: Date.now(), // 立即生效
    endTime: undefined // 不设结束时间
    },

    // 通知设置
    notificationConfig: {
    enableReminder: true,
    // 使用时间达到80%时提醒
    reminderThreshold: 0.8,
    // 提前5分钟提醒
    advanceMinutes: 5
    },

    // 超时后的行为
    timeoutAction: {
    actionType: screenTimeGuard.TimeoutActionType.BLOCK_LAUNCH,
    // 是否允许用户申请额外时间
    allowExtension: true,
    // 额外时间的申请流程配置
    extensionConfig: {
    maxExtensionTimes: 2, // 最多可申请2次
    extensionDurationPerTime: 10 * 60 * 1000, // 每次10分钟
    requireParentApproval: true // 需要家长批准
    }
    }
    };

    // 3. 添加策略
    const policyId = await this.screenTimeGuard.addPolicy(policyParams);

    console.log(`[ScreenTime] 策略创建成功,ID: ${policyId}`);
    console.log(`[ScreenTime] 策略详情:`, JSON.stringify(policyParams, null, 2));

    return policyId;
    } catch (error) {
    console.error('[ScreenTime] 创建策略失败:', error);

    // 错误处理
    if (error.code === 201) {
    console.error('[ScreenTime] 权限不足,请检查权限设置');
    } else if (error.code === 202) {
    console.error('[ScreenTime] 参数错误,请检查策略参数');
    } else if (error.code === 203) {
    console.error('[ScreenTime] 策略已存在或冲突');
    }

    return null;
    }
    }

    // 创建时间段限制策略(比如:晚上10点后禁止使用)
    async createTimeSlotPolicy(
    appBundleName: string,
    startHour: number, // 开始时间(小时)
    startMinute: number, // 开始时间(分钟)
    endHour: number, // 结束时间(小时)
    endMinute: number // 结束时间(分钟)
    ): Promise<string | null> {
    try {
    // 计算时间戳(今天的时间)
    const now = new Date();
    const startTime = new Date(
    now.getFullYear(),
    now.getMonth(),
    now.getDate(),
    startHour,
    startMinute
    ).getTime();

    const endTime = new Date(
    now.getFullYear(),
    now.getMonth(),
    now.getDate(),
    endHour,
    endMinute
    ).getTime();

    // 如果结束时间小于开始时间,表示跨天
    const adjustedEndTime = endTime < startTime ?
    endTime + 24 * 60 * 60 * 1000 : endTime;

    const timeStrategy: screenTimeGuard.TimeStrategy = {
    timeStrategyType: screenTimeGuard.TimeStrategyType.TIME_SLOT_TYPE,
    startTime: startTime,
    endTime: adjustedEndTime,
    totalDuration: undefined, // 时间段策略不需要总时长
    recurrenceRule: {
    frequency: screenTimeGuard.RecurrenceFrequency.DAILY,
    interval: 1
    }
    };

    const policyParams: screenTimeGuard.PolicyParams = {
    policyName: '晚间禁用策略',
    description: `限制 ${appBundleName} 在 ${startHour}:${startMinute} 到 ${endHour}:${endMinute} 期间使用`,
    timeStrategy: timeStrategy,
    targetBundleNames: [appBundleName],
    effectiveDate: {
    startTime: Date.now(),
    endTime: undefined
    },
    timeoutAction: {
    actionType: screenTimeGuard.TimeoutActionType.BLOCK_LAUNCH
    }
    };

    return await this.screenTimeGuard.addPolicy(policyParams);
    } catch (error) {
    console.error('[ScreenTime] 创建时间段策略失败:', error);
    return null;
    }
    }

    // 创建应用分类策略(比如:限制所有游戏类应用)
    async createCategoryPolicy(
    category: string, // 应用分类,如:game、social、education
    dailyLimitMinutes: number
    ): Promise<string | null> {
    try {
    // 注意:这里需要先获取该分类下的所有应用
    const appsInCategory = await this.getAppsByCategory(category);

    if (appsInCategory.length === 0) {
    console.warn(`[ScreenTime] 分类 ${category} 下没有找到应用`);
    return null;
    }

    const timeStrategy: screenTimeGuard.TimeStrategy = {
    timeStrategyType: screenTimeGuard.TimeStrategyType.DURATION_TYPE,
    totalDuration: dailyLimitMinutes * 60 * 1000
    };

    const policyParams: screenTimeGuard.PolicyParams = {
    policyName: `${category}类应用限制`,
    description: `限制所有${this.getCategoryName(category)}应用每日使用${dailyLimitMinutes}分钟`,
    timeStrategy: timeStrategy,
    targetBundleNames: appsInCategory,
    effectiveDate: {
    startTime: Date.now(),
    endTime: undefined
    }
    };

    return await this.screenTimeGuard.addPolicy(policyParams);
    } catch (error) {
    console.error('[ScreenTime] 创建分类策略失败:', error);
    return null;
    }
    }

    // 辅助方法:获取分类下的应用
    private async getAppsByCategory(category: string): Promise<string[]> {
    // 这里需要实现获取应用分类的逻辑
    // 实际开发中可能需要查询应用管理服务
    console.log(`[ScreenTime] 获取 ${category} 分类下的应用`);

    // 模拟返回
    switch (category) {
    case 'game':
    return ['com.example.game1', 'com.example.game2'];
    case 'social':
    return ['com.example.social1', 'com.example.social2'];
    case 'education':
    return ['com.example.edu1', 'com.example.edu2'];
    default:
    return [];
    }
    }

    // 辅助方法:获取分类名称
    private getCategoryName(category: string): string {
    const categoryMap: Record<string, string> = {
    'game': '游戏',
    'social': '社交',
    'education': '教育',
    'productivity': '效率工具',
    'entertainment': '娱乐'
    };
    return categoryMap[category] || category;
    }
    }

    策略类型详解:

  • DURATION_TYPE(时长策略):

    • 核心:限制总使用时长

    • 场景:每天只能用1小时

    • 关键参数:totalDuration(必填)

  • TIME_SLOT_TYPE(时间段策略):

    • 核心:限制使用时间段

    • 场景:晚上10点后禁止使用

    • 关键参数:startTime、endTime(必填)

  • TRUSTLIST_TYPE(白名单策略):

    • 核心:只允许特定应用

    • 场景:学习模式下只允许教育应用

    • 关键参数:restrictionType必须设置为TRUSTLIST_TYPE

  • 步骤3:策略管理与监控

    创建策略只是第一步,我们还需要管理策略的状态和监控执行情况:

    // PolicyMonitor.ets
    import screenTimeGuard from '@ohos.screenTimeGuard';

    export class PolicyMonitor {
    private screenTimeGuard: screenTimeGuard.ScreenTimeGuard;
    private policyCallbacks: Map<string, (status: screenTimeGuard.PolicyStatus) => void> = new Map();

    constructor() {
    this.screenTimeGuard = screenTimeGuard.getScreenTimeGuard();
    }

    // 启动策略
    async startPolicy(policyId: string): Promise<boolean> {
    try {
    await this.screenTimeGuard.startPolicy(policyId);
    console.log(`[ScreenTime] 策略 ${policyId} 已启动`);
    return true;
    } catch (error) {
    console.error(`[ScreenTime] 启动策略失败 ${policyId}:`, error);
    return false;
    }
    }

    // 停止策略
    async stopPolicy(policyId: string): Promise<boolean> {
    try {
    await this.screenTimeGuard.stopPolicy(policyId);
    console.log(`[ScreenTime] 策略 ${policyId} 已停止`);
    return true;
    } catch (error) {
    console.error(`[ScreenTime] 停止策略失败 ${policyId}:`, error);
    return false;
    }
    }

    // 删除策略
    async removePolicy(policyId: string): Promise<boolean> {
    try {
    await this.screenTimeGuard.removePolicy(policyId);
    console.log(`[ScreenTime] 策略 ${policyId} 已删除`);
    return true;
    } catch (error) {
    console.error(`[ScreenTime] 删除策略失败 ${policyId}:`, error);
    return false;
    }
    }

    // 查询策略状态
    async getPolicyStatus(policyId: string): Promise<screenTimeGuard.PolicyStatus | null> {
    try {
    const status = await this.screenTimeGuard.getPolicyStatus(policyId);
    console.log(`[ScreenTime] 策略 ${policyId} 状态:`, status);
    return status;
    } catch (error) {
    console.error(`[ScreenTime] 查询策略状态失败 ${policyId}:`, error);
    return null;
    }
    }

    // 查询所有策略
    async getAllPolicies(): Promise<screenTimeGuard.PolicyInfo[]> {
    try {
    const policies = await this.screenTimeGuard.getAllPolicies();
    console.log(`[ScreenTime] 共找到 ${policies.length} 个策略`);

    // 打印每个策略的详细信息
    policies.forEach((policy, index) => {
    console.log(`策略 ${index + 1}:`);
    console.log(` ID: ${policy.policyId}`);
    console.log(` 名称: ${policy.policyName}`);
    console.log(` 状态: ${policy.status}`);
    console.log(` 目标应用: ${policy.targetBundleNames?.join(', ') || '无'}`);

    if (policy.timeStrategy) {
    console.log(` 策略类型: ${this.getStrategyTypeName(policy.timeStrategy.timeStrategyType)}`);

    if (policy.timeStrategy.totalDuration) {
    const minutes = Math.floor(policy.timeStrategy.totalDuration / 60000);
    console.log(` 限制时长: ${minutes} 分钟`);
    }

    if (policy.timeStrategy.startTime && policy.timeStrategy.endTime) {
    const start = new Date(policy.timeStrategy.startTime).toLocaleTimeString();
    const end = new Date(policy.timeStrategy.endTime).toLocaleTimeString();
    console.log(` 限制时段: ${start} – ${end}`);
    }
    }
    });

    return policies;
    } catch (error) {
    console.error('[ScreenTime] 查询所有策略失败:', error);
    return [];
    }
    }

    // 注册策略状态监听
    registerPolicyListener(
    policyId: string,
    callback: (status: screenTimeGuard.PolicyStatus) => void
    ): void {
    try {
    this.screenTimeGuard.on('policyStatusChange', (status: screenTimeGuard.PolicyStatus) => {
    if (status.policyId === policyId) {
    console.log(`[ScreenTime] 策略 ${policyId} 状态变化:`, status);
    callback(status);
    }
    });

    this.policyCallbacks.set(policyId, callback);
    console.log(`[ScreenTime] 已注册策略 ${policyId} 的状态监听`);
    } catch (error) {
    console.error(`[ScreenTime] 注册策略监听失败 ${policyId}:`, error);
    }
    }

    // 取消策略状态监听
    unregisterPolicyListener(policyId: string): void {
    try {
    this.screenTimeGuard.off('policyStatusChange');
    this.policyCallbacks.delete(policyId);
    console.log(`[ScreenTime] 已取消策略 ${policyId} 的状态监听`);
    } catch (error) {
    console.error(`[ScreenTime] 取消策略监听失败 ${policyId}:`, error);
    }
    }

    // 获取应用使用统计
    async getAppUsageStats(
    bundleName: string,
    startTime: number,
    endTime: number
    ): Promise<screenTimeGuard.AppUsageStats | null> {
    try {
    const stats = await this.screenTimeGuard.getAppUsageStats(
    bundleName,
    startTime,
    endTime
    );

    console.log(`[ScreenTime] 应用 ${bundleName} 使用统计:`, {
    '总使用时间': `${Math.floor(stats.totalTimeUsed / 60000)} 分钟`,
    '使用次数': stats.timesUsed,
    '最后使用时间': new Date(stats.lastTimeUsed).toLocaleString()
    });

    return stats;
    } catch (error) {
    console.error(`[ScreenTime] 获取应用使用统计失败 ${bundleName}:`, error);
    return null;
    }
    }

    // 获取今日使用情况
    async getTodayUsage(bundleName: string): Promise<number> {
    const now = Date.now();
    const startOfDay = new Date();
    startOfDay.setHours(0, 0, 0, 0);

    const stats = await this.getAppUsageStats(
    bundleName,
    startOfDay.getTime(),
    now
    );

    return stats?.totalTimeUsed || 0;
    }

    // 检查应用是否被限制
    async isAppRestricted(bundleName: string): Promise<boolean> {
    try {
    const policies = await this.getAllPolicies();

    for (const policy of policies) {
    // 检查策略是否针对此应用
    if (policy.targetBundleNames?.includes(bundleName)) {
    // 检查策略是否启用
    if (policy.status === screenTimeGuard.PolicyStatus.ACTIVE) {
    return true;
    }
    }
    }

    return false;
    } catch (error) {
    console.error(`[ScreenTime] 检查应用限制状态失败 ${bundleName}:`, error);
    return false;
    }
    }

    // 获取策略类型名称
    private getStrategyTypeName(type: screenTimeGuard.TimeStrategyType): string {
    const typeNames = {
    [screenTimeGuard.TimeStrategyType.DURATION_TYPE]: '时长策略',
    [screenTimeGuard.TimeStrategyType.TIME_SLOT_TYPE]: '时间段策略',
    [screenTimeGuard.TimeStrategyType.TRUSTLIST_TYPE]: '白名单策略'
    };
    return typeNames[type] || '未知类型';
    }
    }

    步骤4:实现用户界面与交互

    有了后台逻辑,我们需要一个友好的用户界面来管理这些策略:

    // ScreenTimeUI.ets
    @Entry
    @Component
    struct ScreenTimeManagement {
    @State policyList: Array<PolicyItem> = []
    @State isAddingPolicy: boolean = false
    @State selectedApp: AppInfo | null = null
    @State dailyLimit: number = 60 // 默认60分钟

    // 策略管理器
    private policyManager: TimePolicyManager = new TimePolicyManager()
    private policyMonitor: PolicyMonitor = new PolicyMonitor()
    private permissionManager: ScreenTimeGuardManager

    aboutToAppear(): void {
    this.permissionManager = new ScreenTimeGuardManager(getContext(this) as common.UIAbilityContext)
    this.initScreenTime()
    }

    // 初始化屏幕时间管理
    async initScreenTime(): Promise<void> {
    // 1. 检查并申请权限
    const hasPermission = await this.permissionManager.checkAndRequestPermission()

    if (!hasPermission) {
    promptAction.showToast({
    message: '需要屏幕时间管理权限才能继续',
    duration: 3000
    })
    return
    }

    // 2. 加载现有策略
    await this.loadPolicies()

    // 3. 加载应用列表
    await this.loadApps()
    }

    // 加载现有策略
    async loadPolicies(): Promise<void> {
    const policies = await this.policyMonitor.getAllPolicies()

    this.policyList = policies.map(policy => ({
    id: policy.policyId,
    name: policy.policyName,
    description: policy.description || '无描述',
    status: policy.status,
    targetApps: policy.targetBundleNames || [],
    strategyType: policy.timeStrategy?.timeStrategyType,
    createdAt: policy.createdTime || Date.now()
    }))
    }

    // 加载应用列表
    async loadApps(): Promise<void> {
    // 这里需要实现获取设备上安装的应用
    // 简化的示例
    const mockApps: AppInfo[] = [
    { bundleName: 'com.example.game1', name: '王者荣耀', icon: 'game_icon', category: 'game' },
    { bundleName: 'com.example.social1', name: '微信', icon: 'social_icon', category: 'social' },
    { bundleName: 'com.example.edu1', name: '学习强国', icon: 'edu_icon', category: 'education' },
    { bundleName: 'com.example.video1', name: '抖音', icon: 'video_icon', category: 'entertainment' }
    ]

    // 在实际开发中,这里应该调用系统API获取真实应用列表
    this.appList = mockApps
    }

    // 创建每日限制策略
    async createDailyLimit(): Promise<void> {
    if (!this.selectedApp) {
    promptAction.showToast({
    message: '请先选择应用',
    duration: 2000
    })
    return
    }

    if (this.dailyLimit <= 0) {
    promptAction.showToast({
    message: '请设置有效的时长限制',
    duration: 2000
    })
    return
    }

    const policyName = `限制${this.selectedApp.name}每日使用`

    const policyId = await this.policyManager.createDailyLimitPolicy(
    this.selectedApp.bundleName,
    this.dailyLimit,
    policyName
    )

    if (policyId) {
    // 启动策略
    const started = await this.policyMonitor.startPolicy(policyId)

    if (started) {
    promptAction.showToast({
    message: `已限制 ${this.selectedApp.name} 每日使用 ${this.dailyLimit} 分钟`,
    duration: 3000
    })

    // 重新加载策略列表
    await this.loadPolicies()

    // 注册状态监听
    this.policyMonitor.registerPolicyListener(policyId, (status) => {
    this.onPolicyStatusChanged(status)
    })
    }
    }
    }

    // 策略状态变化回调
    onPolicyStatusChanged(status: screenTimeGuard.PolicyStatus): void {
    console.log(`策略 ${status.policyId} 状态变化:`, status)

    // 更新UI中的策略状态
    this.policyList = this.policyList.map(policy => {
    if (policy.id === status.policyId) {
    return { …policy, status: status.status }
    }
    return policy
    })

    // 显示通知
    if (status.status === screenTimeGuard.PolicyStatus.TIME_LIMIT_REACHED) {
    this.showTimeLimitNotification(status)
    }
    }

    // 显示时间限制通知
    showTimeLimitNotification(status: screenTimeGuard.PolicyStatus): void {
    // 查找对应的应用
    const policy = this.policyList.find(p => p.id === status.policyId)
    if (policy && policy.targetApps.length > 0) {
    const appName = this.getAppName(policy.targetApps[0])

    promptAction.showDialog({
    title: '使用时间提醒',
    message: `${appName} 今日使用时间已到限制`,
    buttons: [
    {
    text: '知道了',
    color: '#007DFF'
    },
    {
    text: '申请额外时间',
    color: '#FF6B6B',
    action: () => {
    this.requestExtraTime(policy.id)
    }
    }
    ]
    })
    }
    }

    // 申请额外时间
    async requestExtraTime(policyId: string): Promise<void> {
    // 这里可以实现申请额外时间的逻辑
    // 比如:向家长发送申请,或者使用预先设置的额外时间

    promptAction.showToast({
    message: '已发送额外时间申请',
    duration: 2000
    })
    }

    // 切换策略状态
    async togglePolicy(policyId: string, enable: boolean): Promise<void> {
    if (enable) {
    await this.policyMonitor.startPolicy(policyId)
    } else {
    await this.policyMonitor.stopPolicy(policyId)
    }

    await this.loadPolicies()
    }

    // 删除策略
    async deletePolicy(policyId: string): Promise<void> {
    promptAction.showActionMenu({
    title: '确认删除',
    buttons: [
    { text: '取消', color: '#666666' },
    { text: '删除', color: '#FF3B30' }
    ]
    }).then((result) => {
    if (result.index === 1) { // 点击了删除
    this.policyMonitor.removePolicy(policyId).then(() => {
    this.loadPolicies()
    })
    }
    })
    }

    build() {
    Column({ space: 0 }) {
    // 标题栏
    Row({ space: 12 }) {
    Text('屏幕时间管理')
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
    .fontColor('#000000')

    Blank()

    Button('添加限制')
    .fontSize(14)
    .backgroundColor('#007DFF')
    .fontColor('#FFFFFF')
    .onClick(() => {
    this.isAddingPolicy = true
    })
    }
    .width('100%')
    .padding(20)
    .backgroundColor('#FFFFFF')

    // 策略列表
    List({ space: 10 }) {
    ForEach(this.policyList, (policy: PolicyItem) => {
    ListItem() {
    PolicyItemView({
    policy: policy,
    onToggle: (enabled: boolean) => {
    this.togglePolicy(policy.id, enabled)
    },
    onDelete: () => {
    this.deletePolicy(policy.id)
    }
    })
    }
    })
    }
    .width('100%')
    .layoutWeight(1)

    // 添加策略对话框
    if (this.isAddingPolicy) {
    this.AddPolicyDialog()
    }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    }

    @Builder
    AddPolicyDialog() {
    Column({ space: 20 }) {
    // 对话框标题
    Text('添加应用使用限制')
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .fontColor('#000000')
    .margin({ top: 20 })

    // 应用选择
    Column({ space: 8 }) {
    Text('选择应用')
    .fontSize(14)
    .fontColor('#666666')
    .align(Alignment.Start)
    .width('100%')

    // 应用列表(简化显示)
    if (this.selectedApp) {
    Row({ space: 10 }) {
    Image(this.selectedApp.icon)
    .width(40)
    .height(40)
    .borderRadius(8)

    Column({ space: 4 }) {
    Text(this.selectedApp.name)
    .fontSize(16)
    .fontColor('#000000')

    Text(this.selectedApp.bundleName)
    .fontSize(12)
    .fontColor('#999999')
    }

    Blank()

    Button('更换')
    .fontSize(12)
    .onClick(() => {
    this.showAppSelector()
    })
    }
    .width('100%')
    .padding(12)
    .backgroundColor('#FFFFFF')
    .borderRadius(8)
    } else {
    Button('选择应用')
    .width('100%')
    .height(48)
    .backgroundColor('#FFFFFF')
    .onClick(() => {
    this.showAppSelector()
    })
    }
    }
    .width('100%')
    .padding({ left: 20, right: 20 })

    // 时长设置
    Column({ space: 8 }) {
    Text('每日使用限制')
    .fontSize(14)
    .fontColor('#666666')
    .align(Alignment.Start)
    .width('100%')

    Row({ space: 20 }) {
    Slider({
    value: this.dailyLimit,
    min: 5,
    max: 240,
    step: 5,
    style: SliderStyle.InSet
    })
    .width('70%')
    .onChange((value: number) => {
    this.dailyLimit = value
    })

    Text(`${this.dailyLimit} 分钟`)
    .fontSize(16)
    .fontColor('#007DFF')
    .fontWeight(FontWeight.Medium)
    }
    .width('100%')
    }
    .width('100%')
    .padding({ left: 20, right: 20 })

    // 按钮区域
    Row({ space: 12 }) {
    Button('取消')
    .layoutWeight(1)
    .height(44)
    .backgroundColor('#F2F2F2')
    .fontColor('#000000')
    .onClick(() => {
    this.isAddingPolicy = false
    })

    Button('确认')
    .layoutWeight(1)
    .height(44)
    .backgroundColor('#007DFF')
    .fontColor('#FFFFFF')
    .onClick(() => {
    this.createDailyLimit()
    this.isAddingPolicy = false
    })
    }
    .width('100%')
    .padding(20)
    }
    .width('90%')
    .borderRadius(16)
    .backgroundColor('#FFFFFF')
    .shadow({ radius: 20, color: '#1A000000' })
    .align(Alignment.Center)
    }

    // 显示应用选择器
    showAppSelector(): void {
    // 这里应该实现一个应用选择器
    // 由于篇幅限制,我们使用简化版本
    promptAction.showActionMenu({
    title: '选择应用',
    buttons: this.appList.map(app => ({
    text: app.name
    }))
    }).then((result) => {
    if (result.index >= 0) {
    this.selectedApp = this.appList[result.index]
    }
    })
    }
    }

    高级功能:智能策略与使用分析

    基本的时长限制只是开始,我们还可以实现更智能的功能:

    1. 使用习惯分析与智能提醒

    // UsageAnalyzer.ets
    export class UsageAnalyzer {
    private policyMonitor: PolicyMonitor

    constructor() {
    this.policyMonitor = new PolicyMonitor()
    }

    // 分析应用使用习惯
    async analyzeUsagePattern(bundleName: string, days: number = 7): Promise<UsagePattern> {
    const endTime = Date.now()
    const startTime = endTime – days * 24 * 60 * 60 * 1000

    // 获取历史使用数据
    const usageStats = await this.policyMonitor.getAppUsageStats(bundleName, startTime, endTime)

    if (!usageStats) {
    return {
    averageDailyUsage: 0,
    peakUsageHours: [],
    usageTrend: 'stable',
    recommendations: []
    }
    }

    // 分析使用模式
    const pattern: UsagePattern = {
    averageDailyUsage: this.calculateAverageUsage(usageStats, days),
    peakUsageHours: this.findPeakHours(usageStats),
    usageTrend: this.analyzeTrend(usageStats),
    recommendations: this.generateRecommendations(usageStats)
    }

    return pattern
    }

    // 生成智能限制策略
    async generateSmartPolicy(bundleName: string, appName: string): Promise<string | null> {
    // 分析使用习惯
    const pattern = await this.analyzeUsagePattern(bundleName)

    // 根据使用习惯生成策略
    let policyName = `智能限制-${appName}`
    let dailyLimit = 60 // 默认60分钟

    // 根据平均使用时间调整限制
    if (pattern.averageDailyUsage > 120) { // 超过2小时
    dailyLimit = 90 // 限制为1.5小时
    policyName += '(重度使用)'
    } else if (pattern.averageDailyUsage > 60) { // 1-2小时
    dailyLimit = 60 // 限制为1小时
    policyName += '(中度使用)'
    } else { // 少于1小时
    dailyLimit = 30 // 限制为30分钟
    policyName += '(轻度使用)'
    }

    // 在高峰时段加强限制
    const policyManager = new TimePolicyManager()

    // 创建主限制策略
    const mainPolicyId = await policyManager.createDailyLimitPolicy(
    bundleName,
    dailyLimit,
    policyName
    )

    if (!mainPolicyId) {
    return null
    }

    // 如果有明显的高峰时段,创建额外的时段限制
    if (pattern.peakUsageHours.length > 0) {
    for (const hour of pattern.peakUsageHours) {
    const timeSlotPolicyId = await policyManager.createTimeSlotPolicy(
    bundleName,
    hour, 0, // 开始时间
    hour + 2, 0 // 结束时间(2小时后)
    )

    if (timeSlotPolicyId) {
    console.log(`[UsageAnalyzer] 已创建高峰时段限制策略: ${hour}:00-${hour + 2}:00`)
    }
    }
    }

    return mainPolicyId
    }

    // 生成使用报告
    async generateUsageReport(bundleName: string, appName: string): Promise<UsageReport> {
    const todayUsage = await this.policyMonitor.getTodayUsage(bundleName)
    const pattern = await this.analyzeUsagePattern(bundleName)

    const todayMinutes = Math.floor(todayUsage / 60000)
    const averageMinutes = Math.floor(pattern.averageDailyUsage / 60000)

    return {
    appName: appName,
    bundleName: bundleName,
    todayUsage: todayUsage,
    todayMinutes: todayMinutes,
    averageDailyUsage: pattern.averageDailyUsage,
    averageMinutes: averageMinutes,
    peakHours: pattern.peakUsageHours,
    trend: pattern.usageTrend,
    recommendations: pattern.recommendations,
    generatedAt: Date.now()
    }
    }
    }

    2. 家庭共享与家长控制

    // FamilyGuardManager.ets
    export class FamilyGuardManager {
    // 创建儿童账户限制
    async createChildProfilePolicy(childBundleName: string): Promise<string[]> {
    const policyIds: string[] = []
    const policyManager = new TimePolicyManager()

    // 1. 游戏类应用:每天1小时
    const gamePolicyId = await policyManager.createCategoryPolicy('game', 60)
    if (gamePolicyId) policyIds.push(gamePolicyId)

    // 2. 社交应用:每天30分钟
    const socialPolicyId = await policyManager.createCategoryPolicy('social', 30)
    if (socialPolicyId) policyIds.push(socialPolicyId)

    // 3. 视频应用:工作日30分钟,周末1小时
    const videoPolicyId = await this.createWeekendPolicy('entertainment', 30, 60)
    if (videoPolicyId) policyIds.push(videoPolicyId)

    // 4. 晚上9点后禁止使用
    const nightPolicyId = await policyManager.createTimeSlotPolicy(
    childBundleName,
    21, 0, // 晚上9点
    7, 0 // 早上7点
    )
    if (nightPolicyId) policyIds.push(nightPolicyId)

    return policyIds
    }

    // 创建周末不同限制的策略
    private async createWeekendPolicy(
    category: string,
    weekdayMinutes: number,
    weekendMinutes: number
    ): Promise<string | null> {
    // 这里需要更复杂的逻辑来处理工作日和周末的区别
    // 简化实现:创建两个策略,分别在工作日和周末生效

    const policyManager = new TimePolicyManager()

    // 实际实现需要考虑更复杂的日期判断
    return await policyManager.createCategoryPolicy(category, weekdayMinutes)
    }

    // 申请额外时间(孩子申请,家长批准)
    async requestExtraTime(
    policyId: string,
    childName: string,
    extraMinutes: number,
    reason: string
    ): Promise<boolean> {
    // 这里应该实现一个申请流程
    // 1. 孩子发起申请
    // 2. 通知家长
    // 3. 家长批准或拒绝
    // 4. 如果批准,临时调整策略

    console.log(`[FamilyGuard] ${childName} 申请额外 ${extraMinutes} 分钟,理由: ${reason}`)

    // 模拟家长批准
    const approved = await this.notifyParent(childName, extraMinutes, reason)

    if (approved) {
    return await this.grantExtraTime(policyId, extraMinutes)
    }

    return false
    }

    // 通知家长
    private async notifyParent(
    childName: string,
    extraMinutes: number,
    reason: string
    ): Promise<boolean> {
    // 这里应该发送通知给家长的设备
    // 简化实现:显示一个对话框

    return new Promise((resolve) => {
    promptAction.showDialog({
    title: '额外时间申请',
    message: `${childName} 申请额外使用 ${extraMinutes} 分钟\\n理由: ${reason}`,
    buttons: [
    {
    text: '拒绝',
    color: '#FF3B30',
    action: () => resolve(false)
    },
    {
    text: '批准',
    color: '#34C759',
    action: () => resolve(true)
    }
    ]
    })
    })
    }

    // 批准额外时间
    private async grantExtraTime(policyId: string, extraMinutes: number): Promise<boolean> {
    const policyMonitor = new PolicyMonitor()

    // 获取当前策略状态
    const status = await policyMonitor.getPolicyStatus(policyId)
    if (!status) return false

    // 临时调整策略
    // 注意:这里需要Screen Time Guard Kit提供临时调整的API
    // 如果Kit不支持,可能需要创建临时策略

    console.log(`[FamilyGuard] 已批准额外 ${extraMinutes} 分钟`)
    return true
    }
    }

    最佳实践与注意事项

    1. 权限请求的最佳时机

    // 错误的做法:应用启动时就请求所有权限
    aboutToAppear(): void {
    this.requestAllPermissions() // 用户可能不知道为什么要这些权限
    }

    // 正确的做法:在需要时请求,并提供清晰的解释
    async setupScreenTimeGuard(): Promise<void> {
    // 第一步:解释功能
    await this.explainFeature()

    // 第二步:用户确认后请求权限
    const userAgreed = await this.requestPermissionWithExplanation()

    if (userAgreed) {
    // 第三步:初始化功能
    await this.initializeScreenTimeGuard()
    }
    }

    private async explainFeature(): Promise<void> {
    return new Promise((resolve) => {
    promptAction.showDialog({
    title: '屏幕时间管理',
    message: '此功能可以帮助您或您的家人管理设备使用时间。\\n\\n我们需要以下权限:\\n• 管理应用使用时间\\n• 监控应用使用情况\\n\\n这些权限仅用于时间管理,不会访问您的个人数据。',
    buttons: [
    {
    text: '取消',
    color: '#666666',
    action: () => resolve()
    },
    {
    text: '继续',
    color: '#007DFF',
    action: () => resolve()
    }
    ]
    })
    })
    }

    2. 错误处理与兼容性

    class RobustScreenTimeManager {
    private isSupported: boolean = true

    constructor() {
    this.checkCompatibility()
    }

    // 检查设备兼容性
    private checkCompatibility(): void {
    try {
    // 检查API是否存在
    if (typeof screenTimeGuard === 'undefined') {
    this.isSupported = false
    console.warn('[ScreenTime] Screen Time Guard Kit 不支持此设备')
    return
    }

    // 检查API版本
    const version = screenTimeGuard.getVersion()
    console.log(`[ScreenTime] Screen Time Guard Kit 版本: ${version}`)

    if (version < '1.0.0') {
    console.warn('[ScreenTime] API版本过低,某些功能可能不可用')
    }

    } catch (error) {
    this.isSupported = false
    console.error('[ScreenTime] 兼容性检查失败:', error)
    }
    }

    // 安全地创建策略
    async safeCreatePolicy(params: screenTimeGuard.PolicyParams): Promise<string | null> {
    if (!this.isSupported) {
    console.warn('[ScreenTime] 设备不支持Screen Time Guard Kit')
    return null
    }

    try {
    return await screenTimeGuard.getScreenTimeGuard().addPolicy(params)
    } catch (error) {
    console.error('[ScreenTime] 创建策略失败:', error)

    // 根据错误类型采取不同措施
    switch (error.code) {
    case 201: // 权限错误
    console.error('[ScreenTime] 请检查权限设置')
    await this.showPermissionError()
    break

    case 202: // 参数错误
    console.error('[ScreenTime] 策略参数错误,请检查')
    await this.showParameterError(error.message)
    break

    case 203: // 策略冲突
    console.error('[ScreenTime] 策略已存在或冲突')
    await this.showConflictError()
    break

    default:
    console.error('[ScreenTime] 未知错误:', error)
    await this.showGenericError()
    }

    return null
    }
    }
    }

    3. 性能优化建议

    class OptimizedScreenTimeManager {
    private policyCache: Map<string, screenTimeGuard.PolicyStatus> = new Map()
    private lastUpdateTime: number = 0
    private readonly CACHE_DURATION = 5 * 60 * 1000 // 5分钟缓存

    // 带缓存的策略查询
    async getPolicyStatusWithCache(policyId: string): Promise<screenTimeGuard.PolicyStatus | null> {
    const now = Date.now()

    // 检查缓存
    if (this.policyCache.has(policyId)) {
    const cached = this.policyCache.get(policyId)!
    const cacheTime = cached.cacheTime || 0

    // 如果缓存未过期,使用缓存
    if (now – cacheTime < this.CACHE_DURATION) {
    console.log(`[ScreenTime] 使用缓存数据: ${policyId}`)
    return cached
    }
    }

    // 缓存过期或不存在,从API获取
    try {
    const status = await screenTimeGuard.getScreenTimeGuard().getPolicyStatus(policyId)

    if (status) {
    // 添加缓存时间
    ;(status as any).cacheTime = now
    this.policyCache.set(policyId, status)
    }

    return status
    } catch (error) {
    console.error(`[ScreenTime] 获取策略状态失败 ${policyId}:`, error)
    return null
    }
    }

    // 批量操作
    async batchUpdatePolicies(
    updates: Array<{ policyId: string; enabled: boolean }>
    ): Promise<Array<{ policyId: string; success: boolean }>> {
    const results: Array<{ policyId: string; success: boolean }> = []

    // 使用Promise.all并行执行
    const promises = updates.map(async (update) => {
    try {
    if (update.enabled) {
    await screenTimeGuard.getScreenTimeGuard().startPolicy(update.policyId)
    } else {
    await screenTimeGuard.getScreenTimeGuard().stopPolicy(update.policyId)
    }

    // 更新缓存
    if (this.policyCache.has(update.policyId)) {
    const status = this.policyCache.get(update.policyId)!
    status.status = update.enabled ?
    screenTimeGuard.PolicyStatus.ACTIVE :
    screenTimeGuard.PolicyStatus.INACTIVE
    ;(status as any).cacheTime = Date.now()
    }

    results.push({ policyId: update.policyId, success: true })
    } catch (error) {
    console.error(`[ScreenTime] 批量更新失败 ${update.policyId}:`, error)
    results.push({ policyId: update.policyId, success: false })
    }
    })

    await Promise.all(promises)
    return results
    }
    }

    实际应用场景示例

    场景1:家长控制应用

    // ParentControlApp.ets
    @Entry
    @Component
    struct ParentControlApp {
    @State childName: string = '小明'
    @State policies: ParentControlPolicy[] = []
    @State isSetupComplete: boolean = false

    private familyManager: FamilyGuardManager = new FamilyGuardManager()

    aboutToAppear(): void {
    this.loadChildProfile()
    }

    // 加载儿童配置
    async loadChildProfile(): Promise<void> {
    // 1. 从设置加载儿童信息
    const profile = await this.loadChildProfileFromSettings()

    if (profile) {
    this.childName = profile.name

    // 2. 创建或加载策略
    await this.setupPolicies(profile.bundleName)

    this.isSetupComplete = true
    }
    }

    // 设置策略
    async setupPolicies(childBundleName: string): Promise<void> {
    // 创建基础策略
    const policyIds = await this.familyManager.createChildProfilePolicy(childBundleName)

    this.policies = policyIds.map(id => ({
    id,
    name: this.getPolicyName(id),
    enabled: true,
    lastUpdated: Date.now()
    }))
    }

    build() {
    Column({ space: 0 }) {
    if (!this.isSetupComplete) {
    this.SetupGuide()
    } else {
    this.ControlPanel()
    }
    }
    }

    @Builder
    SetupGuide() {
    Column({ space: 20 }) {
    Image($r('app.media.family'))
    .width(200)
    .height(200)

    Text('家长控制')
    .fontSize(24)
    .fontWeight(FontWeight.Bold)

    Text('为您的孩子设置健康的设备使用习惯')
    .fontSize(16)
    .fontColor('#666666')
    .textAlign(TextAlign.Center)
    .padding({ left: 40, right: 40 })

    Column({ space: 10 }) {
    Row({ space: 12 }) {
    Image($r('app.media.icon_time'))
    .width(24)
    .height(24)

    Text('每日使用时间限制')
    .fontSize(16)
    }

    Row({ space: 12 }) {
    Image($r('app.media.icon_bedtime'))
    .width(24)
    .height(24)

    Text('睡前禁用时间')
    .fontSize(16)
    }

    Row({ space: 12 }) {
    Image($r('app.media.icon_education'))
    .width(24)
    .height(24)

    Text('学习时间管理')
    .fontSize(16)
    }
    }
    .padding(20)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .width('80%')

    Button('开始设置')
    .width('80%')
    .height(48)
    .backgroundColor('#007DFF')
    .fontColor('#FFFFFF')
    .margin({ top: 30 })
    }
    }
    }

    场景2:专注模式应用

    // FocusModeApp.ets
    @Entry
    @Component
    struct FocusModeApp {
    @State focusModeActive: boolean = false
    @State remainingTime: number = 25 * 60 // 25分钟
    @State blockedApps: string[] = ['com.example.social1', 'com.example.game1']

    private timer: number = 0

    // 开始专注模式
    startFocusMode(durationMinutes: number): void {
    this.focusModeActive = true
    this.remainingTime = durationMinutes * 60

    // 创建临时限制策略
    this.blockedApps.forEach(async (bundleName) => {
    const policyManager = new TimePolicyManager()
    await policyManager.createDailyLimitPolicy(bundleName, 0, '专注模式限制')
    })

    // 启动倒计时
    this.startTimer()
    }

    // 启动倒计时
    startTimer(): void {
    this.timer = setInterval(() => {
    if (this.remainingTime > 0) {
    this.remainingTime–
    } else {
    this.endFocusMode()
    }
    }, 1000)
    }

    // 结束专注模式
    endFocusMode(): void {
    this.focusModeActive = false
    clearInterval(this.timer)

    // 删除临时策略
    // … 实现策略删除逻辑
    }
    }

    总结

    通过本文的完整实现,我们深入探讨了HarmonyOS Screen Time Guard Kit的强大功能。从基础的单应用时长限制,到高级的家庭控制功能,再到智能的使用习惯分析,我们展示了如何构建一个完整的屏幕时间管理系统。

    核心收获

  • 权限管理是基础:ohos.permission.MANAGE_SCREEN_TIME_GUARD是受限权限,需要用户明确授权

  • 策略设计是关键:时长策略、时间段策略、白名单策略满足不同场景需求

  • 用户体验是核心:合理的提醒机制、临时授权、清晰的设置界面

  • 错误处理很重要:兼容性检查、网络异常处理、权限异常处理

  • 实际价值

    • 对家长:有效管理孩子的设备使用时间,培养健康习惯

    • 对个人:提高工作效率,减少无意识刷手机时间

    • 对开发者:为应用增加家长控制功能,提升产品价值

    • 对学校/企业:管理设备使用,提高学习/工作效率

    最佳实践

  • 渐进式引导:不要一开始就请求所有权限,在需要时逐步请求

  • 透明化设置:让用户清楚知道每个设置的作用

  • 灵活的例外:允许临时授权,避免过于死板

  • 数据可视化:通过图表展示使用情况,帮助用户理解

  • 多设备同步:在家庭场景中,策略应该在所有设备上生效

  • 扩展思考

    Screen Time Guard Kit的应用不仅限于"防沉迷",还可以扩展到:

  • 工作模式:工作时间只允许工作相关应用

  • 学习模式:学习时间屏蔽娱乐应用

  • 驾驶模式:驾驶时限制非必要交互

  • 健康提醒:根据使用时长提醒休息

  • 在数字健康日益重要的今天,一个好的屏幕时间管理系统不仅是功能,更是责任。通过HarmonyOS Screen Time Guard Kit,我们可以帮助用户建立健康的数字生活习惯,让科技真正服务于人,而不是控制人。

    记住,最好的技术是让人感觉不到技术的存在。Screen Time Guard Kit就是这样一种技术——它在后台默默工作,保护我们的时间,帮助我们成为更好的自己。

    赞(0)
    未经允许不得转载:171主机测评 » HarmonyOS 6学习:Screen Time Guard Kit实现应用时长精准管控
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址