DEV Community

linzhongxue
linzhongxue

Posted on

Practical Development of Lifestyle Service Applications Based on HarmonyOS Next: AppGallery Connect Integration Guide

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:

  1. Install the latest version of DevEco Studio (recommended 4.0 or above)
  2. Register a Huawei Developer account
  3. 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"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

[Continued in next message due to length limitations...]

Top comments (0)