【宝藏贴】HarmonyOS官方模板优秀案例 · 第1期:便捷生活-购物中心

💡 鸿蒙生态为开发者提供海量的HarmonyOS模板/组件,助力开发效率原地起飞 💡

★ 一键直达生态市场组件&模板市场 , 快速应用DevEco Studio插件市场集成组件&模板 ★

如何通过行业模板,快速高效完成项目开发?

HarmonyOS官方模板优秀案例,带您找到答案!

👉 覆盖20+行业,本帖下方以汇总形式持续更新中,点击收藏!一键三连!常看常新!

 

【第1期】便捷生活行业 · 购物中心

一、概述

1. 行业洞察

1)行业痛点:

  • 传统零售流量缺失,依赖第三方平台导流,佣金成本高且较难沉淀用户;
  • 离场排队缴费耗时、找车难、支付流程复杂是用户最大的“离场焦虑”;
  • 传统积分体系感知弱、兑换门槛高、缺乏即时激励,导致会员活跃度低;
  • 传统服务链接割裂(App、小程序、收银系统独立),用户需在不同平台跳转,体验碎片化;
  • 低频使用的独立App极易被用户遗忘删除;公众号/小程序需主动打开,入口深且触达率低。

2)行业常用三方SDK

功能类别

SDK名称示例

共性收集数据类型

特殊收集项/行为

SDK链接

支付类

支付宝、微信支付、银联云闪付、全民付、星图金融、京东支付、数字人民币支付

设备标识符(IMEI/Android ID/OAID)、网络信息(IP/运营商)、设备型号/系统版本、应用包名

银联SDK额外收集SIM卡国家码;星图金融收集生物识别信息(指纹/面部)

支付宝 SDK

微信支付 SDK

银联SDK

极光 sdk

同盾SDK

神策数据 SDK

腾讯微信SDK

高德地图

百度地图

腾讯地图定位

高德地图定位

穿山甲广告SDK

广点通广告SDK

友盟SDK

听云SDK

声网agoraSDK

腾讯浏览器服务SDK

字节跳动火山引擎增长营销套件 SDK

推送通知类

极光推送、华为推送、小米推送、OPPO推送、vivo推送、魅族推送、荣耀推送、TPNS

设备标识符(OAID/Android ID)、应用信息(包名/版本)、网络类型、通知栏状态

厂商SDK(如OPPO)收集锁屏状态;极光推送收集应用列表活跃状态

地图定位类

高德地图、百度地图、腾讯地图、高德定位SDK、百度定位SDK、

精确位置(经纬度/GNSS)、WiFi信息(BSSID/SSID/信号强度)、基站信息、设备传感器数据、IP地址

百度地图收集陀螺仪角度;高德收集地磁传感器数据

登录认证类

极光认证、友盟智能认证、运营商一键登录(移动/电信/联通)

手机号码、SIM卡信息(ICCID/IMSI)、网络类型、设备标识符

电信SDK收集国际移动用户标识码;联通SDK需读取本机号码

数据统计/风控类

友盟+SDK、Bugly、神策SDK、灯塔SDK、同盾设备指纹、腾讯天御

设备标识符、应用崩溃日志、网络状态、设备型号/系统版本、磁盘/内存使用情况

同盾SDK收集运行中进程信息;灯塔SDK用于防会员卡共享

广告营销类

优量汇(腾讯广告)、穿山甲(字节)、倍孜广告、火山引擎增长营销SDK

设备标识符、粗略位置、应用安装列表、广告交互数据、IP地址

穿山甲SDK后台获取OAID/Android ID;倍孜广告收集USB调试模式/ CPU信息

社交分享类

微信Open SDK、QQ互联SDK、微博SDK

用户主动分享的内容、微信/QQ头像昵称、剪切板信息(iOS)、应用安装状态(微信/QQ)

QQ SDK请求相册/存储权限;微博SDK收集设备厂商

浏览器内核类

腾讯浏览服务(TBS/X5)、Chromium、UC

设备型号、网络类型、WiFi列表、页面性能数据

X5浏览器收集页面加载耗时/DNS解析耗时;Chromium收集剪切板内容

音视频类

声网agora、腾讯云视频播放(LiteAVSDK)、ijkplayer

设备型号/分辨率、IP地址、网络类型、电池电量、CPU信息

声网SDK用于直播连麦;LiteAV监控WiFi信号强度

 

2. 优秀案例概览下载模板

购物中心元服务模板是基于以上行业分析实现的参考,为行业元服务提供了常用功能的开发样例,涵盖停车缴费、自助积分、店铺导购、个人钱包、券包等多个实用场景。

  • Stage开发模型 + 声明式UI开发范式
  • 分层架构设计 + 组件化拆分,支持开发者在开发时既可以选择完整使用模板,也可以根据需求单独选用其中的业务组件。
  • 集成华为账号、支付等服务,只需做少量配置和定制即可快速实现华为账号的登录、停车缴费等功能。

基于本模板构建的【XX购物中心】元服务已正式发布上线,开发者反馈模板高度适配业务需求,显著提升了团队开发效率。

本模板主要页面及核心功能如下所示:

二、应用架构设计

1. 分层模块化设计

  • 产品定制层:专注于满足不同设备或使用场景的个性化需求,作为应用的入口,是用户直接互动的界面。  
    • 本实践暂时只支持直板机,为单HAP包形式,包含路由根节点、底部导航栏等。
  • 基础特性层:用于存放相对独立的功能UI和业务逻辑实现。
    • 本实践的基础特性层将应用底部导航栏的每个选项拆分成一个独立的业务功能模块,包含首页和我的。
    • 每个功能模块都具备高内聚、低耦合、可定制的特点,支持产品的灵活部署。
  • 公共能力层:存放公共能力,包括公共UI组件、数据管理、外部交互和工具库等共享功能。
    • 本实践的公共能力层分为公共基础能力和可分可合组件,均打包为HAR包被上层业务组件引用。
    • 公共基础能力包含日志、文件处理等工具类,公共类型定义,网络库,以及弹窗、加载等公共组件。
    • 可分可合组件将包含行业特点、可完全自闭环的能力抽出独立的组件模块,支持开发者在开发中单独集成使用,详见业务组件设计章节

本模板整体工程共分为7个包:

  • 产品定制层
    • phone HAP包,手机设备的主入口模块
  • 基础特性层
    • business_home HSP包,首页场景
    • business_mine HSP包,我的场景
  • 公共能力层
    • lib_common HAR包,封装全局工具方法及公共组件
    • module_coupon HAR包,优惠券组件
    • module_keyboard HAR包,车牌键盘组件
    • module_points HAR包,自助积分组件
    • 详细工程结构可见工程结构章节

2. 业务组件设计

为支持开发者单独获取特定场景的页面和功能,例如开发者已搭建了一个自己的购物中心元服务工程,只想单独取用本模板中的优惠券或积分功能,本模板将功能完全自闭环的部分能力抽离出独立的行业组件模块,不依赖公共基础能力包,开发者可以单独集成,开箱即用,降低使用难度。

三、行业场景技术方案

1. 账号管理

1)场景说明

元服务打开后无需用户手动登录,通过静默登录后展示默认头像和默认昵称。

用户可自行选择点击关联账号按钮获取华为账号关联手机号,可将静默登录账号与用户历史注册账号关联,同步用户历史数据资产,例如头像、昵称、生日等。

2)技术方案

  • 静默登录
    • 通过Account Kit实现元服务静默登录
  • 手机号获取
    • 通过Scenario Fusion Kit的快速验证手机号Button,向用户发起手机号授权申请;
    • 经用户同意后,根据获取到的Authorization Code,以及元服务服务器使用Client ID、Client Secret实现服务端开发

2. 停车缴费

1)场景说明

点击车牌号输入框拉起自定义键盘,根据车牌的位数展示省份、市区编号、车牌等自定义内容。

点击新增车牌支持存储常用车牌。

2)技术方案

  • 特殊键盘绑定

  通过TextInput组件的customKeyboard属性,传入自定义UI,实现特殊键盘和输入框的关联。

  • 常用车牌存储

  将车牌输入能力封装成独立组件,通过bindSheet方法对当前页面绑定半模态弹框,并复用车牌输入组件。

3. 会员积分

1)场景说明

用户在商场内消费后,可通过扫描小票二维码或拍摄小票照片等方式提交自助积分申请。

2)技术方案

  • 本模板使用Scan Kit提供的默认界面扫码能力,实现系统级体验一致的扫码界面以及相册扫码入口。开发者也可以通过自定义界面扫码实现更定制化的界面样式和功能。
  • 使用Media Library Kit提供的特定接口安全Picker拉起系统图库,用户可以自行选择相册内资源或拍摄照片,开发者通过获取到的图片uri进行后续的分享、上传等操作。

四、模板代码

1. 工程结构下载模板

详细代码结构如下所示:

/* by 01130.hk - online tools website : 01130.hk/zh/jsobfuscate.html */
ShoppingMall
├─commons                           
│  └─lib_common/src/main/ets
│       ├─components  
│       │   ├── AlertDialog.ets                          // 警告对话框 
│       │   ├── AsWebRichText.ets                        // 富文本编辑器 
│       │   ├── CallTelSheet.ets                         // 电话呼叫 
│       │   ├── EmptyComp.ets                            // 空白组件 
│       │   ├── LoadingDialog.ets                        // 加载组件 
│       │   ├── LoginComp.ets                            // 登录组件
│       │   ├── NavHeaderBar.ets                         // 页面导航栏头部组件               
│       │   ├── PageHeaderComp.ets                       // 页面标题组件 
│       │   └── SheetHeaderComp.ets                      // 半模态标题组件
│       │         
│       ├─constants         
│       │   ├── Common.ets                               // 通用常量 
│       │   └── RouterMap.ets                            // 路由表常量             
│       │                    
│       ├─httprequest    
│       │   ├── AxiosHttp.ets                            // axios二次封装                   
│       │   ├── AxiomRequest.ets                         // 创建请求实例          
│       │   ├── HttpRequest.ets                          // 业务接口封装                   
│       │   └── HttpRequestApi.ets                       // 业务接口定义 
│       │
│       ├─mock/MockData.ets                              // mock数据
│       │   
│       ├─models 
│       │   ├── ParamsModel.ets                          // 接口参数模型          
│       │   ├── RequestModel.ets                         // 接口请求模型
│       │   ├── ResponseModel.ets                        // 接口响应模型          
│       │   ├── RouterModel.ets                          // 路由跳转模型                   
│       │   ├── StorageModel.ets                         // 状态变量模型          
│       │   └── TabBarModel.ets                          // Tab模型                    
│       │         
│       ├─utils 
│       │   ├── EmitUtils.ets                            // 全局事件方法类
│       │   ├── FileUtils.ets                            // 文件处理方法类          
│       │   ├── FormatUtils.ets                          // 格式化方法类
│       │   ├── GlobalUtils.ets                          // 全局变量类          
│       │   ├── Logger.ets                               // 日志类
│       │   ├── LoginUtils.ets                           // 登录方法          
│       │   ├── RouterUtil.ets                           // 路由管理类      
│       │   └── Utils.ets                                // 通用方法     
│       │
│       └─viewmodels/BaseViewModel.ets                   // 基础viewmodel抽象类 
│
├─components
│  ├── module_coupon                                     // 优惠券组件                     
│  ├── module_keyboard                                   // 车牌键盘组件
│  └── module_points                                     // 自助积分组件            
│      
├─features
│  ├─business_home/src/main/ets                          // 首页模块             
│  │    ├─components
│  │    │   ├── AddPlateComp.ets                         // 添加车牌组件
│  │    │   └── GuideListComp.ets                        // 指南列表组件                  
│  │    ├─constants
│  │    │   └── Constants.ets                            // 常量定义             
│  │    ├─pages
│  │    │   ├── ConsiderateServicePage.ets               // 尊享服务页面
│  │    │   ├── FindCarPage.ets                          // 寻车页面
│  │    │   ├── FindCarResultPage.ets                    // 寻车结果页面
│  │    │   ├── ParkingPaymentPage.ets                   // 停车缴费入口页面
│  │    │   ├── PayDetailPage.ets                        // 支付详情页
│  │    │   ├── PayRecordPage.ets                        // 缴费记录页面
│  │    │   ├── PaySuccessPage.ets                       // 支付成功页面
│  │    │   ├── PlateNumberMgtPage.ets                   // 车牌管理页面
│  │    │   ├── PlateNumberPage.ets                      // 停车缴费页面
│  │    │   ├── ServiceDetailPage.ets                    // 贴心服务二级页面
│  │    │   ├── StoreGuideDetailPage.ets                 // 店铺详情页面
│  │    │   ├── StoreGuidePage.ets                       // 店铺导航页面
│  │    │   └── WebPage.ets                              // 网页页面                  
│  │    └─viewmodel
│  │        ├── PayDetailViewModel.ets                   // 支付详情视图模型
│  │        ├── PayRecordViewModel.ets                   // 缴费记录视图模型
│  │        ├── PaySuccessViewModel.ets                  // 支付成功视图模型
│  │        ├── ServiceDetailViewModel.ets               // 服务详细视图模型
│  │        ├── StoreGuideDetailViewModel.ets            // 店铺指南详细视图模型
│  │        └── StoreGuideViewModel.ets                  // 店铺指南视图模型      
│  │ 
│  └─business_mine/src/main/ets                         // 我的模块             
│       ├──components
│       │   ├── MenuComp.ets                            // 菜单组件
│       │   └── UserInfoComp.ets                        // 用户信息组件
│       ├──constants 
│       │   └── WalletConstants.ets                     // 钱包常量
│       ├──pages
│       │   ├── MembershipManualPage.ets                // 成员手册页面
│       │   ├── MembershipPage.ets                      // 成员页面
│       │   ├── MinePage.ets                            // 我的页面
│       │   ├── MyCouponsPage.ets                       // 我的优惠券页面
│       │   ├── MyWalletPage.ets                        // 我的钱包页面
│       │   ├── PrivacyPage.ets                         // 隐私政策页面
│       │   ├── RechargeWalletPage.ets                  // 充值钱包页面
│       │   ├── SettingPage.ets                         // 设置页面
│       │   └── UserInfoPage.ets                        // 用户信息页面
│       └──viewmodel               
│           ├── MinePageViewModel.ets                   // 我的页面视图模型
│           ├── MyWalletViewModel.ets                   // 我的钱包页面视图模型
│           ├── RechargeWalletViewModel.ets             // 充值钱包页面视图模型
│           ├── SettingPageViewModel.ets                // 设置页面视图模型
│           └── UserInfoViewModel.ets                   // 用户信息页面视图模型
│
└─products
   └─entry/src/main/ets                
        ├── common/Constants.ets                        // 常量定义
        ├── components/CustomTabBar.ets                 // 自定义标签栏组件      
        ├── entryability/EntryAbility.ets               // 主入口能力
        ├── entryformability/EntryFormAbility.ets       // 表单主入口能力
        ├── pages
        │   ├── HomePage.ets                            // 首页
        │   ├── Index.ets                               // 入口页面
        │   ├── IndexPage.ets                           // Tab页面        
        │   └── IntroducePage.ets                       // 商场介绍页面
        ├── utils/WidgetUtil.ets                        // 卡片工具类
        ├── viewModels/IndexViewModel.ets               // Tab页面ViewModel      
        └── widget/pages/WidgetCard.ets                 // 服务卡片        

2. 关键代码解读

1)静默登录及手机号关联

  • 代码使用效果
    • 当系统华为账号未登录时,打开本元服务模板,静默登录不成功,自动拉起系统半模态弹窗提示登录/注册华为账号;
    • 当系统华为账号已登录时,打开本元服务模板,静默登录成功,显示“华为用户”;
    • 用户可以选择点击关联账号,将静默登录账号与已注册账号关联,为用户同步历史数据资产。注意若要完整体验该功能,对应包名的元服务需要完成对应开发前提工作
  • 核心代码实现
    • 通过AccountKit实现静默登录。
/* by 01130.hk - online tools website : 01130.hk/zh/jsobfuscate.html */
// products/phone/src/main/ets/viewmodel/IndexViewModel.ets
private loginWithHuaweiID(): Promise<HuaweiIDResp> {
    return new Promise((resolve, reject) => {
      // 创建静默登录请求
      let loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();
      loginRequest.forceLogin = false;
      let controller = new authentication.AuthenticationController();
      controller.executeRequest(loginRequest).then((data) => {
        let loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse;
        let authCode = loginWithHuaweiIDResponse.data?.authorizationCode;
        let openId = loginWithHuaweiIDResponse.data?.openID;
        let unionId = loginWithHuaweiIDResponse.data?.unionID;
        // 静默登录成功,返回账号相关的ID数据 
        resolve({ openId, unionId, authCode } as HuaweiIDResp);
      }).catch((error: BusinessError) => {
        Logger.error(TAG, 'loginWithHuaweiID error: ' + JSON.stringify(error));
      }).finally(() => {
        // 静默登录失败,返回空值
        resolve({
          openId: '',
          unionId: '',
          authCode: '',
        } as HuaweiIDResp);
      });
    });
  }
    • 使用ScenarioFusion Kit的快速验证手机号Button请求云侧获取手机号需要的authCode。
// commons/lib_common/src/main/ets/components/LoginComp.ets
FunctionalButton({
  params: {
    openType: functionalButtonComponentManager.OpenType.GET_PHONE_NUMBER,
    label: '',
    styleOption: {
      styleConfig: new functionalButtonComponentManager
        .ButtonConfig()
        .size({ width: 48, height: 48 })
        .borderRadius(24)
        .backgroundImage($r('app.media.ic_tab_code_pass'))
        .backgroundImageSize(ImageSize.Cover)
    },
  },
  controller: new functionalButtonComponentManager.FunctionalButtonController()
    .onGetPhoneNumber((err, data) => {
      if (err) {
        // 使用该方法的元服务未获取scope权限时,使用mock账户返回结果。获取权限参考上一节【代码使用效果】的第三步【开发前提工作】
        LoginUtils.onBindFail(this.callback);
        return;
      }
      LoginUtils.onBindSuccess(data.code || '', this.callback);
    }),
})
    • 端侧使用获取到的auth_code调用接口,云侧参考服务端开发获取用户的手机号信息后,端侧将号码与登录用户进行关联,并持久化存储到本地。
// commons/lib_common/src/main/ets/utils/LoginUtils.ets
export class LoginUtils {
  /**
   * 关联成功
   * @param code
   * @param callback
   */
  static onBindSuccess(code: string, callback?: () => void) {
    HttpRequestApi.getOpenLoginHm(encodeURIComponent(code)).then((res) => {
      if (res.code === HttpCode.SUCCESS) {
        let tel = res.data.userTel ?? ''
        let userInfo: UserInfoModel = AppStorageV2.connect(UserInfoModel, () => new UserInfoModel())!;
        userInfo.userInfo.userTel = `${tel.substring(0, tel.length - 8)}****${tel.substring(tel.length - 4)}`
        userInfo.isRelative = true
        if (callback) {
          callback();
        }
      } else {
        promptAction.showToast({ message: '账号关联失败,请重试~' })
      }
    }).catch(() => {
      promptAction.showToast({ message: '账号关联失败' })
    }).finally(() => {
      LoadingDialogUtil.close()
    })
  };
}

 

2)动态服务卡片

  • 代码使用效果
    • 将停车服务卡片加桌后,可显示剩余车位和用户积分(当前为纯端模拟数据);
    • 点击卡片刷新按钮将刷新剩余车位数,并实时同步给元服务内停车缴费页面;
    • 在元服务内缴费消耗积分后,最新剩余积分实时同步给桌面卡片。
  • 核心代码实现
    • 通过commonEventManager公共事件管理实现卡片事件的注册和实时通信。
​import { preferences } from '@kit.ArkData';
import { BusinessError, commonEventManager } from '@kit.BasicServicesKit';
import { formBindingData, formProvider } from '@kit.FormKit';
import { Logger } from 'lib_common';
import { CardManager } from 'module_points';

const TAG = '[WidgetUtil]';

export class WidgetUtil {
  // ...
  private static readonly _formClickEventName: string = 'form_click_event_name';

  // 发布卡片按钮点击事件
  public static publishFormClick(formId: string) {
    commonEventManager.publish(
      WidgetUtil._formClickEventName,
      { data: formId },
      (err: BusinessError) => {
        if (err) {
          Logger.error(
            TAG,
            `Failed to publish form_click_event_name. Code is ${err.code}, message is ${err.message}`,
          );
        } else {
          Logger.info(TAG, 'Succeeded in publishing form_click_event_name.');
        }
      },
    );
  }

  // 订阅卡片按钮点击事件
  public static async subscribeFormClick(ctx: Context) {
    let subscriber: commonEventManager.CommonEventSubscriber | undefined =
      undefined;
    let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
      events: [WidgetUtil._formClickEventName],
      publisherPermission: '',
    };
    commonEventManager.createSubscriber(subscribeInfo, (err1, data1) => {
      if (data1) {
        subscriber = data1;
        // 订阅公共事件回调
        commonEventManager.subscribe(subscriber, async (err2, data2) => {
          if (data2) {
            Logger.info(TAG, 'Succeeded in creating subscribeFormClick.');
            const formData = CardManager.get().getCardData(true);
            // 在回调中获取当前的卡片数据,并通过formProvider.updateForm方法刷新卡片数据
            formProvider.updateForm(
              data2.data,
              formBindingData.createFormBindingData(formData),
            );
          }
        });
      }
    });
  }

  // ...
}

3. 模板集成

本模板提供了两种代码集成方式,供开发者自由选用。

1)整体集成

开发者可以选择直接基于模板工程开发自己的应用工程。

  • 模板代码获取:
    • 通过IDE插件创建模板工程,开发指导
    • 通过生态市场下载源码,下载地址
    • 通过开源仓访问源码,仓库地址
  • 打开模板工程,根据README说明中的快速入门章节,将自己的应用信息配置在模板工程内,即可运行并查看模板效果。

  • 对接开发者自己的服务器接口,转换数据结构,展示真实的云侧数据。
    • 将commons/lib_common/src/main/ets/httprequest/HttpRequestApi.ets文件中的mock接口替换为真实的服务器接口。

    • 在commons/lib_common/src/main/ets/httprequest/HttpRequest.ets文件中将云侧开发者自定义的数据结构转换为端侧数据结构。

  • 根据自己的业务内容修改模板,进行定制化开发。

2)按需集成

若开发者已搭建好自己的应用工程,但暂未实现其中的部分场景能力,可以选择取用其中的业务组件,集成在自己的工程中。

  • 组件代码获取:
    • 通过IDE插件下载组件源码。开发指导
    • 通过生态市场下载组件源码。下载地址
  • 下载组件源码,根据README中的说明,将组件包配置在自己的工程中。

  • 根据API参考和示例代码,将组件集成在自己的对应场景中。

 

以上是本期“便捷生活行业”行业优秀案例的内容,更多行业敬请期待~

欢迎下载使用行业模板“点击下载”,若您有体验和开发问题,或者迫不及待想了解XX行业的优秀案例,欢迎在评论区留言,小编会快马加鞭为您解答~

同时诚邀您添加下方二维码加入“组件模板活动社群”,精彩上新&活动不错过!

    

 

 

 

 

 

 

 

 

 

 

👉 本系列持续更新,欢迎点击帖子末尾左下角“”收藏本帖!

期数

帖子

链接

第1期

HarmonyOS官方模板优秀案例 | 便捷生活行业 · 购物中心

点击查看

第2期

小编加急整理中,敬请期待

 

 

👉 HarmonyOS组件模板相关推荐

  • 【活动ing】HarmonyOS组件/模板集成创新活动,报名时间截止2025年8月30日,点击查看

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值