鸿蒙跨端家庭药盒助手开发指南 原创

进修的泡芙
发布于 2025-6-22 16:43
浏览
0收藏

鸿蒙跨端家庭药盒助手开发指南

一、系统架构设计

基于HarmonyOS的AI能力和分布式技术,构建智能药品管理与提醒系统:
药品识别层:通过OCR和图像识别技术识别药品信息

数据管理层:存储药品信息和服药计划

提醒服务层:定时提醒用户服药

跨端同步层:多设备间同步药品数据和提醒状态

!https://example.com/harmony-medicine-assistant-arch.png

二、核心代码实现
药品识别服务

// MedicineService.ets
import ocr from ‘@ohos.ai.ocr’;
import ai from ‘@ohos.ai’;
import distributedData from ‘@ohos.distributedData’;
import { MedicineInfo, MedicineReminder } from ‘./MedicineTypes’;

class MedicineService {
private static instance: MedicineService = null;
private ocrEngine: ocr.OCREngine;
private modelManager: ai.ModelManager;
private dataManager: distributedData.DataManager;
private listeners: MedicineListener[] = [];

private constructor() {
this.initOCREngine();
this.initModelManager();
this.initDataManager();
public static getInstance(): MedicineService {

if (!MedicineService.instance) {
  MedicineService.instance = new MedicineService();

return MedicineService.instance;

private initOCREngine(): void {

try {
  const context = getContext() as common.Context;
  this.ocrEngine = ocr.createOCREngine(context);

catch (err) {

  console.error('初始化OCR引擎失败:', JSON.stringify(err));

}

private initModelManager(): void {
try {
this.modelManager = ai.createModelManager(getContext());

  // 加载药品识别模型
  this.modelManager.loadModel({
    modelName: 'medicine_recognition',
    modelPath: 'resources/rawfile/medicine.model',
    callback: (err, data) => {
      if (err) {
        console.error('加载药品模型失败:', JSON.stringify(err));

}

  });

catch (err) {

  console.error('初始化模型管理器失败:', JSON.stringify(err));

}

private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: ‘com.example.medicine’,
area: distributedData.Area.GLOBAL,
isEncrypted: true
});

this.dataManager.registerDataListener('medicine_sync', (data) => {
  this.handleSyncData(data);
});

public async recognizeMedicine(imageData: ArrayBuffer): Promise<MedicineInfo> {

try {
  // 使用OCR识别药品文字信息
  const ocrResult = await this.ocrEngine.recognize({
    image: imageData,
    language: 'zh',
    options: {
      detectDirection: true,
      detectLanguage: true

});

  // 使用AI模型识别药品类型
  const modelInput = {
    data: imageData,
    width: 224,
    height: 224,
    format: 'RGB'
  };
  
  const modelOutput = await this.modelManager.runModel({
    modelName: 'medicine_recognition',
    input: modelInput
  });
  
  const medicineInfo: MedicineInfo = {
    id: Date.now().toString(),
    name: modelOutput.result.name || '未知药品',
    type: modelOutput.result.type || '其他',
    dosage: this.extractDosage(ocrResult.text),
    description: ocrResult.text,
    imageData: imageData,
    timestamp: Date.now()
  };
  
  // 同步药品信息
  this.syncMedicineInfo(medicineInfo);
  
  return medicineInfo;

catch (err) {

  console.error('药品识别失败:', JSON.stringify(err));
  throw err;

}

private extractDosage(text: string): string {
// 简单提取剂量信息(实际应用中需要更复杂的逻辑)
const dosageRegex = /(\d+.?\d)\s(mgg ml 片 粒
丸)/g;
const matches = dosageRegex.exec(text);
return matches ? matches[0] : ‘请咨询医生’;
public async addReminder(reminder: MedicineReminder): Promise<void> {

try {
  // 存储到本地数据库
  const database = relationalStore.getRdbStore(getContext(), {
    name: 'medicine_reminder.db',
    securityLevel: relationalStore.SecurityLevel.S1
  });
  
  await database.insert('reminders', reminder);
  
  // 同步提醒信息
  this.syncReminder(reminder);
  
  // 设置提醒通知
  this.scheduleNotification(reminder);

catch (err) {

  console.error('添加提醒失败:', JSON.stringify(err));
  throw err;

}

private syncMedicineInfo(info: MedicineInfo): void {
this.dataManager.syncData(‘medicine_sync’, {
type: ‘medicine_info’,
data: info,
timestamp: Date.now()
});
private syncReminder(reminder: MedicineReminder): void {

this.dataManager.syncData('medicine_sync', {
  type: 'medicine_reminder',
  data: reminder,
  timestamp: Date.now()
});

private handleSyncData(data: any): void {

if (!data) return;

switch (data.type) {
  case 'medicine_info':
    this.notifyMedicineAdded(data.data);
    break;
  case 'medicine_reminder':
    this.notifyReminderAdded(data.data);
    break;

}

private notifyMedicineAdded(info: MedicineInfo): void {
this.listeners.forEach(listener => {
listener.onMedicineAdded?.(info);
});
private notifyReminderAdded(reminder: MedicineReminder): void {

this.listeners.forEach(listener => {
  listener.onReminderAdded?.(reminder);
});

private scheduleNotification(reminder: MedicineReminder): void {

const notificationRequest: notification.NotificationRequest = {
  content: {
    title: '服药提醒',
    text: 该服用 ${reminder.medicineName} 了,
    additionalText: 剂量: ${reminder.dosage},
    tapAction: {
      bundleName: 'com.example.medicine',
      abilityName: 'MainAbility'

},

  id: parseInt(reminder.id),
  deliveryTime: reminder.nextRemindTime
};

notification.publish(notificationRequest).then(() => {
  console.log('提醒设置成功');
}).catch(err => {
  console.error('设置提醒失败:', JSON.stringify(err));
});

public addListener(listener: MedicineListener): void {

if (!this.listeners.includes(listener)) {
  this.listeners.push(listener);

}

public removeListener(listener: MedicineListener): void {
this.listeners = this.listeners.filter(l => l !== listener);
}

interface MedicineListener {
onMedicineAdded?(info: MedicineInfo): void;
onReminderAdded?(reminder: MedicineReminder): void;
export const medicineService = MedicineService.getInstance();

主界面实现

// MainScreen.ets
import { medicineService } from ‘./MedicineService’;
import { cameraService } from ‘./CameraService’;
import { MedicineInfo, MedicineReminder } from ‘./MedicineTypes’;

@Component
export struct MainScreen {
@State hasPermission: boolean = false;
@State isProcessing: boolean = false;
@State currentMedicine: MedicineInfo | null = null;
@State reminders: MedicineReminder[] = [];
@State showReminderDialog: boolean = false;
@State newReminder: MedicineReminder = this.createEmptyReminder();

aboutToAppear() {
this.checkPermissions();
medicineService.addListener({
onMedicineAdded: (info) => {
this.handleMedicineAdded(info);
},
onReminderAdded: (reminder) => {
this.handleReminderAdded(reminder);
});

this.loadReminders();

aboutToDisappear() {

medicineService.removeListener({
  onMedicineAdded: (info) => {
    this.handleMedicineAdded(info);
  },
  onReminderAdded: (reminder) => {
    this.handleReminderAdded(reminder);

});

build() {

Column() {
  // 标题栏
  Row() {
    Text('家庭药盒助手')
      .fontSize(24)
      .fontWeight(FontWeight.Bold)
      .layoutWeight(1)
    
    Button(this.hasPermission ? '添加药品' : '授权')
      .width(100)
      .onClick(() => {
        if (this.hasPermission) {
          this.showActionMenu();

else {

          this.requestPermissions();

})

.padding(10)

  .width('100%')
  
  // 当前药品信息
  if (this.currentMedicine) {
    Column() {
      Row() {
        Image(this.currentMedicine.imageData)
          .width(80)
          .height(80)
          .objectFit(ImageFit.Contain)
          .margin({ right: 15 })
        
        Column() {
          Text(this.currentMedicine.name)
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 5 })
          
          Text(类型: ${this.currentMedicine.type})
            .fontSize(14)
            .fontColor('#666666')
            .margin({ bottom: 2 })
          
          Text(剂量: ${this.currentMedicine.dosage})
            .fontSize(14)
            .fontColor('#666666')

.alignItems(HorizontalAlign.Start)

.width(‘100%’)

      .padding(10)
      .backgroundColor('#F5F5F5')
      .borderRadius(8)
      .margin({ bottom: 20 })
      
      Button('设置提醒')
        .width(200)
        .height(50)
        .fontSize(18)
        .onClick(() => {
          this.newReminder.medicineName = this.currentMedicine.name;
          this.newReminder.dosage = this.currentMedicine.dosage;
          this.showReminderDialog = true;
        })

.width(‘100%’)

    .margin({ bottom: 20 })

// 提醒列表

  if (this.reminders.length > 0) {
    Column() {
      Text('服药提醒')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })
      
      List({ space: 10 }) {
        ForEach(this.reminders, (reminder) => {
          ListItem() {
            Column() {
              Row() {
                Text(reminder.medicineName)
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                  .layoutWeight(1)
                
                Text(reminder.dosage)
                  .fontSize(14)
                  .fontColor('#666666')

.margin({ bottom: 5 })

              Row() {
                Text('下次提醒:')
                  .fontSize(14)
                  .fontColor('#666666')
                
                Text(this.formatTime(reminder.nextRemindTime))
                  .fontSize(14)
                  .fontColor('#409EFF')
                  .margin({ left: 5 })

Row() {

                Text(频率: ${reminder.frequency}次/天)
                  .fontSize(14)
                  .fontColor('#666666')
                  .layoutWeight(1)
                
                Button('完成')
                  .width(60)
                  .height(30)
                  .fontSize(12)
                  .onClick(() => {
                    this.markAsTaken(reminder);
                  })

.margin({ top: 5 })

.padding(10)

            .width('100%')
            .backgroundColor('#FFFFFF')
            .border({ width: 1, color: '#E0E0E0' })
            .borderRadius(8)

})

.height(300)

.width(‘100%’)

else if (!this.currentMedicine) {

    Column() {
      Text('暂无药品信息')
        .fontSize(18)
        .margin({ bottom: 10 })
      
      Text('点击"添加药品"按钮开始识别药品')
        .fontSize(16)
        .fontColor('#666666')

.padding(20)

    .width('90%')
    .backgroundColor('#F5F5F5')
    .borderRadius(8)
    .margin({ top: 50 })

}

.width('100%')
.height('100%')
.padding(20)

// 设置提醒对话框
if (this.showReminderDialog) {
  DialogComponent({
    title: '设置服药提醒',
    content: this.buildReminderDialogContent(),
    confirm: {
      value: '保存',
      action: () => this.saveReminder()
    },
    cancel: {
      value: '取消',
      action: () => this.showReminderDialog = false

})

}

private buildReminderDialogContent(): void {
Column() {
Row() {
Text(‘药品名称:’)
.fontSize(16)
.width(80)

    Text(this.newReminder.medicineName)
      .fontSize(16)
      .fontWeight(FontWeight.Bold)

.margin({ bottom: 15 })

  Row() {
    Text('剂量:')
      .fontSize(16)
      .width(80)
    
    Text(this.newReminder.dosage)
      .fontSize(16)

.margin({ bottom: 15 })

  Row() {
    Text('开始时间:')
      .fontSize(16)
      .width(80)
    
    DatePicker({
      start: new Date(),
      selected: new Date(this.newReminder.startTime),
      onDateChange: (value) => {
        this.newReminder.startTime = value.getTime();

})

.margin({ bottom: 15 })

  Row() {
    Text('每日次数:')
      .fontSize(16)
      .width(80)
    
    TextPicker({
      range: ['1', '2', '3', '4'],
      selected: parseInt(this.newReminder.frequency) - 1,
      onValueChange: (value) => {
        this.newReminder.frequency = value;

})

.margin({ bottom: 15 })

  Row() {
    Text('提醒方式:')
      .fontSize(16)
      .width(80)
    
    Toggle({ type: ToggleType.Checkbox, isOn: this.newReminder.notification })
      .onChange((isOn) => {
        this.newReminder.notification = isOn;
      })
    
    Text('通知提醒')
      .fontSize(16)
      .margin({ left: 10 })

}

.padding(20)

private createEmptyReminder(): MedicineReminder {

const now = new Date();
now.setMinutes(0);
now.setSeconds(0);

return {
  id: Date.now().toString(),
  medicineName: '',
  dosage: '',
  startTime: now.getTime(),
  nextRemindTime: now.getTime(),
  frequency: '1',
  notification: true,
  taken: false
};

private async checkPermissions(): Promise<void> {

try {
  const permissions = [
    'ohos.permission.USE_AI',
    'ohos.permission.CAMERA',
    'ohos.permission.DISTRIBUTED_DATASYNC',
    'ohos.permission.NOTIFICATION'
  ];
  
  const result = await abilityAccessCtrl.verifyPermissions(
    getContext(),
    permissions
  );
  
  this.hasPermission = result.every(perm => perm.granted);

catch (err) {

  console.error('检查权限失败:', JSON.stringify(err));
  this.hasPermission = false;

}

private async requestPermissions(): Promise<void> {
this.hasPermission = await medicineService.requestPermissions();

if (!this.hasPermission) {
  prompt.showToast({ message: '授权失败,无法使用药品识别功能' });

}

private showActionMenu(): void {
ActionMenu.show({
title: ‘添加药品方式’,
buttons: [
value: ‘camera’,

      action: () => this.recognizeFromCamera()
    },

value: ‘manual’,

      action: () => this.addMedicineManually()

]

});

private async recognizeFromCamera(): Promise<void> {

try {
  this.isProcessing = true;
  
  const imageData = await cameraService.captureFrame();
  const medicineInfo = await medicineService.recognizeMedicine(imageData);
  
  this.currentMedicine = medicineInfo;

catch (err) {

  console.error('药品识别失败:', JSON.stringify(err));
  prompt.showToast({ message: '药品识别失败,请重试' });

finally {

  this.isProcessing = false;

}

private addMedicineManually(): void {
this.currentMedicine = {
id: Date.now().toString(),
name: ‘手动添加药品’,
type: ‘其他’,
dosage: ‘请咨询医生’,
description: ‘’,
imageData: new ArrayBuffer(0),
timestamp: Date.now()
};
private async loadReminders(): Promise<void> {

try {
  const database = relationalStore.getRdbStore(getContext(), {
    name: 'medicine_reminder.db',
    securityLevel: relationalStore.SecurityLevel.S1
  });
  
  const predicates = new relationalStore.RdbPredicates('reminders');
  const result = await database.query(predicates, ['*']);
  
  this.reminders = result.map(row => ({
    id: row.id.toString(),
    medicineName: row.medicineName,
    dosage: row.dosage,
    startTime: row.startTime,
    nextRemindTime: row.nextRemindTime,
    frequency: row.frequency,
    notification: row.notification === 1,
    taken: row.taken === 1
  }));

catch (err) {

  console.error('加载提醒失败:', JSON.stringify(err));

}

private async saveReminder(): Promise<void> {
try {
// 计算下次提醒时间
const frequency = parseInt(this.newReminder.frequency);
const interval = 24 / frequency 60 60 * 1000;
this.newReminder.nextRemindTime = this.newReminder.startTime;

  await medicineService.addReminder(this.newReminder);
  
  this.showReminderDialog = false;
  this.newReminder = this.createEmptyReminder();

catch (err) {

  console.error('保存提醒失败:', JSON.stringify(err));
  prompt.showToast({ message: '保存提醒失败,请重试' });

}

private async markAsTaken(reminder: MedicineReminder): Promise<void> {
try {
const database = relationalStore.getRdbStore(getContext(), {
name: ‘medicine_reminder.db’,
securityLevel: relationalStore.SecurityLevel.S1
});

  // 更新为已服用
  const predicates = new relationalStore.RdbPredicates('reminders');
  predicates.equalTo('id', reminder.id);
  
  const values = {
    taken: 1
  };
  
  await database.update(values, predicates);
  
  // 计算下次提醒时间
  const frequency = parseInt(reminder.frequency);
  const interval = 24 / frequency  60  60 * 1000;
  const nextTime = Date.now() + interval;
  
  // 更新下次提醒时间
  const newValues = {
    taken: 0,
    nextRemindTime: nextTime
  };
  
  await database.update(newValues, predicates);
  
  // 重新加载提醒
  this.loadReminders();
  
  prompt.showToast({ message: '已记录服药' });

catch (err) {

  console.error('更新提醒状态失败:', JSON.stringify(err));
  prompt.showToast({ message: '操作失败,请重试' });

}

private handleMedicineAdded(info: MedicineInfo): void {
this.currentMedicine = info;
this.isProcessing = false;
private handleReminderAdded(reminder: MedicineReminder): void {

this.loadReminders();

private formatTime(timestamp: number): string {

const date = new Date(timestamp);
return {date.getHours()}:{date.getMinutes().toString().padStart(2, '0')};

}

类型定义

// MedicineTypes.ets
export interface MedicineInfo {
id: string;
name: string;
type: string;
dosage: string;
description: string;
imageData: ArrayBuffer;
timestamp: number;
export interface MedicineReminder {

id: string;
medicineName: string;
dosage: string;
startTime: number; // 时间戳
nextRemindTime: number; // 时间戳
frequency: string; // 每日次数
notification: boolean;
taken: boolean;

三、项目配置与权限
权限配置

// module.json5
“module”: {

"requestPermissions": [

“name”: “ohos.permission.USE_AI”,

    "reason": "使用AI模型识别药品"
  },

“name”: “ohos.permission.CAMERA”,

    "reason": "拍摄药品照片"
  },

“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,

    "reason": "同步药品数据"
  },

“name”: “ohos.permission.NOTIFICATION”,

    "reason": "发送服药提醒"

],

"abilities": [

“name”: “MainAbility”,

    "type": "page",
    "visible": true
  },

“name”: “CameraAbility”,

    "type": "service",
    "backgroundModes": ["camera"]
  },

“name”: “ReminderAbility”,

    "type": "service",
    "backgroundModes": ["notification"]

]

}

四、总结与扩展

本家庭药盒助手系统实现了以下核心功能:
智能药品识别:通过图像识别和OCR技术自动识别药品信息

服药计划管理:灵活设置服药时间和频率

智能提醒服务:准时提醒用户服药

跨设备同步:家庭成员间共享药品数据和服药记录

扩展方向:
药品数据库集成:对接权威药品数据库获取更详细信息

用药记录分析:生成用药报告和统计图表

药品库存管理:跟踪药品剩余量并提醒补充

家庭成员共享:多用户协同管理家庭用药

健康数据整合:与健康监测设备数据关联分析

紧急情况处理:漏服提醒和紧急联系人通知

通过HarmonyOS的AI能力和分布式技术,我们构建了一个智能化的家庭药盒管理系统,帮助用户科学管理服药计划,提高用药安全性,并在家庭成员间实现用药信息的无缝同步。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐