
鸿蒙植物识别小助手开发指南 原创
鸿蒙植物识别小助手开发指南
一、系统架构设计
基于HarmonyOS的AI能力和分布式技术,我们设计了一套植物识别小助手系统,主要功能包括:
植物拍照:使用设备相机拍摄植物照片
AI识别:识别植物种类和相关信息
知识库展示:显示植物详细信息
多设备同步:跨设备同步识别记录和收藏
社区分享:分享植物发现到社区
!https://example.com/harmony-plant-arch.png
二、核心代码实现
相机服务管理
// PlantCameraService.ets
import camera from ‘@ohos.multimedia.camera’;
import image from ‘@ohos.multimedia.image’;
class PlantCameraService {
private static instance: PlantCameraService;
private cameraManager: camera.CameraManager;
private cameraInput: camera.CameraInput | null = null;
private previewOutput: camera.PreviewOutput | null = null;
private photoOutput: camera.PhotoOutput | null = null;
private constructor() {
this.cameraManager = camera.getCameraManager();
public static getInstance(): PlantCameraService {
if (!PlantCameraService.instance) {
PlantCameraService.instance = new PlantCameraService();
return PlantCameraService.instance;
public async initCamera(previewSurfaceId: string): Promise<void> {
const cameras = this.cameraManager.getSupportedCameras();
if (cameras.length === 0) {
throw new Error('No camera available');
this.cameraInput = this.cameraManager.createCameraInput(cameras[0]);
await this.cameraInput.open();
const previewProfile = this.cameraManager.getSupportedOutputCapability(
cameras[0],
camera.ProfileMode.PROFILE_MODE_DEFAULT
).previewProfiles[0];
this.previewOutput = this.cameraManager.createPreviewOutput(
previewProfile,
previewSurfaceId
);
const photoProfiles = this.cameraManager.getSupportedOutputCapability(
cameras[0],
camera.ProfileMode.PROFILE_MODE_DEFAULT
).photoProfiles;
this.photoOutput = this.cameraManager.createPhotoOutput(
photoProfiles[0]
);
public async takePlantPhoto(): Promise<image.Image> {
if (!this.photoOutput) {
throw new Error('Photo output not initialized');
const photoSettings = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
rotation: camera.ImageRotation.ROTATION_0
};
return new Promise((resolve, reject) => {
this.photoOutput!.capture(photoSettings, (err, image) => {
if (err) {
reject(err);
else {
resolve(image);
});
});
}
export const plantCameraService = PlantCameraService.getInstance();
植物识别服务
// PlantRecognitionService.ets
import image from ‘@ohos.multimedia.image’;
import http from ‘@ohos.net.http’;
class PlantRecognitionService {
private static instance: PlantRecognitionService;
private httpClient: http.HttpRequest;
private apiKey = ‘YOUR_PLANT_API_KEY’;
private constructor() {
this.httpClient = http.createHttp();
public static getInstance(): PlantRecognitionService {
if (!PlantRecognitionService.instance) {
PlantRecognitionService.instance = new PlantRecognitionService();
return PlantRecognitionService.instance;
public async recognizePlant(image: image.Image): Promise<PlantInfo> {
const formData = new FormData();
formData.append('image', image);
formData.append('api_key', this.apiKey);
return new Promise((resolve, reject) => {
this.httpClient.request(
'https://plant-api.example.com/identify',
method: ‘POST’,
header: { 'Content-Type': 'multipart/form-data' },
extraData: formData
},
(err, data) => {
if (err) {
reject(err);
else {
const result = JSON.parse(data.result);
resolve(this.processPlantInfo(result));
}
);
});
private processPlantInfo(rawData: any): PlantInfo {
return {
name: rawData.species.commonNames[0] || '未知植物',
scientificName: rawData.species.scientificName,
probability: rawData.probability,
description: rawData.species.description,
careTips: rawData.species.careTips || [],
similarPlants: rawData.similarSpecies || []
};
}
export const plantRecognitionService = PlantRecognitionService.getInstance();
多设备同步服务
// PlantSyncService.ets
import distributedData from ‘@ohos.data.distributedData’;
import deviceManager from ‘@ohos.distributedHardware.deviceManager’;
class PlantSyncService {
private static instance: PlantSyncService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;
private constructor() {
this.initKVStore();
private async initKVStore(): Promise<void> {
const config = {
bundleName: 'com.example.plantAssistant',
userInfo: { userId: 'currentUser' }
};
this.kvManager = distributedData.createKVManager(config);
this.kvStore = await this.kvManager.getKVStore('plant_store', {
createIfMissing: true
});
this.kvStore.on('dataChange', (data) => {
this.handleRemoteUpdate(data);
});
public static getInstance(): PlantSyncService {
if (!PlantSyncService.instance) {
PlantSyncService.instance = new PlantSyncService();
return PlantSyncService.instance;
public async syncPlantRecord(record: PlantRecord): Promise<void> {
await this.kvStore.put(record_${record.id}, JSON.stringify(record));
public async getPlantRecords(): Promise<PlantRecord[]> {
const entries = await this.kvStore.getEntries('record_');
return Array.from(entries).map(([_, value]) => JSON.parse(value));
public async syncFavorite(plantId: string, isFavorite: boolean): Promise<void> {
await this.kvStore.put(favorite_${plantId}, JSON.stringify(isFavorite));
public async isFavorite(plantId: string): Promise<boolean> {
const value = await this.kvStore.get(favorite_${plantId});
return value ? JSON.parse(value) : false;
private handleRemoteUpdate(data: distributedData.ChangeInfo): void {
if (data.deviceId === deviceInfo.deviceId) return;
const key = data.key as string;
if (key.startsWith('record_')) {
const record = JSON.parse(data.value);
EventBus.emit('plantRecordUpdated', record);
else if (key.startsWith(‘favorite_’)) {
const [plantId, isFavorite] = [key.split('_')[1], JSON.parse(data.value)];
EventBus.emit('favoriteUpdated', { plantId, isFavorite });
}
export const plantSyncService = PlantSyncService.getInstance();
植物知识库服务
// PlantKnowledgeService.ets
import http from ‘@ohos.net.http’;
import preferences from ‘@ohos.data.preferences’;
class PlantKnowledgeService {
private static instance: PlantKnowledgeService;
private httpClient: http.HttpRequest;
private localCache: Record<string, PlantDetail> = {};
private constructor() {
this.httpClient = http.createHttp();
public static getInstance(): PlantKnowledgeService {
if (!PlantKnowledgeService.instance) {
PlantKnowledgeService.instance = new PlantKnowledgeService();
return PlantKnowledgeService.instance;
public async getPlantDetail(scientificName: string): Promise<PlantDetail> {
if (this.localCache[scientificName]) {
return this.localCache[scientificName];
const url = https://plant-api.example.com/details/${encodeURIComponent(scientificName)};
return new Promise((resolve, reject) => {
this.httpClient.request(
url,
method: ‘GET’ },
(err, data) => {
if (err) {
reject(err);
else {
const detail = JSON.parse(data.result);
this.localCache[scientificName] = detail;
resolve(detail);
}
);
});
public async searchPlants(query: string): Promise<PlantSearchResult[]> {
const url = https://plant-api.example.com/search?q=${encodeURIComponent(query)};
return new Promise((resolve, reject) => {
this.httpClient.request(
url,
method: ‘GET’ },
(err, data) => {
if (err) {
reject(err);
else {
resolve(JSON.parse(data.result));
}
);
});
}
export const plantKnowledgeService = PlantKnowledgeService.getInstance();
三、主界面实现
相机识别界面
// PlantCameraView.ets
@Component
struct PlantCameraView {
@State previewSurfaceId: string = ‘’;
@State capturedImage: image.Image | null = null;
@State isRecognizing: boolean = false;
aboutToAppear() {
this.initCamera();
build() {
Stack() {
// 相机预览
XComponent({
id: 'plantCameraPreview',
type: 'surface',
libraryname: 'libcamera.so',
controller: this.previewController
})
.onLoad(() => {
this.previewSurfaceId = this.previewController.getXComponentSurfaceId();
plantCameraService.initCamera(this.previewSurfaceId);
})
.width('100%')
.height('100%')
// 拍照按钮
Button('识别植物')
.onClick(() => this.captureAndRecognize())
.position({ x: '50%', y: '90%' })
// 识别状态
if (this.isRecognizing) {
LoadingProgress()
.position({ x: '50%', y: '50%' })
}
private async captureAndRecognize(): Promise<void> {
this.isRecognizing = true;
this.capturedImage = await plantCameraService.takePlantPhoto();
const plantInfo = await plantRecognitionService.recognizePlant(this.capturedImage);
// 保存识别记录
const record: PlantRecord = {
id: generateId(),
plantInfo,
timestamp: Date.now(),
location: await this.getCurrentLocation()
};
await plantSyncService.syncPlantRecord(record);
EventBus.emit('plantIdentified', plantInfo);
this.isRecognizing = false;
private async getCurrentLocation(): Promise<Location | null> {
try {
const geoLocationManager = geoLocation.createGeoLocationManager();
const location = await geoLocationManager.getCurrentLocation();
return {
latitude: location.latitude,
longitude: location.longitude
};
catch (err) {
console.error('获取位置失败:', err);
return null;
}
function generateId(): string {
return Math.random().toString(36).substring(2) + Date.now().toString(36);
植物详情界面
// PlantDetailView.ets
@Component
struct PlantDetailView {
@State plantInfo: PlantInfo | null = null;
@State plantDetail: PlantDetail | null = null;
@State isFavorite: boolean = false;
aboutToAppear() {
EventBus.on(‘plantIdentified’, (info) => {
this.plantInfo = info;
this.loadPlantDetail();
this.checkFavoriteStatus();
});
build() {
Column() {
if (this.plantInfo && this.plantDetail) {
Scroll() {
Column() {
// 植物基本信息
Text(this.plantInfo.name)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text(this.plantInfo.scientificName)
.fontSize(16)
.fontColor('#666666')
Text(识别准确率: ${(this.plantInfo.probability * 100).toFixed(1)}%)
.fontSize(14)
.margin({ top: 8 })
// 植物图片
Image(this.plantDetail.imageUrl)
.width('100%')
.aspectRatio(1)
.margin({ top: 16 })
// 植物详情
Text('植物描述')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ top: 24 })
Text(this.plantDetail.description)
.fontSize(16)
.margin({ top: 8 })
// 养护指南
if (this.plantDetail.careGuide) {
Text('养护指南')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ top: 24 })
ForEach(this.plantDetail.careGuide, (item) => {
Column() {
Text(• {item.title}: {item.description})
.fontSize(16)
.margin({ top: 8 })
})
}
.padding(16)
// 收藏按钮
Button(this.isFavorite ? '已收藏' : '收藏')
.onClick(() => this.toggleFavorite())
.margin(16)
}
private async loadPlantDetail(): Promise<void> {
if (this.plantInfo) {
this.plantDetail = await plantKnowledgeService.getPlantDetail(
this.plantInfo.scientificName
);
}
private async checkFavoriteStatus(): Promise<void> {
if (this.plantInfo) {
this.isFavorite = await plantSyncService.isFavorite(this.plantInfo.scientificName);
}
private async toggleFavorite(): Promise<void> {
if (this.plantInfo) {
const newStatus = !this.isFavorite;
await plantSyncService.syncFavorite(this.plantInfo.scientificName, newStatus);
this.isFavorite = newStatus;
}
识别记录界面
// PlantHistoryView.ets
@Component
struct PlantHistoryView {
@State records: PlantRecord[] = [];
aboutToAppear() {
this.loadRecords();
EventBus.on(‘plantRecordUpdated’, () => this.loadRecords());
build() {
Column() {
Text('识别记录')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 16, left: 16 })
if (this.records.length === 0) {
Text('暂无识别记录')
.fontSize(16)
.margin({ top: 32 })
else {
List({ space: 10 }) {
ForEach(this.records, (record) => {
ListItem() {
PlantRecordItem({ record })
})
.layoutWeight(1)
}
private async loadRecords(): Promise<void> {
this.records = await plantSyncService.getPlantRecords();
this.records.sort((a, b) => b.timestamp - a.timestamp);
}
@Component
struct PlantRecordItem {
private record: PlantRecord;
build() {
Row() {
Image(this.record.plantInfo.imageUrl || ‘resources/plant_placeholder.png’)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(8)
Column() {
Text(this.record.plantInfo.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(this.record.plantInfo.scientificName)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
Text(formatDate(this.record.timestamp))
.fontSize(12)
.fontColor('#999999')
.margin({ top: 8 })
.margin({ left: 12 })
.layoutWeight(1)
.padding(12)
.onClick(() => {
EventBus.emit('showPlantDetail', this.record.plantInfo);
})
}
function formatDate(timestamp: number): string {
const date = new Date(timestamp);
return {date.getFullYear()}-{date.getMonth() + 1}-{date.getDate()} {date.getHours()}:${date.getMinutes()};
四、高级功能实现
多设备协同识别
// CollaborativePlantRecognition.ets
class CollaborativePlantRecognition {
private static instance: CollaborativePlantRecognition;
private constructor() {}
public static getInstance(): CollaborativePlantRecognition {
if (!CollaborativePlantRecognition.instance) {
CollaborativePlantRecognition.instance = new CollaborativePlantRecognition();
return CollaborativePlantRecognition.instance;
public async startGroupRecognition(groupId: string): Promise<void> {
const devices = await deviceManager.getTrustedDevices();
await Promise.all(devices.map(device =>
this.inviteDeviceToGroup(device.id, groupId)
));
private async inviteDeviceToGroup(deviceId: string, groupId: string): Promise<void> {
const ability = await featureAbility.startAbility({
bundleName: 'com.example.plantAssistant',
abilityName: 'PlantGroupAbility',
deviceId
});
await ability.call({
method: 'joinGroup',
parameters: [groupId]
});
public async sharePlantRecord(record: PlantRecord, groupId: string): Promise<void> {
await plantSyncService.syncPlantRecord(record);
const devices = await deviceManager.getTrustedDevices();
await Promise.all(devices.map(device =>
this.sendRecordToDevice(device.id, record, groupId)
));
private async sendRecordToDevice(deviceId: string, record: PlantRecord, groupId: string): Promise<void> {
const ability = await featureAbility.startAbility({
bundleName: 'com.example.plantAssistant',
abilityName: 'PlantGroupAbility',
deviceId
});
await ability.call({
method: 'receivePlantRecord',
parameters: [record, groupId]
});
}
export const collaborativeRecognition = CollaborativePlantRecognition.getInstance();
植物社区功能
// PlantCommunityService.ets
import http from ‘@ohos.net.http’;
class PlantCommunityService {
private static instance: PlantCommunityService;
private httpClient: http.HttpRequest;
private constructor() {
this.httpClient = http.createHttp();
public static getInstance(): PlantCommunityService {
if (!PlantCommunityService.instance) {
PlantCommunityService.instance = new PlantCommunityService();
return PlantCommunityService.instance;
public async sharePlantDiscovery(record: PlantRecord, comment: string): Promise<void> {
const url = 'https://plant-community.example.com/posts';
return new Promise((resolve, reject) => {
this.httpClient.request(
url,
method: ‘POST’,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify({
plantRecord: record,
comment,
userId: 'currentUser',
timestamp: Date.now()
})
},
(err, data) => {
if (err) {
reject(err);
else {
resolve();
}
);
});
public async getRecentDiscoveries(): Promise<CommunityPost[]> {
const url = 'https://plant-community.example.com/posts/recent';
return new Promise((resolve, reject) => {
this.httpClient.request(
url,
method: ‘GET’ },
(err, data) => {
if (err) {
reject(err);
else {
resolve(JSON.parse(data.result));
}
);
});
}
export const plantCommunityService = PlantCommunityService.getInstance();
植物养护提醒
// PlantCareReminder.ets
import reminderAgent from ‘@ohos.reminderAgent’;
import preferences from ‘@ohos.data.preferences’;
class PlantCareReminder {
private static instance: PlantCareReminder;
private constructor() {}
public static getInstance(): PlantCareReminder {
if (!PlantCareReminder.instance) {
PlantCareReminder.instance = new PlantCareReminder();
return PlantCareReminder.instance;
public async scheduleCareReminder(plantId: string, careType: string, intervalDays: number): Promise<void> {
const reminderRequest: reminderAgent.ReminderRequest = {
reminderType: reminderAgent.ReminderType.REMINDER_TYPE_TIMER,
actionButton: [{ title: '已完成' }, { title: '稍后提醒' }],
wantAgent: {
pkgName: 'com.example.plantAssistant',
abilityName: 'PlantCareReminderAbility'
},
ringDuration: 60,
snoozeTimes: 3,
timeInterval: intervalDays 24 60 * 60,
title: 植物养护提醒,
content: 该给您的{this.getPlantName(plantId)}{this.getCareAction(careType)}了,
expiredContent: "养护提醒已过期"
};
const reminderId = await reminderAgent.publishReminder(reminderRequest);
await this.saveReminderId(plantId, careType, reminderId);
private async saveReminderId(plantId: string, careType: string, reminderId: number): Promise<void> {
const prefs = await preferences.getPreferences('plant_reminders');
await prefs.put({plantId}_{careType}, reminderId.toString());
await prefs.flush();
private getCareAction(careType: string): string {
switch (careType) {
case 'water': return '浇水';
case 'fertilize': return '施肥';
case 'prune': return '修剪';
default: return '养护';
}
private async getPlantName(plantId: string): Promise<string> {
const records = await plantSyncService.getPlantRecords();
const record = records.find(r => r.plantInfo.scientificName === plantId);
return record?.plantInfo.name || ‘植物’;
}
export const plantCareReminder = PlantCareReminder.getInstance();
五、总结
本植物识别小助手实现了以下核心价值:
精准识别:利用AI技术准确识别常见室内外植物
知识丰富:提供详细的植物信息和养护指南
多设备协同:支持跨设备同步识别记录和收藏
社区互动:分享植物发现到社区,与其他植物爱好者交流
扩展方向:
增加AR植物识别功能
开发植物生长追踪功能
集成智能家居系统,自动调节植物生长环境
增加病虫害识别和防治建议
注意事项:
需要申请ohos.permission.CAMERA权限
植物识别准确率受图片质量和植物特征可见度影响
部分功能需要网络连接
多设备协同需保持网络连接
位置服务需要ohos.permission.LOCATION权限
