Practical Development of Lifestyle Service Applications Based on HarmonyOS Next: AppGallery Connect Integration Guide
1. Introduction to AppGallery Connect and Environment Setup
AppGallery Connect is a one-stop application service platform provided by Huawei for developers, offering comprehensive backend capabilities for HarmonyOS application development. For lifestyle service applications, we can leverage AppGallery Connect to implement core functionalities such as user authentication, data storage, and push notifications.
First, ensure the development environment is properly configured:
- Install the latest version of DevEco Studio (recommended 4.0 or above)
- Register a Huawei Developer account
- Create a project in AppGallery Connect and enable required services
// Example: Adding AppGallery Connect configuration in config.json
{
"app": {
"bundleName": "com.example.lifeservice",
"vendor": "example",
"version": {
"code": 1,
"name": "1.0"
},
"apiVersion": {
"compatible": 8,
"target": 9,
"releaseType": "Release"
}
},
"deviceConfig": {
"default": {
"agconnect": {
"api_key": "YOUR_API_KEY", // Obtain from AGC console
"app_id": "YOUR_APP_ID", // Obtain from AGC console
"cp_id": "YOUR_CP_ID", // Obtain from AGC console
"product_id": "YOUR_PRODUCT_ID"
}
}
}
}
2. User Authentication Service Integration
Lifestyle service applications typically require a user system to provide personalized services. AppGallery Connect offers multiple authentication methods, including phone number, email, and Huawei account.
2.1 Initializing Authentication Service
import agconnect from '@hw-agconnect/api';
import '@hw-agconnect/auth-component';
// Initialize AGC when the app starts
async function initAGC() {
try {
await agconnect.instance().init();
console.log('AGC initialization successful');
} catch (error) {
console.error('AGC initialization failed:', error);
}
}
// Call in EntryAbility's onCreate
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
initAGC();
}
}
2.2 Implementing Phone Number Login Functionality
// Login page component
@Component
struct LoginPage {
@State phoneNumber: string = '';
@State verifyCode: string = '';
@State isCounting: boolean = false;
@State countdown: number = 60;
// Send verification code
async sendVerifyCode() {
if (!this.phoneNumber) {
prompt.showToast({ message: 'Please enter phone number' });
return;
}
try {
const authService = agconnect.auth().getAuthService();
await authService.requestPhoneVerifyCode('86', this.phoneNumber);
this.startCountdown();
prompt.showToast({ message: 'Verification code sent' });
} catch (error) {
prompt.showToast({ message: 'Failed to send verification code: ' + error.message });
}
}
// Countdown handling
startCountdown() {
this.isCounting = true;
const timer = setInterval(() => {
if (this.countdown <= 0) {
clearInterval(timer);
this.isCounting = false;
this.countdown = 60;
} else {
this.countdown--;
}
}, 1000);
}
// Perform login
async doLogin() {
if (!this.phoneNumber || !this.verifyCode) {
prompt.showToast({ message: 'Please enter phone number and verification code' });
return;
}
try {
const authService = agconnect.auth().getAuthService();
const credential = agconnect.auth.PhoneAuthProvider.credentialWithVerifyCode(
'86', this.phoneNumber, this.verifyCode
);
const user = await authService.signIn(credential);
prompt.showToast({ message: 'Login successful: ' + user.getUid() });
// Navigate to home page
router.replaceUrl({ url: 'pages/HomePage' });
} catch (error) {
prompt.showToast({ message: 'Login failed: ' + error.message });
}
}
build() {
Column() {
TextInput({ placeholder: 'Enter phone number' })
.width('90%')
.height(50)
.type(InputType.Number)
.onChange((value: string) => {
this.phoneNumber = value;
})
Row() {
TextInput({ placeholder: 'Enter verification code' })
.width('60%')
.height(50)
.type(InputType.Number)
.onChange((value: string) => {
this.verifyCode = value;
})
Button(this.isCounting ? `${this.countdown} seconds remaining` : 'Get verification code')
.width('30%')
.height(50)
.enabled(!this.isCounting)
.onClick(() => this.sendVerifyCode())
}
.width('90%')
.justifyContent(FlexAlign.SpaceBetween)
Button('Login')
.width('90%')
.height(50)
.margin({ top: 20 })
.onClick(() => this.doLogin())
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
3. Cloud Database Service Integration
Lifestyle service applications typically need to store user data and service information. AppGallery Connect provides cloud database services supporting real-time synchronization and offline caching.
3.1 Initializing Cloud Database
import '@hw-agconnect/database-server';
// Database service utility class
class CloudDBHelper {
private static instance: CloudDBHelper;
private cloudDB: any;
private constructor() {
this.initCloudDB();
}
static getInstance(): CloudDBHelper {
if (!CloudDBHelper.instance) {
CloudDBHelper.instance = new CloudDBHelper();
}
return CloudDBHelper.instance;
}
private async initCloudDB() {
try {
const agc = agconnect.instance();
this.cloudDB = agc.cloudDB();
await this.cloudDB.initEnv();
console.log('CloudDB initialization successful');
} catch (error) {
console.error('CloudDB initialization failed:', error);
}
}
// Get database instance
getCloudDB() {
return this.cloudDB;
}
}
// Initialize when app starts
CloudDBHelper.getInstance();
3.2 Defining Data Models and CRUD Operations
// Define service item data model
@Class
class ServiceItem {
@Field()
id: string = ''; // Service ID
@Field()
name: string = ''; // Service name
@Field()
category: string = ''; // Service category
@Field()
price: number = 0; // Service price
@Field()
description: string = ''; // Service description
@Field()
createTime: number = 0; // Creation timestamp
constructor(partial?: Partial<ServiceItem>) {
if (partial) {
Object.assign(this, partial);
}
}
}
// Service management class
class ServiceManager {
private cloudDB: any;
constructor() {
this.cloudDB = CloudDBHelper.getInstance().getCloudDB();
}
// Add service
async addService(item: ServiceItem): Promise<boolean> {
try {
item.id = this.generateId();
item.createTime = new Date().getTime();
await this.cloudDB.insert(ServiceItem, item);
return true;
} catch (error) {
console.error('Failed to add service:', error);
return false;
}
}
// Query all services
async getAllServices(): Promise<ServiceItem[]> {
try {
const query = this.cloudDB.createQuery(ServiceItem);
const result = await this.cloudDB.executeQuery(query);
return result.getSnapshotObjects();
} catch (error) {
console.error('Failed to query services:', error);
return [];
}
}
// Query services by category
async getServicesByCategory(category: string): Promise<ServiceItem[]> {
try {
const query = this.cloudDB.createQuery(ServiceItem)
.equalTo('category', category)
.orderByDesc('createTime');
const result = await this.cloudDB.executeQuery(query);
return result.getSnapshotObjects();
} catch (error) {
console.error('Failed to query by category:', error);
return [];
}
}
// Generate unique ID
private generateId(): string {
return 'srv_' + Math.random().toString(36).substr(2, 9);
}
}
[Continued in next message due to length limitations...]
Top comments (0)