k***@163.com
k***@163.com
  • 发布:2025-10-27 17:13
  • 更新:2025-10-27 17:13
  • 阅读:50

UniApp开发鸿蒙应用实践:从底部小白条到代理提醒的完整解决方案

分类:鸿蒙Next

前言

随着鸿蒙生态的快速发展,越来越多的开发者开始关注如何快速将现有应用适配到鸿蒙平台。UniApp作为一个成熟的跨平台开发框架,已经支持了鸿蒙应用的开发。然而在实际开发过程中,我们会遇到一些平台特有的问题和挑战。本文将基于一个服药提醒应用的开发实践,详细介绍如何解决鸿蒙平台的底部安全区适配问题,以及如何使用UTS插件实现代理提醒功能。

一、底部小白条问题的解决方案(SafeArea适配)

1.1 问题背景

在鸿蒙设备上,特别是全面屏设备,底部通常会有一个用于手势导航的"小白条"区域。这个区域被称为安全区域(Safe Area),如果应用界面没有正确处理这个区域,会导致底部内容被遮挡,影响用户体验。

1.2 SafeArea配置方案

UniApp为鸿蒙平台提供了完善的安全区域配置方案。我们需要在manifest.json文件中进行配置:

{  
  "app-harmony": {  
    "safearea": {  
      "background": "#ffffff",  
      "backgroundDark": "#2f0508",  
      "bottom": {  
        "offset": "none"  
      }  
    }  
  }  
}

配置说明:

  • background: 浅色模式下安全区域的背景色,这里设置为白色#ffffff,与应用主题保持一致
  • backgroundDark: 深色模式下安全区域的背景色,设置为深红色#2f0508,适配暗黑主题
  • bottom.offset: 底部区域占位策略,设置为"none"表示在没有TabBar时不需要占位

我们成功解决了底部小白条的适配问题,确保应用在各种鸿蒙设备上都能正常显示和交互。

二、代理提醒功能的UTS插件实现

2.1 代理提醒简介

代理提醒(Reminder Agent)是鸿蒙系统提供的一项重要能力,允许应用在后台设置定时提醒,即使应用被关闭也能准时触发。这对于服药提醒、日程管理等场景至关重要。

鸿蒙系统的代理提醒支持三种类型:

  • 闹钟提醒(ALARM): 基于时间的周期性提醒,适合每天固定时间的场景
  • 日历提醒(CALENDAR): 基于日期的事件提醒,适合特定日期的事件
  • 倒计时提醒(TIMER): 基于时长的一次性提醒,适合短期计时场景

2.2 为什么需要UTS插件

UniApp虽然支持鸿蒙平台,但并未内置代理提醒的API。要使用鸿蒙的原生能力,我们需要通过UTS(UniApp TypeScript)插件来调用鸿蒙的原生API。

UTS插件的优势:

  • 类型安全: 基于TypeScript,提供完整的类型检查
  • 性能优秀: 编译为原生代码,性能接近原生开发
  • 开发便捷: 语法接近TypeScript,学习成本低
  • 跨平台: 可以为不同平台编写不同的实现

2.3 UTS插件项目结构

我们创建了一个名为uni-reminder的UTS插件,项目结构如下:

uni_modules/  
└── uni-reminder/  
    ├── utssdk/  
    │   ├── app-harmony/        # 鸿蒙平台实现  
    │   │   └── index.uts       # 主要实现文件  
    │   └── interface.uts       # 接口定义文件  
    ├── package.json  
    └── readme.md

关键文件说明:

  • interface.uts: 定义插件的接口类型,包括所有方法的参数和回调类型
  • app-harmony/index.uts: 鸿蒙平台的具体实现,调用鸿蒙原生API

2.4 接口定义(interface.uts)

首先,我们需要定义清晰的接口类型。以闹钟提醒为例:

// 闹钟提醒选项  
export type PublishAlarmReminderOptions = {  
  hour: number                    // 闹钟小时数(0-23)  
  minute: number                  // 闹钟分钟数(0-59)  
  daysOfWeek?: Array<number> | null  // 重复日期,周日=0  
  title?: string | null           // 提醒标题  
  content?: string | null         // 提醒内容  
  success?: PublishAlarmReminderSuccessCallback | null  
  fail?: PublishAlarmReminderFailCallback | null  
  complete?: PublishAlarmReminderCompleteCallback | null  
}  

// 成功回调返回值  
export type PublishAlarmReminderSuccess = {  
  errMsg: string  
  reminderId: number  // 提醒ID,用于后续取消  
}  

// 定义uni对象上的方法  
export interface Uni {  
  publishAlarmReminder(options: PublishAlarmReminderOptions): void  
  publishCalendarReminder(options: PublishCalendarReminderOptions): void  
  publishTimerReminder(options: PublishTimerReminderOptions): void  
  cancelReminder(options: CancelReminderOptions): void  
  cancelAllReminders(options: CancelAllRemindersOptions): void  
  getValidReminders(options: GetValidRemindersOptions): void  
}

这种接口定义方式遵循了UniApp的API设计规范,使用success/fail/complete回调模式,保持了与UniApp其他API的一致性。

2.5 鸿蒙平台核心实现

2.5.1 导入鸿蒙原生API

import reminderAgentManager from '@ohos.reminderAgentManager'  
import { BusinessError } from '@kit.BasicServicesKit'
  • reminderAgentManager: 鸿蒙的代理提醒管理器
  • BusinessError: 鸿蒙的业务错误类型

2.5.2 实现闹钟提醒

export function publishAlarmReminder(options: PublishAlarmReminderOptions): void {  
  try {  
    // 构建闹钟提醒请求对象  
    const requestObj = {  
      reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,  
      hour: options.hour,  
      minute: options.minute,  
      title: options.title || '闹钟提醒',  
      content: options.content || '该起床了',  
      wantAgent: {  
        pkgName: 'com.liudd1.anshichiyao',  
        abilityName: 'EntryAbility'  
      },  
      actionButton: [{  
        title: '关闭',  
        type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE  
      }]  
    } as UTSJSONObject  

    // 设置重复日期  
    if (options.daysOfWeek && options.daysOfWeek.length > 0) {  
      requestObj['daysOfWeek'] = options.daysOfWeek  
    }  

    // 发布提醒  
    reminderAgentManager.publishReminder(  
      requestObj as unknown as reminderAgentManager.ReminderRequest  
    )  
      .then((reminderId: number) => {  
        options?.success?.({  
          errMsg: 'publishAlarmReminder:ok',  
          reminderId: reminderId  
        })  
        options?.complete?.({ errMsg: 'publishAlarmReminder:ok' })  
      })  
      .catch((err: BusinessError) => {  
        options?.fail?.({ errMsg: `publishAlarmReminder:fail ${err.message}` })  
        options?.complete?.({ errMsg: `publishAlarmReminder:fail ${err.message}` })  
      })  
  } catch (err) {  
    const error = err as BusinessError  
    options?.fail?.({ errMsg: `publishAlarmReminder:fail ${error.message}` })  
    options?.complete?.({ errMsg: `publishAlarmReminder:fail ${error.message}` })  
  }  
}

实现要点:

  1. reminderType: 指定提醒类型为闹钟
  2. wantAgent: 配置点击提醒后要启动的应用和页面
  3. actionButton: 添加操作按钮
  4. daysOfWeek: 可选的重复日期数组
  5. 错误处理: 使用try-catch和Promise.catch双重错误处理

2.5.3 实现日历提醒

export function publishCalendarReminder(options: PublishCalendarReminderOptions): void {  
  try {  
    const date = new Date(options.dateTime)  

    const requestObj = {  
      reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_CALENDAR,  
      dateTime: {  
        year: date.getFullYear(),  
        month: date.getMonth() + 1,  
        day: date.getDate(),  
        hour: date.getHours(),  
        minute: date.getMinutes()  
      },  
      title: options.title || '日历提醒',  
      content: options.content || '事件提醒',  
      wantAgent: {  
        pkgName: 'com.liudd1.anshichiyao',  
        abilityName: 'EntryAbility'  
      },  
      actionButton: [{  
        title: '关闭',  
        type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE  
      }]  
    } as UTSJSONObject  

    // 设置重复月份和日期  
    if (options.repeatMonths && options.repeatMonths.length > 0) {  
      requestObj['repeatMonths'] = options.repeatMonths  
    }  
    if (options.repeatDays && options.repeatDays.length > 0) {  
      requestObj['repeatDays'] = options.repeatDays  
    }  

    // 发布提醒(Promise处理逻辑同闹钟提醒)  
    // ...  
  } catch (err) {  
    // 错误处理  
  }  
}

2.5.4 实现倒计时提醒

export function publishTimerReminder(options: PublishTimerReminderOptions): void {  
  try {  
    const requestObj = {  
      reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_TIMER,  
      triggerTimeInSeconds: options.triggerTimeInSeconds,  
      title: options.title || '倒计时提醒',  
      content: options.content || '倒计时已到',  
      wantAgent: {  
        pkgName: 'com.liudd1.anshichiyao',  
        abilityName: 'EntryAbility'  
      },  
      actionButton: [{  
        title: '关闭',  
        type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE  
      }]  
    } as UTSJSONObject  

    // 发布提醒  
    // ...  
  } catch (err) {  
    // 错误处理  
  }  
}

2.6 权限配置

使用代理提醒功能需要在manifest.json中声明权限:

{  
  "app-harmony": {  
    "permissions": [  
      "ohos.permission.PUBLISH_AGENT_REMINDER"  
    ]  
  }  
}

同时配合通知权限插件请求用户授权:

uni.requestNotification({  
  success: (res) => {  
    if (res.granted) {  
      console.log('通知权限已获取')  
    }  
  }  
})

2.7 在应用中使用插件

插件开发完成后,在应用中的使用非常简单:

export default {  
  data() {  
    return {  
      reminderIds: []  
    }  
  },  
  methods: {  
    // 设置每天早上8点的服药提醒  
    setMedicineReminder() {  
      uni.publishAlarmReminder({  
        hour: 8,  
        minute: 0,  
        daysOfWeek: [1, 2, 3, 4, 5, 6, 0],  
        title: '服药提醒',  
        content: '该吃药了,记得按时服药哦!',  
        success: (res) => {  
          console.log('提醒设置成功,ID:', res.reminderId)  
          this.reminderIds.push(res.reminderId)  
          uni.showToast({ title: '提醒设置成功' })  
        },  
        fail: (err) => {  
          console.error('提醒设置失败:', err.errMsg)  
        }  
      })  
    },  

    // 设置30分钟后的倒计时提醒  
    setTimerReminder() {  
      uni.publishTimerReminder({  
        triggerTimeInSeconds: 30 * 60,  
        title: '服药倒计时',  
        content: '30分钟已到,该服药了',  
        success: (res) => {  
          this.reminderIds.push(res.reminderId)  
        }  
      })  
    },  

    // 取消所有提醒  
    cancelAllReminders() {  
      uni.cancelAllReminders({  
        success: () => {  
          this.reminderIds = []  
          uni.showToast({ title: '已清空所有提醒' })  
        }  
      })  
    }  
  }  
}

希望本文的分享能够帮助到正在开发鸿蒙应用的开发者们,让我们一起为鸿蒙生态的繁荣贡献力量!

1 关注 分享
小疯子呵

要回复文章请先登录注册