
鸿蒙智能快递柜取件助手开发指南 原创
鸿蒙智能快递柜取件助手开发指南
一、系统架构设计
基于HarmonyOS的智能快递柜取件助手,利用短信识别和分布式能力实现以下功能:
短信识别:自动解析短信中的取件码和快递柜位置
跨设备同步:手机识别取件码,大屏展示取件信息
一键开柜:支持远程开柜操作
取件提醒:智能提醒未取快递
!https://example.com/harmony-parcel-helper-arch.png
二、核心代码实现
短信解析服务
// SmsParserService.ets
import sms from ‘@ohos.telephony.sms’;
import distributedData from ‘@ohos.distributedData’;
class SmsParserService {
private static instance: SmsParserService = null;
private dataManager: distributedData.DataManager;
private parcelListeners: ParcelListener[] = [];
private constructor() {
this.initDataManager();
this.initSmsListener();
public static getInstance(): SmsParserService {
if (!SmsParserService.instance) {
SmsParserService.instance = new SmsParserService();
return SmsParserService.instance;
private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: 'com.example.parcelhelper',
area: distributedData.Area.GLOBAL,
isEncrypted: true
});
this.dataManager.registerDataListener('parcel_sync', (data) => {
this.handleSyncData(data);
});
private initSmsListener(): void {
try {
sms.on('smsReceive', (data) => {
this.parseSms(data.message);
});
catch (err) {
console.error('初始化短信监听失败:', JSON.stringify(err));
}
private parseSms(message: string): void {
// 常见快递柜短信格式正则匹配
const patterns = [
/取件码(\d{4,6})[\s,,]+请至(.+?)快递柜取件/i,
/验证码:(\d{4,6})[\s,,]+地址:(.+?)快递柜/i,
/【(.+?)】您的取件码是(\d{4,6})[\s,,]+请到(.+?)取件/i
];
let code = '';
let location = '';
let carrier = '';
for (const pattern of patterns) {
const match = message.match(pattern);
if (match) {
if (match.length >= 3) {
code = match[1];
location = match[2];
if (match.length >= 4) {
carrier = match[1];
break;
}
if (code && location) {
const parcelInfo: ParcelInfo = {
id: Date.now().toString(),
code: code,
location: location,
carrier: carrier || '未知快递',
receiveTime: Date.now(),
status: '待取件',
message: message
};
this.notifyParcelFound(parcelInfo);
this.syncParcelInfo(parcelInfo);
}
private notifyParcelFound(info: ParcelInfo): void {
this.parcelListeners.forEach(listener => {
listener.onParcelFound(info);
});
private syncParcelInfo(info: ParcelInfo): void {
this.dataManager.syncData('parcel_sync', {
type: 'parcel_info',
info: info,
timestamp: Date.now()
});
private handleSyncData(data: any): void {
if (!data || data.type !== 'parcel_info') return;
this.parcelListeners.forEach(listener => {
listener.onParcelFound(data.info);
});
public addParcelListener(listener: ParcelListener): void {
if (!this.parcelListeners.includes(listener)) {
this.parcelListeners.push(listener);
}
public removeParcelListener(listener: ParcelListener): void {
this.parcelListeners = this.parcelListeners.filter(l => l !== listener);
}
interface ParcelListener {
onParcelFound(info: ParcelInfo): void;
interface ParcelInfo {
id: string;
code: string;
location: string;
carrier: string;
receiveTime: number;
status: ‘待取件’ ‘已取件’
‘已过期’;
message: string;
export const smsService = SmsParserService.getInstance();
快递柜控制服务
// LockerControlService.ets
import distributedData from ‘@ohos.distributedData’;
import http from ‘@ohos.net.http’;
class LockerControlService {
private static instance: LockerControlService = null;
private dataManager: distributedData.DataManager;
private controlListeners: ControlListener[] = [];
private constructor() {
this.initDataManager();
public static getInstance(): LockerControlService {
if (!LockerControlService.instance) {
LockerControlService.instance = new LockerControlService();
return LockerControlService.instance;
private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: 'com.example.parcelhelper',
area: distributedData.Area.GLOBAL,
isEncrypted: true
});
this.dataManager.registerDataListener('locker_sync', (data) => {
this.handleSyncData(data);
});
public async openLocker(lockerId: string, code: string): Promise<boolean> {
try {
// 实际应用中应调用快递柜API
const httpRequest = http.createHttp();
const response = await httpRequest.request(
'https://api.example.com/open-locker',
method: ‘POST’,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify({ lockerId, code })
);
if (response.responseCode === 200) {
const result = JSON.parse(response.result);
if (result.success) {
this.syncLockerStatus(lockerId, 'opened');
return true;
}
return false;
catch (err) {
console.error('开柜请求失败:', JSON.stringify(err));
return false;
}
private syncLockerStatus(lockerId: string, status: string): void {
this.dataManager.syncData(‘locker_sync’, {
type: ‘locker_status’,
lockerId: lockerId,
status: status,
timestamp: Date.now()
});
private handleSyncData(data: any): void {
if (!data) return;
switch (data.type) {
case 'locker_status':
this.controlListeners.forEach(listener => {
listener.onLockerStatusChange(data.lockerId, data.status);
});
break;
case 'open_request':
this.handleOpenRequest(data.fromDevice, data.lockerId, data.code);
break;
}
private handleOpenRequest(fromDevice: string, lockerId: string, code: string): void {
// 显示确认对话框
const dialog = new AlertDialog({
title: ‘开柜请求’,
message: 设备 {fromDevice} 请求打开 {lockerId} 快递柜,
buttons: [
text: ‘允许’,
action: async () => {
const success = await this.openLocker(lockerId, code);
prompt.showToast({
message: success ? '开柜成功' : '开柜失败'
});
},
text: ‘拒绝’,
action: () => {
prompt.showToast({ message: '已拒绝请求' });
}
});
dialog.show();
public async requestOpenLocker(deviceId: string, lockerId: string, code: string): Promise<void> {
this.dataManager.syncData('locker_sync', {
type: 'open_request',
fromDevice: this.dataManager.getDeviceId(),
lockerId: lockerId,
code: code,
timestamp: Date.now()
});
public addControlListener(listener: ControlListener): void {
if (!this.controlListeners.includes(listener)) {
this.controlListeners.push(listener);
}
public removeControlListener(listener: ControlListener): void {
this.controlListeners = this.controlListeners.filter(l => l !== listener);
}
interface ControlListener {
onLockerStatusChange(lockerId: string, status: string): void;
export const lockerService = LockerControlService.getInstance();
主界面实现
// MainScreen.ets
import { smsService } from ‘./SmsParserService’;
import { lockerService } from ‘./LockerControlService’;
@Component
export struct MainScreen {
@State parcels: ParcelInfo[] = [];
@State selectedParcel: ParcelInfo | null = null;
@State connectedDevices: string[] = [];
build() {
Column() {
// 标题栏
Row() {
Text(‘智能快递柜取件助手’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button('协同')
.width(80)
.onClick(() => {
this.showDeviceSelector();
})
.padding(10)
.width('100%')
// 快递列表
if (this.parcels.length === 0) {
Column() {
Image($r('app.media.ic_empty'))
.width(120)
.height(120)
.margin({ bottom: 20 })
Text('暂无待取快递')
.fontSize(16)
.width(‘100%’)
.height('60%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
else {
List() {
ForEach(this.parcels, (parcel) => {
ListItem() {
Column() {
Row() {
Text(parcel.carrier)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Text(this.formatTime(parcel.receiveTime))
.fontSize(12)
.fontColor('#666666')
.margin({ bottom: 8 })
Row() {
Text(取件码: ${parcel.code})
.fontSize(16)
.layoutWeight(1)
Text(parcel.status === '待取件' ? '待取件' : '已取件')
.fontSize(14)
.fontColor(parcel.status === '待取件' ? '#FF9800' : '#4CAF50')
Text(parcel.location)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 8 })
.padding(15)
.width('100%')
.borderRadius(8)
.backgroundColor(this.selectedParcel?.id === parcel.id ? '#E3F2FD' : Color.White)
.onClick(() => {
this.selectedParcel = parcel;
})
})
.height(‘60%’)
.margin({ bottom: 20 })
// 控制区域
if (this.selectedParcel) {
Column() {
Button('一键开柜')
.width('80%')
.height(50)
.margin({ bottom: 10 })
.onClick(() => {
this.openSelectedLocker();
})
Button('分享取件码')
.width('80%')
.height(50)
.onClick(() => {
this.shareParcelInfo();
})
}
// 设备连接状态
if (this.connectedDevices.length > 0) {
Column() {
Text('已连接设备')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })
ForEach(this.connectedDevices, (device) => {
Text(device)
.fontSize(14)
.margin({ bottom: 4 })
})
.padding(10)
.width('90%')
.backgroundColor('#F5F5F5')
.borderRadius(8)
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.padding(20)
.onAppear(() => {
smsService.addParcelListener({
onParcelFound: (info) => {
this.addParcel(info);
});
lockerService.addControlListener({
onLockerStatusChange: (lockerId, status) => {
this.updateLockerStatus(lockerId, status);
});
})
.onDisappear(() => {
smsService.removeParcelListener({
onParcelFound: () => {}
});
lockerService.removeControlListener({
onLockerStatusChange: () => {}
});
})
private addParcel(info: ParcelInfo): void {
// 避免重复添加
if (!this.parcels.some(p => p.id === info.id ||
(p.code = info.code && p.location = info.location))) {
this.parcels = [info, ...this.parcels];
}
private updateLockerStatus(lockerId: string, status: string): void {
if (status === ‘opened’ && this.selectedParcel) {
this.parcels = this.parcels.map(p => {
if (p.id === this.selectedParcel?.id) {
return { …p, status: ‘已取件’ };
return p;
});
this.selectedParcel = null;
prompt.showToast({ message: '取件成功' });
}
private openSelectedLocker(): void {
if (!this.selectedParcel) return;
lockerService.openLocker(
this.selectedParcel.location,
this.selectedParcel.code
).then(success => {
prompt.showToast({
message: success ? '开柜请求已发送' : '开柜请求失败'
});
});
private shareParcelInfo(): void {
if (!this.selectedParcel) return;
const devices = ['设备1', '设备2', '设备3']; // 实际应从设备管理服务获取
const dialog = new AlertDialog({
title: '分享到设备',
items: devices,
onSelect: (index) => {
this.sendToDevice(devices[index]);
});
dialog.show();
private sendToDevice(deviceId: string): void {
if (!this.selectedParcel) return;
lockerService.requestOpenLocker(
deviceId,
this.selectedParcel.location,
this.selectedParcel.code
);
prompt.showToast({ message: 已分享到 ${deviceId} });
private showDeviceSelector(): void {
const devices = ['设备1', '设备2', '设备3']; // 实际应从设备管理服务获取
const dialog = new AlertDialog({
title: '选择协同设备',
items: devices,
onSelect: (index) => {
this.connectToDevice(devices[index]);
});
dialog.show();
private connectToDevice(deviceId: string): void {
if (!this.connectedDevices.includes(deviceId)) {
this.connectedDevices.push(deviceId);
prompt.showToast({ message: 已连接 ${deviceId} });
}
private formatTime(timestamp: number): string {
const date = new Date(timestamp);
return {date.getMonth()+1}/{date.getDate()} {date.getHours()}:{date.getMinutes().toString().padStart(2, ‘0’)};
}
三、项目配置与权限
权限配置
// module.json5
“module”: {
"requestPermissions": [
“name”: “ohos.permission.RECEIVE_SMS”,
"reason": "读取短信获取取件码"
},
“name”: “ohos.permission.INTERNET”,
"reason": "连接快递柜服务"
},
“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,
"reason": "同步取件信息"
},
“name”: “ohos.permission.ACCESS_DISTRIBUTED_DEVICE_MANAGER”,
"reason": "发现和连接其他设备"
],
"abilities": [
“name”: “MainAbility”,
"type": "page",
"visible": true
},
“name”: “LockerAbility”,
"type": "service",
"backgroundModes": ["dataTransfer"]
]
}
四、总结与扩展
本智能快递柜取件助手实现了以下核心功能:
智能识别:自动解析短信中的取件信息
便捷取件:一键操作快速开柜
多设备协同:家庭成员共享取件信息
状态同步:实时更新取件状态
扩展方向:
快递追踪:整合物流信息追踪
代取服务:授权他人代取快递
批量取件:支持多件快递同时取出
历史记录:保存取件记录便于查询
社区服务:与物业系统对接提供增值服务
通过HarmonyOS的分布式能力和短信识别功能,我们构建了一个便捷、高效的快递取件解决方案,大大简化了快递取件流程。
