鸿蒙开发-设置刷牙提醒——齿录的通知实现

3 阅读4分钟

用@ohos.notification设置刷牙提醒——齿录的通知实现

去鸿蒙应用市场搜一下**「齿录」**,下载下来体验体验。设置早晚刷牙提醒后,到了时间系统会推送通知提醒你——这个功能看起来简单,但在鸿蒙里实现通知需要了解@ohos.notification的用法。体验完了再回来看这篇文章,看看本地通知是怎么设置的。


写在前面

大家好,我是一名写了十多年Web前端的老兵。上一篇文章讲了@ohos.data.preferences的习惯追踪,这篇文章我们聚焦到通知提醒:怎么用@ohos.notification设置本地通知

在Web里,你可以用Notification API推送浏览器通知。鸿蒙里的通知系统更强大,支持定时通知、通知渠道、通知按钮等。


这篇文章聊什么

齿录的提醒通知,核心要解决:

  1. 定时通知:每天早上8点和晚上10点推送刷牙提醒
  2. 通知内容:显示提醒文字和打卡按钮
  3. 通知管理:开启/关闭提醒、修改时间

第一步:声明权限

module.json5里声明通知权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.NOTIFICATION",
        "reason": "用于推送刷牙提醒",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      }
    ]
  }
}

第二步:发送简单通知

import { notificationManager } from '@kit.NotificationKit'

async function sendSimpleNotification(title: string, content: string) {
  const notificationRequest: notificationManager.NotificationRequest = {
    id: Date.now(),
    content: {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
      normal: {
        title: title,
        text: content
      }
    }
  }

  await notificationManager.publish(notificationRequest)
}

第三步:定时通知

鸿蒙的定时通知需要用notificationManager.publishReminder

import { notificationManager } from '@kit.NotificationKit'

async function scheduleReminder(hour: number, minute: number, title: string, content: string) {
  const now = new Date()
  const target = new Date()
  target.setHours(hour, minute, 0, 0)

  // 如果目标时间已过,设置为明天
  if (target.getTime() <= now.getTime()) {
    target.setDate(target.getDate() + 1)
  }

  const triggerTime = target.getTime()

  const reminder: notificationManager.ReminderRequest = {
    reminderType: notificationManager.ReminderType.TIMER,
    triggerTime: triggerTime,
    maxScreenWantAgent: {
      // 点击通知打开应用
    },
    notificationId: Date.now(),
    content: {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
      normal: {
        title: title,
        text: content
      }
    },
    tapDismissed: true
  }

  await notificationManager.publishReminder(reminder)
}

第四步:实现刷牙提醒页面

import { notificationManager } from '@kit.NotificationKit'
import { preferences } from '@kit.ArkData'

interface ReminderSettings {
  morningEnabled: boolean
  morningTime: string    // '08:00'
  eveningEnabled: boolean
  eveningTime: string    // '22:00'
}

@Entry
@Component
struct ReminderSettingsPage {
  @State settings: ReminderSettings = {
    morningEnabled: true,
    morningTime: '08:00',
    eveningEnabled: true,
    eveningTime: '22:00'
  }
  @State morningHour: number = 8
  @State morningMinute: number = 0
  @State eveningHour: number = 22
  @State eveningMinute: number = 0

  private context = getContext(this) as common.UIAbilityContext

  async aboutToAppear() {
    await this.loadSettings()
  }

  async loadSettings() {
    try {
      const pref = await preferences.getPreferences(this.context, 'dental_habits')
      const saved = await pref.get('reminder_settings', '')
      if (typeof saved === 'string' && saved.length > 0) {
        this.settings = JSON.parse(saved) as ReminderSettings
        this.parseTime()
      }
    } catch (err) {
      console.error('读取设置失败:', err)
    }
  }

  parseTime() {
    const morningParts = this.settings.morningTime.split(':')
    this.morningHour = parseInt(morningParts[0])
    this.morningMinute = parseInt(morningParts[1])

    const eveningParts = this.settings.eveningTime.split(':')
    this.eveningHour = parseInt(eveningParts[0])
    this.eveningMinute = parseInt(eveningParts[1])
  }

  async saveSettings() {
    try {
      const pref = await preferences.getPreferences(this.context, 'dental_habits')
      this.settings.morningTime = `${this.morningHour.toString().padStart(2, '0')}:${this.morningMinute.toString().padStart(2, '0')}`
      this.settings.eveningTime = `${this.eveningHour.toString().padStart(2, '0')}:${this.eveningMinute.toString().padStart(2, '0')}`
      await pref.put('reminder_settings', JSON.stringify(this.settings))
      await pref.flush()

      // 更新通知
      await this.updateReminders()
    } catch (err) {
      console.error('保存设置失败:', err)
    }
  }

  async updateReminders() {
    // 取消所有现有通知
    await notificationManager.cancelAllReminders()

    // 设置新的通知
    if (this.settings.morningEnabled) {
      await this.scheduleDailyReminder(
        this.morningHour,
        this.morningMinute,
        '早上好!',
        '别忘了刷牙哦,保持口腔健康从早起开始。'
      )
    }

    if (this.settings.eveningEnabled) {
      await this.scheduleDailyReminder(
        this.eveningHour,
        this.eveningMinute,
        '晚安提醒',
        '睡前记得刷牙和使用牙线,保护牙齿从今天做起。'
      )
    }
  }

  async scheduleDailyReminder(hour: number, minute: number, title: string, content: string) {
    const now = new Date()
    const target = new Date()
    target.setHours(hour, minute, 0, 0)

    if (target.getTime() <= now.getTime()) {
      target.setDate(target.getDate() + 1)
    }

    const reminder: notificationManager.ReminderRequest = {
      reminderType: notificationManager.ReminderType.TIMER,
      triggerTime: target.getTime(),
      notificationId: hour * 100 + minute,
      content: {
        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
        normal: {
          title: title,
          text: content
        }
      },
      tapDismissed: true
    }

    try {
      await notificationManager.publishReminder(reminder)
      console.info(`已设置提醒: ${hour}:${minute}`)
    } catch (err) {
      console.error(`设置提醒失败: ${err}`)
    }
  }

  build() {
    Column() {
      Text('提醒设置')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .margin({ bottom: 24 })

      // 早上提醒
      Column() {
        Row() {
          Text('早上刷牙提醒')
            .fontSize(16)
            .fontColor('#FFFFFF')

          Toggle({ type: ToggleType.Switch, isOn: this.settings.morningEnabled })
            .onChange((isOn: boolean) => {
              this.settings.morningEnabled = isOn
              this.saveSettings()
            })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)

        if (this.settings.morningEnabled) {
          TimePicker({
            selected: new Date(2024, 0, 1, this.morningHour, this.morningMinute)
          })
            .onChange((value: TimePickerResult) => {
              this.morningHour = value.hour
              this.morningMinute = value.minute
              this.saveSettings()
            })
            .margin({ top: 8 })
        }
      }
      .padding(16)
      .backgroundColor('#1F2937')
      .borderRadius(12)
      .margin({ bottom: 16 })

      // 晚上提醒
      Column() {
        Row() {
          Text('晚上刷牙提醒')
            .fontSize(16)
            .fontColor('#FFFFFF')

          Toggle({ type: ToggleType.Switch, isOn: this.settings.eveningEnabled })
            .onChange((isOn: boolean) => {
              this.settings.eveningEnabled = isOn
              this.saveSettings()
            })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)

        if (this.settings.eveningEnabled) {
          TimePicker({
            selected: new Date(2024, 0, 1, this.eveningHour, this.eveningMinute)
          })
            .onChange((value: TimePickerResult) => {
              this.eveningHour = value.hour
              this.eveningMinute = value.minute
              this.saveSettings()
            })
            .margin({ top: 8 })
        }
      }
      .padding(16)
      .backgroundColor('#1F2937')
      .borderRadius(12)

      // 测试通知
      Button('测试通知')
        .onClick(() => {
          sendSimpleNotification('齿录提醒', '这是一条测试通知')
        })
        .width('100%')
        .height(48)
        .backgroundColor('#374151')
        .borderRadius(24)
        .margin({ top: 24 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#111827')
    .padding(16)
  }
}

第五步:处理通知点击

用户点击通知后,可以跳转到打卡页面:

import { wantAgent, WantAgent } from '@kit.AbilityKit'

async function createWantAgent(): Promise<WantAgent> {
  const wantAgentInfo: wantAgent.WantAgentParams = {
    wants: [
      {
        bundleName: 'com.example.dentalapp',
        abilityName: 'EntryAbility',
        parameters: {
          page: 'checkin'
        }
      }
    ],
    actionType: wantAgent.OperationType.START_ABILITY,
    requestCode: 0,
    actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
  }

  return await wantAgent.getWantAgent(wantAgentInfo)
}

// 在创建通知时使用wantAgent
const reminder: notificationManager.ReminderRequest = {
  reminderType: notificationManager.ReminderType.TIMER,
  triggerTime: target.getTime(),
  notificationId: hour * 100 + minute,
  content: {
    notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
    normal: {
      title: title,
      text: content
    }
  },
  tapDismissed: true,
  maxScreenWantAgent: await createWantAgent()
}

总结

这篇文章围绕"齿录"的提醒通知功能,把@ohos.notification的核心用法过了一遍:

基本通知

  • notificationManager.publish():发送即时通知
  • NotificationRequest:配置通知内容

定时通知

  • notificationManager.publishReminder():设置定时通知
  • ReminderRequest:配置触发时间和内容
  • ReminderType.TIMER:定时触发

通知管理

  • notificationManager.cancelAllReminders():取消所有通知
  • notificationManager.cancel():取消指定通知

注意事项

  • 需要声明通知权限
  • 定时通知设置为每天触发
  • 用户点击通知可以跳转到指定页面
  • 测试时先用即时通知验证功能

如果你对"齿录"感兴趣,欢迎去鸿蒙应用市场搜索下载体验。有问题欢迎交流。