基于HarmonyOS Next的生活服务类应用开发实战:AppGallery Connect集成指南

一、AppGallery Connect简介与环境准备

AppGallery Connect是华为为开发者提供的一站式应用服务平台,它为HarmonyOS应用开发提供了丰富的后端能力支持。在生活服务类应用中,我们可以利用AppGallery Connect实现用户认证、数据存储、推送通知等核心功能。

首先需要确保开发环境配置正确:

  1. 安装最新版DevEco Studio(建议4.0及以上版本)
  2. 注册华为开发者账号
  3. 在AppGallery Connect中创建项目并启用所需服务
// 示例:在config.json中添加AppGallery Connect配置
{
  "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",  // 从AGC控制台获取
        "app_id": "YOUR_APP_ID",    // 从AGC控制台获取
        "cp_id": "YOUR_CP_ID",      // 从AGC控制台获取
        "product_id": "YOUR_PRODUCT_ID"
      }
    }
  }
}

二、用户认证服务集成

生活服务类应用通常需要用户系统来提供个性化服务。AppGallery Connect提供了多种认证方式,包括手机号、邮箱、华为账号等。

2.1 初始化认证服务

import agconnect from '@hw-agconnect/api';
import '@hw-agconnect/auth-component';

// 在应用启动时初始化AGC
async function initAGC() {
  try {
    await agconnect.instance().init();
    console.log('AGC初始化成功');
  } catch (error) {
    console.error('AGC初始化失败:', error);
  }
}

// 在EntryAbility的onCreate中调用
export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    initAGC();
  }
}

2.2 实现手机号登录功能

// 登录页面组件
@Component
struct LoginPage {
  @State phoneNumber: string = '';
  @State verifyCode: string = '';
  @State isCounting: boolean = false;
  @State countdown: number = 60;

  // 发送验证码
  async sendVerifyCode() {
    if (!this.phoneNumber) {
      prompt.showToast({ message: '请输入手机号' });
      return;
    }
    
    try {
      const authService = agconnect.auth().getAuthService();
      await authService.requestPhoneVerifyCode('86', this.phoneNumber);
      this.startCountdown();
      prompt.showToast({ message: '验证码已发送' });
    } catch (error) {
      prompt.showToast({ message: '发送验证码失败: ' + error.message });
    }
  }

  // 倒计时处理
  startCountdown() {
    this.isCounting = true;
    const timer = setInterval(() => {
      if (this.countdown <= 0) {
        clearInterval(timer);
        this.isCounting = false;
        this.countdown = 60;
      } else {
        this.countdown--;
      }
    }, 1000);
  }

  // 执行登录
  async doLogin() {
    if (!this.phoneNumber || !this.verifyCode) {
      prompt.showToast({ message: '请输入手机号和验证码' });
      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: '登录成功: ' + user.getUid() });
      // 跳转到主页
      router.replaceUrl({ url: 'pages/HomePage' });
    } catch (error) {
      prompt.showToast({ message: '登录失败: ' + error.message });
    }
  }

  build() {
    Column() {
      TextInput({ placeholder: '请输入手机号' })
        .width('90%')
        .height(50)
        .type(InputType.Number)
        .onChange((value: string) => {
          this.phoneNumber = value;
        })

      Row() {
        TextInput({ placeholder: '请输入验证码' })
          .width('60%')
          .height(50)
          .type(InputType.Number)
          .onChange((value: string) => {
            this.verifyCode = value;
          })

        Button(this.isCounting ? `${this.countdown}秒后重试` : '获取验证码')
          .width('30%')
          .height(50)
          .enabled(!this.isCounting)
          .onClick(() => this.sendVerifyCode())
      }
      .width('90%')
      .justifyContent(FlexAlign.SpaceBetween)

      Button('登录')
        .width('90%')
        .height(50)
        .margin({ top: 20 })
        .onClick(() => this.doLogin())
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

三、云数据库服务集成

生活服务类应用通常需要存储用户数据、服务信息等。AppGallery Connect提供了云数据库服务,支持实时同步和离线缓存。

3.1 初始化云数据库

import '@hw-agconnect/database-server';

// 数据库服务工具类
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初始化成功');
    } catch (error) {
      console.error('CloudDB初始化失败:', error);
    }
  }

  // 获取数据库实例
  getCloudDB() {
    return this.cloudDB;
  }
}

// 在应用启动时初始化
CloudDBHelper.getInstance();

3.2 定义数据模型与CRUD操作

// 定义服务项目数据模型
@Class
class ServiceItem {
  @Field()
  id: string = '';  // 服务ID

  @Field()
  name: string = '';  // 服务名称

  @Field()
  category: string = '';  // 服务分类

  @Field()
  price: number = 0;  // 服务价格

  @Field()
  description: string = '';  // 服务描述

  @Field()
  createTime: number = 0;  // 创建时间戳

  constructor(partial?: Partial<ServiceItem>) {
    if (partial) {
      Object.assign(this, partial);
    }
  }
}

// 服务管理类
class ServiceManager {
  private cloudDB: any;

  constructor() {
    this.cloudDB = CloudDBHelper.getInstance().getCloudDB();
  }

  // 添加服务
  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('添加服务失败:', error);
      return false;
    }
  }

  // 查询所有服务
  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('查询服务失败:', error);
      return [];
    }
  }

  // 按分类查询服务
  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('按分类查询失败:', error);
      return [];
    }
  }

  // 生成唯一ID
  private generateId(): string {
    return 'srv_' + Math.random().toString(36).substr(2, 9);
  }
}

3.3 实现服务列表界面

// 服务列表页面组件
@Component
struct ServiceListPage {
  private serviceManager: ServiceManager = new ServiceManager();
  @State serviceItems: ServiceItem[] = [];
  @State selectedCategory: string = 'all';
  @State categories: string[] = ['all', 'cleaning', 'repair', 'delivery'];

  aboutToAppear() {
    this.loadServices();
  }

  async loadServices() {
    if (this.selectedCategory === 'all') {
      this.serviceItems = await this.serviceManager.getAllServices();
    } else {
      this.serviceItems = await this.serviceManager.getServicesByCategory(this.selectedCategory);
    }
  }

  build() {
    Column() {
      // 分类筛选
      Scroll(.horizontal) {
        Row() {
          ForEach(this.categories, (category: string) => {
            Button(category)
              .margin(5)
              .stateEffect(this.selectedCategory === category)
              .onClick(() => {
                this.selectedCategory = category;
                this.loadServices();
              })
          })
        }
      }
      .height(50)

      // 服务列表
      List({ space: 10 }) {
        ForEach(this.serviceItems, (item: ServiceItem) => {
          ListItem() {
            ServiceItemCard({ item: item })
          }
        }, (item: ServiceItem) => item.id)
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
  }
}

// 服务项卡片组件
@Component
struct ServiceItemCard {
  @Prop item: ServiceItem;

  build() {
    Column() {
      Text(this.item.name)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
      
      Text(this.item.description)
        .fontSize(14)
        .margin({ top: 5 })
        .maxLines(2)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
      
      Row() {
        Text(`¥${this.item.price}`)
          .fontSize(16)
          .fontColor(Color.Red)
        
        Blank()
        
        Text(this.item.category)
          .fontSize(12)
          .fontColor(Color.Gray)
      }
      .width('100%')
      .margin({ top: 10 })
    }
    .padding(10)
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(8)
    .shadow({ radius: 4, color: '#999', offsetX: 1, offsetY: 1 })
  }
}

四、云函数与支付集成

生活服务类应用通常需要处理订单和支付流程。AppGallery Connect提供了云函数和支付服务来简化这些复杂流程。

4.1 创建订单云函数

// 前端调用创建订单
async function createOrder(serviceId: string, userId: string): Promise<any> {
  try {
    const agc = agconnect.instance();
    const functionCall = agc.function().wrap('createOrder-$latest');
    const result = await functionCall.call({
      serviceId: serviceId,
      userId: userId
    });
    return result.getValue();
  } catch (error) {
    console.error('创建订单失败:', error);
    throw error;
  }
}

// 云函数示例代码(后端)
/*
exports.handler = async (event, context) => {
  const { serviceId, userId } = event;
  
  // 1. 验证服务是否存在
  const service = await db.collection('services').doc(serviceId).get();
  if (!service.exists) {
    throw new Error('服务不存在');
  }
  
  // 2. 创建订单记录
  const order = {
    orderId: generateOrderId(),
    serviceId,
    userId,
    amount: service.data().price,
    status: 'pending',
    createTime: new Date().getTime()
  };
  
  await db.collection('orders').add(order);
  
  // 3. 返回支付参数
  return {
    orderId: order.orderId,
    amount: order.amount,
    serviceName: service.data().name
  };
};
*/

4.2 集成支付功能

import iap from '@hw-iap/api';

// 支付功能封装
class PaymentService {
  // 发起支付
  static async pay(orderInfo: any): Promise<boolean> {
    try {
      const productInfo = {
        priceType: iap.PriceType.IN_APP_CONSUMABLE,  // 消耗型商品
        productId: orderInfo.orderId,
        productName: orderInfo.serviceName,
        amount: orderInfo.amount,
        currency: 'CNY'
      };

      const result = await iap.createPurchaseIntent(productInfo);
      if (result.returnCode === 0) {
        // 支付成功,更新订单状态
        await this.confirmOrder(orderInfo.orderId);
        return true;
      } else {
        throw new Error(`支付失败: ${result.errMsg}`);
      }
    } catch (error) {
      console.error('支付过程出错:', error);
      throw error;
    }
  }

  // 确认订单
  private static async confirmOrder(orderId: string) {
    const agc = agconnect.instance();
    const functionCall = agc.function().wrap('confirmOrder-$latest');
    await functionCall.call({ orderId });
  }
}

// 在订单页面使用
@Component
struct OrderPage {
  @State orderInfo: any = null;
  @State isLoading: boolean = true;

  aboutToAppear() {
    this.loadOrder();
  }

  async loadOrder() {
    try {
      const serviceId = router.getParams()?.serviceId;
      const userId = await this.getCurrentUserId();
      this.orderInfo = await createOrder(serviceId, userId);
    } catch (error) {
      prompt.showToast({ message: '获取订单失败: ' + error.message });
    } finally {
      this.isLoading = false;
    }
  }

  async handlePay() {
    try {
      this.isLoading = true;
      await PaymentService.pay(this.orderInfo);
      prompt.showToast({ message: '支付成功' });
      router.back();
    } catch (error) {
      prompt.showToast({ message: '支付失败: ' + error.message });
    } finally {
      this.isLoading = false;
    }
  }

  build() {
    Column() {
      if (this.isLoading) {
        LoadingProgress()
          .height(50)
          .width(50)
      } else if (this.orderInfo) {
        Text('订单详情')
          .fontSize(20)
          .margin({ bottom: 20 })
        
        Text(`服务: ${this.orderInfo.serviceName}`)
          .fontSize(16)
          .margin({ bottom: 10 })
        
        Text(`金额: ¥${this.orderInfo.amount}`)
          .fontSize(18)
          .fontColor(Color.Red)
          .margin({ bottom: 20 })
        
        Button('立即支付')
          .width('80%')
          .height(50)
          .onClick(() => this.handlePay())
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

五、消息推送与通知

生活服务类应用需要及时通知用户订单状态变化。AppGallery Connect提供了推送服务,支持多种消息类型。

5.1 集成推送服务

import push from '@hw-push/api';

// 推送服务初始化
async function initPushService() {
  try {
    await push.init();
    console.log('推送服务初始化成功');
    
    // 获取推送token
    const token = await push.getToken();
    console.log('推送Token:', token);
    
    // 监听消息
    push.onMessageReceived((message) => {
      console.log('收到推送消息:', message);
      this.handlePushMessage(message);
    });
  } catch (error) {
    console.error('推送服务初始化失败:', error);
  }
}

// 处理推送消息
function handlePushMessage(message: any) {
  const notification = {
    content: {
      contentType: push.ContentType.NOTIFICATION,
      normal: {
        title: message.notification?.title || '新消息',
        body: message.notification?.body || '您有一条新消息',
        clickAction: {
          type: push.ClickAction.TYPE_APP,
          intent: message.intent
        }
      }
    }
  };
  
  push.createNotification(notification)
    .then(() => console.log('通知创建成功'))
    .catch((error) => console.error('通知创建失败:', error));
}

// 在Ability的onCreate中调用
initPushService();

5.2 发送订单状态通知

// 后端云函数示例代码
/*
exports.sendOrderNotification = async (orderId, status) => {
  const order = await db.collection('orders').doc(orderId).get();
  if (!order.exists) return;
  
  const user = await db.collection('users').doc(order.data().userId).get();
  const token = user.data().pushToken;
  
  const message = {
    notification: {
      title: '订单状态更新',
      body: `您的订单${orderId}状态已变更为${status}`
    },
    data: {
      orderId: orderId,
      type: 'order_update'
    },
    token: token
  };
  
  await admin.messaging().send(message);
};
*/

六、应用发布与数据分析

完成开发后,可以通过AppGallery Connect发布应用并监控应用表现。

6.1 应用发布准备

  1. 在AppGallery Connect中创建应用
  2. 配置应用信息、图标、截图等
  3. 设置定价和分发区域
  4. 生成签名证书
// 在config.json中添加发布配置
{
  "app": {
    // ...其他配置
    "distributionFilter": {
      "countries": ["CN", "US", "UK"],  // 分发国家
      "apiCompatible": 8,
      "apiTarget": 9
    }
  }
}

6.2 集成数据分析

AppGallery Connect提供了应用数据分析服务,帮助开发者了解用户行为。

import analytics from '@hw-analytics/api';

// 记录自定义事件
function logEvent(eventName: string, params?: object) {
  analytics.instance().logEvent(eventName, params);
}

// 示例:记录服务浏览事件
@Component
struct ServiceDetailPage {
  @Prop serviceId: string;

  aboutToAppear() {
    logEvent('view_service', {
      service_id: this.serviceId,
      timestamp: new Date().getTime()
    });
  }
}

// 设置用户属性
async function setUserProperties(userId: string) {
  await analytics.instance().setUserId(userId);
  await analytics.instance().setUserProfile({
    user_level: 'vip',  // 用户等级
    last_login: new Date().toISOString()  // 最后登录时间
  });
}

七、总结与最佳实践

通过本教程,我们完成了一个基于HarmonyOS Next的生活服务类应用核心功能开发,涵盖了:

  1. 用户认证系统实现
  2. 云数据库集成与服务管理
  3. 订单与支付流程处理
  4. 消息推送与通知系统
  5. 应用发布与数据分析

最佳实践建议:

  1. 模块化设计:将AGC相关功能封装成独立模块,便于维护和复用
  2. 错误处理:对所有云服务调用做好错误处理和用户提示
  3. 数据安全:敏感操作应在云函数中实现,而非前端直接处理
  4. 性能优化:合理使用本地缓存减少云数据库查询
  5. 用户体验:关键操作提供加载状态反馈

通过AppGallery Connect的丰富服务,开发者可以快速构建功能完善的生活服务类应用,而将更多精力集中在业务逻辑和用户体验优化上。


林钟雪
4 声望0 粉丝