Development Guide for Food Discovery Application Based on HarmonyOS Next
1. Project Overview and Development Environment Setup
We will develop a food discovery app named "FoodFinder" with core features:
- Location-based nearby restaurant recommendations
- Food detail display and user ratings
- Favorites management
- Restaurant search and filtering
Development Environment Requirements:
- DevEco Studio 4.1 (Build Version 4.1.3.400)
- HarmonyOS SDK 5.0
- AppGallery Connect service integration
- TypeScript language environment
Project Initialization Steps:
- Create a HarmonyOS application project
- Configure cloud service dependencies in
build-profile.json5
"dependencies": {
"@ohos/agconnect-database": "^5.0.0",
"@ohos/agconnect-auth": "^5.0.0",
"@ohos/location": "^5.0.0"
}
- Enable CloudDB, Auth Service, and Location Service in AGC console
2. Core Function Implementation and Code Analysis
1. Location Acquisition and Restaurant Data Query
// Get user location and query nearby restaurants
import geoLocationManager from '@ohos.geoLocationManager';
import cloudDB from '@ohos/agconnect-database';
@Entry
@Component
struct NearbyRestaurants {
@State restaurants: Restaurant[] = [];
async aboutToAppear() {
// Get current location
const location = await geoLocationManager.getCurrentLocation();
this.queryNearbyRestaurants(location.latitude, location.longitude);
}
// Query nearby restaurants
async queryNearbyRestaurants(lat: number, lon: number) {
const cloudDBZone = cloudDB.getCloudDBZone("FoodDB");
const query = cloudDB.createQuery();
query.equalTo('geoPoint', cloudDB.GeoPoint(lat, lon));
query.limit(10);
const snapshot = await cloudDBZone.executeQuery(query);
this.restaurants = snapshot.getObjects(Restaurant);
}
build() {
List() {
ForEach(this.restaurants, (item: Restaurant) => {
RestaurantItem({ data: item })
})
}
}
}
// Restaurant data model
class Restaurant implements cloudDB.CloudDBZoneObject {
@cloudDB.field() id: string = '';
@cloudDB.field() name: string = '';
@cloudDB.field() rating: number = 0;
@cloudDB.field({ geoPoint: true }) location: cloudDB.GeoPoint = new cloudDB.GeoPoint(0, 0);
}
2. Restaurant Detail Page Implementation
@Component
struct RestaurantDetail {
@Prop restaurant: Restaurant;
@State isFavorite: boolean = false;
// Check if favorited
async aboutToAppear() {
const auth = await import('@ohos/agconnect-auth');
const userId = auth.getCurrentUser().uid;
this.isFavorite = await this.checkFavoriteStatus(userId, this.restaurant.id);
}
// Toggle favorite status
toggleFavorite() {
if (this.isFavorite) {
// Remove from CloudDB
cloudDB.getCloudDBZone("UserDB").delete(this.favoriteRecord);
} else {
// Add to CloudDB
const record = new FavoriteRecord(userId, this.restaurant.id);
cloudDB.getCloudDBZone("UserDB").upsert(record);
}
this.isFavorite = !this.isFavorite;
}
build() {
Column() {
Image(this.restaurant.mainImage)
.width('100%')
.aspectRatio(1.5)
Text(this.restaurant.name)
.fontSize(24)
.margin(10)
RatingBar({ rating: this.restaurant.rating })
Button(this.isFavorite ? 'Unfavorite' : 'Favorite')
.onClick(() => this.toggleFavorite())
.margin(20)
}
}
}
3. Favorites Synchronization
// User favorites management
class FavoriteService {
// Get all user favorites
static async getUserFavorites(userId: string): Promise<Restaurant[]> {
const query = cloudDB.createQuery()
.equalTo('userId', userId)
.relatedTo('restaurant', Restaurant);
const snapshot = await cloudDB.getCloudDBZone("UserDB").executeQuery(query);
return snapshot.getObjects(Restaurant);
}
// Setup real-time data listener
static setupFavoritesListener(callback: (favorites: Restaurant[]) => void) {
const query = cloudDB.createQuery()
.equalTo('userId', auth.getCurrentUser().uid);
const listener = cloudDB.getCloudDBZone("UserDB")
.subscribe(query, {
onSnapshot: (snapshot) => {
callback(snapshot.getObjects(Restaurant));
}
});
return listener;
}
}
3. Key HarmonyOS Features Implementation
1. Atomic Service for Dish Sharing
// Define sharing atomic service
@Entry
@Component
struct DishShareCard {
@State dishInfo: Dish = new Dish();
build() {
Card() {
Column() {
Image(this.dishInfo.image)
.width(120)
.height(120)
Text(this.dishInfo.name)
.fontSize(16)
Text(`¥${this.dishInfo.price}`)
.fontColor(Color.Red)
}
.padding(10)
}
.onClick(() => {
// Navigate to restaurant detail
router.pushUrl({ url: `pages/RestaurantDetail?id=${this.dishInfo.restaurantId}` });
})
}
}
2. Offline Caching with Relational Database
// Initialize local database
const RDB_STORE_CONFIG: relationalStore.StoreConfig = {
name: "FoodCache.db",
securityLevel: relationalStore.SecurityLevel.S1
};
relationalStore.getRdbStore(this.context, RDB_STORE_CONFIG, (err, store) => {
store.executeSql(
`CREATE TABLE IF NOT EXISTS restaurant_cache (
id TEXT PRIMARY KEY,
name TEXT,
rating REAL,
data TEXT
)`
);
});
// Use cached data when network fails
async function getRestaurants() {
try {
const onlineData = await fetchOnlineData();
cacheData(onlineData); // Update cache
return onlineData;
} catch (error) {
return loadCachedData(); // Return cached data
}
}
4. Performance Optimization Practices
- Image Loading Optimization
// Use lazy loading and placeholder
AsyncImage(this.restaurant.image)
.placeholder($r('app.media.placeholder'))
.transitionEffect(TransitionEffect.OPACITY)
- Pagination Loading
// Implement scroll pagination
List({ scroller: this.scroller }) {
// ...
}
.onReachEnd(() => {
if (!this.isLoading) {
this.loadNextPage();
}
})
- Rendering Performance Optimization
// Optimize long lists with component reuse
ForEach(this.restaurants, (item: Restaurant) => {
RestaurantItem({ data: item })
}, (item: Restaurant) => item.id) // Key: set unique identifier
5. AppGallery Connect Integration Key Points
- CloudDB Rule Configuration
{
"rules": {
"restaurants": {
".read": "auth != null",
".write": "auth != null && resource.data.owner == auth.uid"
}
}
}
- AB Testing for Recommendation Algorithm
// Get AB testing parameters
import agc from '@ohos/agconnect-remoteconfig';
const config = agc.getRemoteConfig();
const params = await config.applyDefaults({
recommendation_algorithm: 'v1'
}).fetch();
const algorithmVersion = params.getValue('recommendation_algorithm').asString();
6. Project Testing and Release
- Unit Test Example
// Test rating calculation logic
describe('RatingCalculator', () => {
it('should calculate weighted rating', () => {
const ratings = [5, 4, 3, 5];
const result = calculateWeightedRating(ratings);
expect(result).toBeCloseTo(4.25);
});
});
- Pre-release Checklist
- [ ] Complete AGC application signature configuration
- [ ] Pass ArkCompiler compilation check in DevEco Studio
- [ ] Test location services on Huawei devices
- [ ] Configure privacy policy documents
Conclusion
This guide demonstrates the complete development process of FoodFinder application using HarmonyOS Next capabilities:
- Implement cloud data synchronization with
@ohos/agconnect-database
- Enhance UX with Atomic Services
- Enable offline capabilities with relational databases
- Achieve multi-device sync through distributed capabilities
Further expansions:
- Integrate Huawei Pay for online ordering
- Add AR menu preview functionality
- Implement cross-device cooking guide handoff
Full source code: github.com/HarmonyOS-FoodFinder
Note: Configure CloudDB schema in AGC console and enable location permissions before running
Through this practice, developers can master the complete development workflow for lifestyle applications on HarmonyOS Next, leveraging distributed capabilities and cloud services to build high-performance applications.
Top comments (0)