HarmonyOS鸿蒙Next基于美食发现应用开发实战:AGC与ArkTS的完美融合

HarmonyOS鸿蒙Next基于美食发现应用开发实战:AGC与ArkTS的完美融合 引言

在移动应用开发领域,美食类应用一直占据着重要地位。借助HarmonyOS Next的强大分布式能力和AppGallery Connect(AGC)的后端支持,开发者可以构建出体验卓越、功能丰富的应用。本文将带领您从零开始,开发一个名为“美味寻踪”的美食发现应用,重点讲解如何利用HarmonyOS SDK的应用服务和AGC云服务,实现核心功能。

我们将使用ArkTS语言进行开发,这是HarmonyOS应用的首选开发语言,结合了TypeScript的强类型特性与HarmonyOS的UI框架能力。通过本教程,您将掌握如何集成AGC服务、构建UI界面、管理应用状态以及实现数据同步。

开发环境准备

在开始编码之前,请确保您的开发环境满足以下要求:

  • 安装DevEco Studio 5.0或更高版本
  • 配置HarmonyOS SDK 5.0或更高版本
  • 注册华为开发者账号并开通AppGallery Connect服务
  • 在AGC控制台创建项目并启用认证服务、云数据库等服务

项目结构与配置

首先创建一个新的HarmonyOS工程,选择"Empty Ability"模板。我们需要在项目中集成AGC SDK,在package.json文件中添加依赖:

{
"dependencies": {
"@hw-agconnect/agconnect-clouddb": "^1.0.0",
"@hw-agconnect/agconnect-auth": "^1.0.0",
"@hw-agconnect/agconnect-storage": "^1.0.0"
}
}

在module.json5文件中配置必要的权限:

{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_NETWORK_INFO"
}
]
}
}

数据模型设计

我们使用AGC云数据库存储美食数据。首先定义美食数据模型:

// model/Restaurant.ts
export class Restaurant {
// 餐厅ID,主键
id: string = '';

// 餐厅名称
name: string = '';

// 餐厅描述
description: string = '';

// 餐厅评分
rating: number = 0;

// 人均消费
averagePrice: number = 0;

// 餐厅地址
address: string = '';

// 餐厅图片URL
imageUrl: string = '';

// 创建时间
createTime: Date = new Date();

// 构造函数
constructor() {
// 初始化对象时生成唯一ID
this.id = this.generateId();
}

// 生成唯一ID的方法
private generateId(): string {
return 'restaurant_' + new Date().getTime() + '_' + Math.random().toString(36).substr(2);
}
}

云数据库服务封装

接下来创建云数据库服务类,封装与AGC云数据库的交互:

// service/CloudDBService.ts
import { clouddb } from '@hw-agconnect/agconnect-clouddb';
import { Restaurant } from '../model/Restaurant';

export class CloudDBService {
// 云数据库实例
private cloudDB: clouddb.AGConnectCloudDB;

// 区域配置
private readonly zoneName = 'YOUR_ZONE_NAME';

// 对象类型名称
private readonly objectTypeName = 'Restaurant';

// 初始化云数据库
async initializeCloudDB(): Promise<void> {
try {
// 获取AGConnect实例
const agcInstance = agconnect.instance();

// 创建CloudDB实例
this.cloudDB = clouddb.AGConnectCloudDB.getInstance(agcInstance);

// 创建云数据库区域
await this.cloudDB.createObjectType(clouddb.ObjectTypeInfoHelper.getObjectTypeInfo(this.zoneName));

// 打开云数据库
await this.cloudDB.openCloudDBZone(clouddb.CloudDBZoneConfig.build(this.zoneName));

console.log('CloudDB initialized successfully');
} catch (error) {
console.error('Failed to initialize CloudDB:', error);
throw error;
}
}

// 添加餐厅到云数据库
async addRestaurant(restaurant: Restaurant): Promise<void> {
try {
const zone = this.cloudDB.getCloudDBZone(this.zoneName);
await zone.executeUpsert(restaurant);
console.log('Restaurant added successfully');
} catch (error) {
console.error('Failed to add restaurant:', error);
throw error;
}
}

// 从云数据库查询所有餐厅
async getAllRestaurants(): Promise<Restaurant[]> {
try {
const zone = this.cloudDB.getCloudDBZone(this.zoneName);
const query = clouddb.CloudDBZoneQuery.where(Restaurant.class).equalTo('isDeleted', false);
const result = await zone.executeQuery(query, Restaurant.class);
return result.getSnapshotObjects();
} catch (error) {
console.error('Failed to query restaurants:', error);
throw error;
}
}

// 根据ID查询餐厅
async getRestaurantById(id: string): Promise<Restaurant | null> {
try {
const zone = this.cloudDB.getCloudDBZone(this.zoneName);
const query = clouddb.CloudDBZoneQuery.where(Restaurant.class).equalTo('id', id);
const result = await zone.executeQuery(query, Restaurant.class);
const restaurants = result.getSnapshotObjects();
return restaurants.length > 0 ? restaurants[0] : null;
} catch (error) {
console.error('Failed to query restaurant by id:', error);
throw error;
}
}
}

用户界面设计与实现

主页面实现

主页面展示美食列表,使用Swiper组件实现轮播图,List组件展示餐厅列表:

// pages/MainPage.ets
import { Restaurant } from '../model/Restaurant';
import { CloudDBService } from '../service/CloudDBService';

@Entry
@Component
struct MainPage {
// 云数据库服务实例
private cloudDBService: CloudDBService = new CloudDBService();

// 餐厅列表数据
@State restaurantList: Restaurant[] = [];

// 页面加载状态
@State isLoading: boolean = true;

// 轮播图数据
@State bannerImages: string[] = [
'common/images/banner1.jpg',
'common/images/banner2.jpg',
'common/images/banner3.jpg'
];

// 初始化云数据库并加载数据
async onPageShow() {
try {
await this.cloudDBService.initializeCloudDB();
this.restaurantList = await this.cloudDBService.getAllRestaurants();
this.isLoading = false;
} catch (error) {
console.error('Failed to load data:', error);
this.isLoading = false;
}
}

build() {
Column() {
// 顶部轮播图
Swiper() {
ForEach(this.bannerImages, (image: string) => {
Image(image)
.width('100%')
.height(200)
.objectFit(ImageFit.Cover)
})
}
.height(200)
.autoPlay(true)
.interval(3000)
.indicator(true)

// 内容区域
if (this.isLoading) {
// 加载中状态
LoadingProgress()
.height(100)
.width(100)
} else {
// 餐厅列表
List({ space: 10 }) {
ForEach(this.restaurantList, (restaurant: Restaurant) => {
ListItem() {
RestaurantItem({ restaurant: restaurant })
}
})
}
.onScrollIndex((start: number, end: number) => {
console.log(`Scroll from ${start} to ${end}`);
})
}
}
.width('100%')
.height('100%')
.onAppear(() => {
this.onPageShow();
})
}
}

// 餐厅列表项组件
@Component
struct RestaurantItem {
@Prop restaurant: Restaurant;

build() {
Row() {
// 餐厅图片
Image(this.restaurant.imageUrl)
.width(80)
.height(80)
.borderRadius(8)
.margin(10)

// 餐厅信息
Column() {
Text(this.restaurant.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.textOverflow({ overflow: TextOverflow.Ellipsis })

Text(this.restaurant.description)
.fontSize(14)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })

Row() {
// 评分
Text(`评分: ${this.restaurant.rating}`)
.fontSize(12)

// 人均价格
Text(`人均: ¥${this.restaurant.averagePrice}`)
.fontSize(12)
.margin({ left: 10 })
}
.margin({ top: 5 })
}
.layoutWeight(1)
}
.padding(10)
.backgroundColor(Color.White)
.borderRadius(8)
.shadow({ radius: 4, color: Color.Gray, offsetX: 2, offsetY: 2 })
}
}
}

餐厅详情页面

创建餐厅详情页面,展示餐厅的详细信息:

// pages/RestaurantDetailPage.ets
import { Restaurant } from '../model/Restaurant';
import { CloudDBService } from '../service/CloudDBService';

@Entry
@Component
struct RestaurantDetailPage {
// 餐厅ID参数
private restaurantId: string = '';

// 餐厅详情
@State restaurant: Restaurant | null = null;

// 云数据库服务
private cloudDBService: CloudDBService = new CloudDBService();

// 加载餐厅详情
async onPageShow() {
try {
await this.cloudDBService.initializeCloudDB();
this.restaurant = await this.cloudDBService.getRestaurantById(this.restaurantId);
} catch (error) {
console.error('Failed to load restaurant details:', error);
}
}

build() {
Column() {
if (this.restaurant) {
// 餐厅图片
Image(this.restaurant.imageUrl)
.width('100%')
.height(200)
.objectFit(ImageFit.Cover)

// 餐厅信息
Column() {
Text(this.restaurant.name)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })

Text(this.restaurant.description)
.fontSize(16)
.margin({ bottom: 10 })

Row() {
Text(`评分: ${this.restaurant.rating}`)
.fontSize(14)
.fontColor(Color.Orange)

Text(`人均: ¥${this.restaurant.averagePrice}`)
.fontSize(14)
.margin({ left: 20 })
}
.margin({ bottom: 10 })

Text(`地址: ${this.restaurant.address}`)
.fontSize(14)
.margin({ bottom: 10 })
}
.padding(20)
} else {
LoadingProgress()
.height(100)
.width(100)
}
}
.width('100%')
.height('100%')
.onAppear(() => {
this.onPageShow();
})
}
}

用户认证与数据安全

为了保障数据安全,我们需要集成AGC认证服务,确保只有登录用户才能进行数据操作:

// service/AuthService.ts
import { auth } from '@hw-agconnect/agconnect-auth';

export class AuthService {
// 当前用户
private currentUser: auth.AGConnectUser | null = null;

// 用户登录
async login(email: string, password: string): Promise<auth.AGConnectUser> {
try {
const agcAuth = auth.instance();
const user = await agcAuth.signInWithEmailAndPassword(email, password);
this.currentUser = user.getUser();
return this.currentUser;
} catch (error) {
console.error('Login failed:', error);
throw error;
}
}

// 用户注册
async register(email: string, password: string): Promise<auth.AGConnectUser> {
try {
const agcAuth = auth.instance();
const user = await agcAuth.createUserWithEmailAndPassword(email, password);
this.currentUser = user.getUser();
return this.currentUser;
} catch (error) {
console.error('Registration failed:', error);
throw error;
}
}

// 获取当前用户
getCurrentUser(): auth.AGConnectUser | null {
return this.currentUser;
}

// 用户登出
async logout(): Promise<void> {
try {
const agcAuth = auth.instance();
await agcAuth.signOut();
this.currentUser = null;
} catch (error) {
console.error('Logout failed:', error);
throw error;
}
}

// 检查用户是否已登录
async checkLoginStatus(): Promise<boolean> {
try {
const agcAuth = auth.instance();
const user = agcAuth.getCurrentUser();
this.currentUser = user;
return user !== null;
} catch (error) {
console.error('Check login status failed:', error);
return false;
}
}
}

应用状态管理

使用AppStorage进行全局状态管理,确保数据在不同页面间共享:

// utils/AppState.ts
import { AppStorage } from 'ohos/base';
import { Restaurant } from '../model/Restaurant';

// 全局状态键值
const GlobalKeys = {
USER_TOKEN: 'userToken',
FAVORITE_RESTAURANTS: 'favoriteRestaurants',
SEARCH_HISTORY: 'searchHistory'
} as const;

class AppState {
// 设置用户token
setUserToken(token: string): void {
AppStorage.setOrCreate(GlobalKeys.USER_TOKEN, token);
}

// 获取用户token
getUserToken(): string {
return AppStorage.get(GlobalKeys.USER_TOKEN) || '';
}

// 添加收藏餐厅
addFavoriteRestaurant(restaurant: Restaurant): void {
const favorites = this.getFavoriteRestaurants();
if (!favorites.some(item => item.id === restaurant.id)) {
favorites.push(restaurant);
AppStorage.setOrCreate(GlobalKeys.FAVORITE_RESTAURANTS, favorites);
}
}

// 移除收藏餐厅
removeFavoriteRestaurant(restaurantId: string): void {
const favorites = this.getFavoriteRestaurants();
const index = favorites.findIndex(item => item.id === restaurantId);
if (index !== -1) {
favorites.splice(index, 1);
AppStorage.setOrCreate(GlobalKeys.FAVORITE_RESTAURANTS, favorites);
}
}

// 获取收藏餐厅列表
getFavoriteRestaurants(): Restaurant[] {
return AppStorage.get(GlobalKeys.FAVORITE_RESTAURANTS) || [];
}

// 添加搜索历史
addSearchHistory(keyword: string): void {
const history = this.getSearchHistory();
if (!history.includes(keyword)) {
history.unshift(keyword);
// 只保留最近10条记录
if (history.length > 10) {
history.pop();
}
AppStorage.setOrCreate(GlobalKeys.SEARCH_HISTORY, history);
}
}

// 获取搜索历史
getSearchHistory(): string[] {
return AppStorage.get(GlobalKeys.SEARCH_HISTORY) || [];
}
}

export const appState = new AppState();

总结与展望

通过本文的讲解,我们完成了一个基于HarmonyOS Next的美食发现应用的核心开发。我们实现了以下功能:

  1. 使用AGC云数据库进行数据存储和查询
  2. 构建了美观的UI界面,包括轮播图和餐厅列表
  3. 实现了用户认证和数据安全机制
  4. 使用AppStorage进行全局状态管理

这个应用还可以进一步扩展,例如添加实时评论功能、收藏功能、地图导航集成、智能推荐算法等。HarmonyOS的分布式特性还允许我们将应用扩展到智能手表、平板等其他设备上,为用户提供无缝的多设备体验。

班级链接:https://developer.huawei.com/consumer/cn/training/classDetail/b4bd2b2e454b43c295beede88442e692?type=1?ha_source=hmosclass&ha_sourceId=89000248


更多关于HarmonyOS鸿蒙Next基于美食发现应用开发实战:AGC与ArkTS的完美融合的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next美食发现应用开发基于ArkTS语言实现UI与业务逻辑。通过AGC(AppGallery Connect)集成认证、云存储、数据分析等服务。应用使用ArkUI声明式开发范式构建界面,结合分布式能力实现跨设备数据同步。AGC Serverless提供后端支持,无需自建服务器。项目完整展示了鸿蒙生态下前端与云端服务的无缝对接方案。

更多关于HarmonyOS鸿蒙Next基于美食发现应用开发实战:AGC与ArkTS的完美融合的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个非常全面的HarmonyOS Next美食应用开发实战教程,涵盖了从环境搭建到核心功能实现的完整流程。您对AGC云数据库的集成、ArkTS UI开发以及状态管理的实现都处理得很专业。

特别值得肯定的是:

  1. 数据模型设计合理,Restaurant类字段完整覆盖了美食应用的核心信息需求
  2. CloudDBService封装规范,提供了完整的CRUD操作接口
  3. UI组件分层清晰,MainPage和RestaurantDetailPage的组件化设计符合HarmonyOS开发最佳实践
  4. 认证服务和状态管理模块的加入提升了应用的完整性和安全性

在实际部署时,需要注意云数据库区域配置和权限管理的细节处理。整体架构设计体现了HarmonyOS分布式能力和AGC云服务的有效结合。

回到顶部