基于HarmonyOS Next的“食光记”美食社区应用开发全解析

基于HarmonyOS Next的“食光记”美食社区应用开发全解析

本文将使用HarmonyOS 5.0的ArkTS语言与AppGallery Connect服务,从零构建一个功能完整的美食社交应用“食光记”。您将掌握用户认证、数据存储、位置服务等核心功能的集成方法。

一、项目概述与技术栈

应用场景:用户可分享美食探店笔记、收藏喜爱的餐厅、发现附近美食热点

核心技术

  • HarmonyOS 5.0 (Next API 10)
  • ArkTS 声明式开发
  • AGC服务:认证服务、云数据库、云存储、云函数
  • 位置服务、媒体库访问

二、工程搭建与AGC配置

  1. 创建HarmonyOS工程
// 在entry/src/main/ets/pages/Index.ets初始化
@Entry
@Component
struct Index {
  build() {
    Column() {
      Text('食光记')
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
  }
}

  1. AGC服务开通
  • 在AGC控制台创建项目并启用: 认证服务(手机号/邮箱登录)CloudDB(美食数据存储)Cloud Storage(图片缓存)Cloud Functions(业务逻辑处理)

三、核心功能实现

1. 用户认证模块

// utils/AGCManager.ets
import agconnect from '@hw-agconnect/api';
import '@hw-agconnect/auth';

// 初始化AGC认证
export function initAGC() {
  agconnect.instance().init();
}

// 手机号登录
export async function phoneLogin(phone: string, code: string): Promise<boolean> {
  try {
    const credential = agconnect.auth.PhoneAuthProvider.credentialWithVerifyCode(phone, code);
    await agconnect.auth().signIn(credential);
    return true;
  } catch (err) {
    console.error("登录失败: " + JSON.stringify(err));
    return false;
  }
}

2. 美食数据存储(CloudDB)

// model/FoodNote.ets
@ObjectType
export class FoodNote {
  @PrimaryKey()
  id: number = 0; // 主键

  @Field()
  title: string = ''; // 笔记标题

  @Field()
  restaurant: string = ''; // 餐厅名称

  @Field()
  content: string = ''; // 详细评价

  @Field()
  userId: string = ''; // 关联用户ID

  @Field()
  location: string = ''; // 经纬度 "lat,lng"
}

// CloudDBManager.ets
import { FoodNote } from './model/FoodNote';
import clouddb from '@hw-agconnect/clouddb';

// 初始化云数据库
const AGConnectCloudDB = clouddb.AGConnectCloudDB;
const cloudDBZone = AGConnectCloudDB.createCloudDBZone();

// 添加美食笔记
export async function addFoodNote(note: FoodNote): Promise<void> {
  try {
    await cloudDBZone.executeUpsert(note);
    console.log('笔记保存成功');
  } catch (e) {
    console.error('保存失败: ' + e.message);
  }
}

// 查询附近美食
export async function queryNearbyNotes(lat: number, lng: number): Promise<FoodNote[]> {
  const query = clouddb.CloudDBZoneQuery.where(FoodNote)
    .nearTo('location', `${lat},${lng}`, 5); // 5公里范围
  return await cloudDBZone.executeQuery(query);
}

3. 图片上传(Cloud Storage)

// ImageUploader.ets
import agc from '@hw-agconnect/api';
import storage from '@hw-agconnect/storage';

export async function uploadFoodImage(fileUri: string): Promise<string> {
  // 1. 获取存储实例
  const storageInstance = agc.storage().storage();
  
  // 2. 创建引用路径
  const timestamp = new Date().getTime();
  const reference = storageInstance.ref(`food_images/${timestamp}.jpg`);
  
  // 3. 上传文件
  await reference.putFile(fileUri);
  
  // 4. 获取公开访问URL
  return await reference.getDownloadURL();
}

4. 位置服务集成

// LocationService.ets
import geolocation from **********';

// 获取用户当前位置
export async function getCurrentLocation(): Promise<{lat: number, lng: number}> {
  try {
    const location = await geolocation.getCurrentLocation();
    return {
      lat: location.latitude,
      lng: location.longitude
    };
  } catch (err) {
    console.error('定位失败: ' + JSON.stringify(err));
    return { lat: 0, lng: 0 }; // 返回默认值
  }
}

四、功能整合:发布美食笔记页面

// CreateNotePage.ets
@Component
struct CreateNotePage {
  @State title: string = '';
  @State content: string = '';
  @State selectedImage: string = '';
  @Link location: string; // 从父组件传入位置

  build() {
    Column() {
      // 标题输入
      TextInput({ placeholder: '笔记标题' })
        .onChange((value) => { this.title = value; })
      
      // 图片选择器
      Button('选择照片')
        .onClick(async () => {
          const image = await pickImageFromGallery();
          this.selectedImage = image;
        })
      
      // 内容输入
      TextArea({ placeholder: '分享你的美食体验...' })
        .onChange((value) => { this.content = value; })
      
      // 发布按钮
      Button('发布笔记')
        .onClick(async () => {
          // 1. 上传图片
          const imageUrl = await uploadFoodImage(this.selectedImage);
          
          // 2. 创建数据对象
          const newNote = new FoodNote();
          newNote.title = this.title;
          newNote.content = this.content;
          newNote.location = this.location;
          newNote.imageUrl = imageUrl;
          
          // 3. 保存到数据库
          await addFoodNote(newNote);
          
          // 4. 返回首页
          router.back();
        })
    }
  }
}

五、性能优化实践

  1. 数据缓存策略
// 使用@StorageProp本地缓存
@Entry
@Component
struct HomePage {
  @StorageProp('cachedNotes') cachedNotes: FoodNote[] = [];
  
  aboutToAppear() {
    if (this.cachedNotes.length === 0) {
      this.loadDataFromCloud();
    }
  }
  
  async loadDataFromCloud() {
    const notes = await queryNearbyNotes(...);
    this.cachedNotes = notes; // 自动持久化
  }
}

  1. 图片懒加载优化
// 使用LazyForEach加载列表
LazyForEach(this.foodNotes, (note: FoodNote) => {
  ListItem() {
    AsyncImage(note.imageUrl) // 异步加载图片
      .aspectRatio(1.5)
      .placeholder($r('app.media.loading')) // 占位图
  }
}, (note) => note.id.toString())

六、扩展能力建议

  1. 智能推荐(AGC预测服务)
  2. 实时消息推送(Push Kit)
  3. 安全风控(Safety Detect)

总结

本文通过“食光记”美食社区应用的开发实战,完整演示了:

  1. 使用ArkTS声明式语法构建UI界面
  2. 集成AGC认证服务实现用户系统
  3. 通过CloudDB管理结构化美食数据
  4. 利用位置服务实现附近美食发现
  5. 使用云存储处理图片资源
  6. 实施关键性能优化策略
全部评论

相关推荐

不愿透露姓名的神秘牛友
05-20 16:14
已编辑
不止遇到一次了,什么都不会,让提合并请求,问什么是合并请求。让gitlab.页面把测试截图附上,不知道截图要放在哪,那么大的编辑看不到吗让配开发机,问ip是什么东西……这都咋进来的啊,我们(我2023年毕业)那会儿没AI的时候面试都是直接linux,docker,k8s,git,结构与算法,计网。怎么才过去2年,实习生跟傻子一样,有些问题问的我难受,不会git&nbsp;commit,不会git&nbsp;pull,不会切换分支,直接要覆盖master....————而且态度非常敷衍,3天前给开个仓库权限,连本地都没有拉下来。让写一个小文档,都是说一句,写一句,说把目录加上,挺嗤之以鼻,最后还是把目录加上了😂😂任何文档和注释都是方便后来人的,现在的人真的很自负啊,打开github看看任何一个开源项目的文档和注释,都写的很详细。难道现在的同学在校期间不经常拉开源项目看源码学习吗?&nbsp;哪怕是一个swap函数,开源项目里都经常注释:1&nbsp;3&nbsp;5&nbsp;7&nbsp;9&nbsp;2&nbsp;4&nbsp;6&nbsp;8&nbsp;10^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rswap:{功能描述}{使用样例}————给我气笑了,没次问我有什么任务的时候,我都是说,优先你学校导师的项目,然后再做公司需求。然后给了两个需求,一个月内搞定就行,既然是agent开发,1.&nbsp;部署需要维护项目的开发环境2.阅读opencode/openclaude代码(我个人感觉龙虾的源码agent部分很常规,就一个channel+agent,还不如看claude泄露的代码和opencode)然后任务1搞了几周说因为环境问题,他申请到的远程开发机是linux,装的python2,项目是py3的,所以没搭建,我说你不行就用conda或docker把环境屏蔽了呢,没搭理我。任务2:看了很长时间代码,给我回了一句,opencode和openclaude是用go写的……我说你打开github看右下角那的语言是ts还是go……&nbsp;结果满脸懵的说ts是什么……我让看agent&nbsp;loop,哪怕全局搜索一下while(true),跳过去从头看到尾就大致清楚了,压根没看。————嘻嘻,我已经开始做社招简历了。
redf1sh:默认会git结果发现真不会,这种一看就是没做过项目的,真做过项目的至少会提交
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务