文档管理中心
指南汽车类行业实践汽车应用案例

汽车应用案例

简介

本文档介绍汽车类HarmonyOS应用的架构设计实践,提供常见的资讯、购车、商城以及充电服务等功能,帮助开发者快速构建一款汽车类应用。

  • Stage开发模型+声明式UI开发范式。
  • 按照应用设备形态,规划一个手机设备Entry类型HAP包。
  • 本实践性能优先,应用程序包大小可控,且无单独加载模块场景,业务模块包类型采用HAR包。

应用布局

说明

实践应用框架代码运行图,开发者可以基于框架代码替换相关资源文件,以保证应用良好的使用体验。

  • 应用首页采用各类APP常见页面导航布局。
  • 首页底部导航包含“探索”,“购车”,“商城”,“服务”,“我的”五个功能入口,分别对应五个功能模块(模块划分详见本实践软件视图)。
  • 探索页面上部是热门汽车介绍Banner轮播图,中间是汽车资讯列表瀑布流。
  • 购车页面提供车辆详细信息以及预约试驾等能力。
  • 首页->服务->最优站点,基于位置提供最佳充电位置服务。

应用架构设计

模块划分

根据行业应用的功能,按照高内聚,低耦合的原则,常见汽车类应用功能以及职责划分模块如下,开发者在实际设计过程中,可以根据模块的复杂程度实际情况再进一步细分:

表1 模块划分
展开

模块名称

功能点

探索

行业资讯

购车

产品详情,购车指南

商城

商品搜索,商品详情,商品购买

服务

充电服务,服务门店

我的

我的车辆,我的订单,我的积分,我的家充

通用

资源,国际化,导航

软件视图设计

应用分层模块类型划分指导,参见分层模块化实践

产品定制层:本实践只涉及手机端,设计为一个HAP,包含页面框架、导航、手机独有资源等。

基础特性层:“探索”、“购车” 等功能模块设计为HAR包,被上层引用。

公共能力层:本实践将“应用路由”、“基础工具”、“DFX”等基础公共模块打包为Har包被上层业务组件引用,其中路由管理划分到公共组件。

图1 软件视图

逻辑视图设计

根据本应用功能的模块以及依赖,分解对基础服务以及三方的依赖,逻辑视图如下:

图2 逻辑视图

公共关键技术方案

介绍行业应用通用的公共关键技术,详见公共关键技术方案

行业关键技术方案

扫码充电技术方案

功能设计

扫码充电是汽车类行业的基础能力。应用充电服务,提供最优站点列表以及路径规划。常见页面路径:首页->服务->扫码充电,功能入口如下图所示:
图3 扫码充电功能入口

设计

使用Scan Kit(统一扫码服务)实现扫码能力,本示例代码使用默认界面扫码能力。

表2 方案对比参考
展开

能力

限制条件

scanBarcode (默认界面扫码)

系统体验一致的扫码体验,系统预授权,暂不支持悬浮屏、分屏场景,相册扫码只支持单码识别。

customScan (自定义界面扫码)

适用对扫码有定制需求的开发,需要授权使用相机权限;需要开发者自行实现扫码的人机交互界面。

代码参考

代码详情参见扫码充电代码实现

最优站点技术方案

功能设计

提供最优站点列表以及路径规划。常见页面路径:首页→服务→最优站点,功能页面如下图所示:

图4 最优充电站点功能页面

方案设计

  • 使用HarmonyOS Map Kit(地图服务)能力,应用无需集成SDK,不影响包大小,开发者不用考虑SDK升级。
  • 使用Map Kit地图服务,首先要在AppGallery Connect配置使用相关API,参考指导配置AppGallery Connect

代码参考

申请ohos.permission.LOCATION和ohos.permission.APPROXIMATELY_LOCATION权限,您需要在module.json5配置文件中声明所需要的权限,具体可参考声明权限

代码详情参见最优站点代码实现

行业创新设计

说明

结合HarmonyOS,针对行业的创新场景设计,开发者可以参考行业创新设计方案,实现创新场景代码。

导航体验提升设计

场景说明

最优站点页面,点击站点导航图标拉起导航类应用,导航应用单独一个界面。通用方案:使用隐式want能力,启动设备内地图应用,多个应用时会弹出对话框显示多个应用图标,用户选择。如果本机没有安装地图导航应用,会有类似“请安装地图应用”提示,用户需要先下载导航应用,操作繁琐,体验差。

创新设计

利用元服务免安装能力,导航元服务(相应元服务已上架)内嵌展示在应用内。在用户没有安装导航应用情况下,也能正常打开地图导航功能,实现导航能力。

图5 元服务内嵌效果示意图

应用框架代码

说明

本篇代码非应用的全量代码,只包括应用的部分框架代码。

框架代码中的登录验证仅提供UI界面,手机号输入满11位后,任意密码均可登录,开发者需自行实现鉴权认证。

代码运行环境

软件要求

  • DevEco Studio版本:DevEco Studio 6.0.0 Release及以上。
  • HarmonyOS SDK版本:HarmonyOS 6.0.0 Release SDK及以上。

硬件要求

  • 设备类型:华为手机。
  • HarmonyOS系统:HarmonyOS 6.0.0 Release及以上。

环境搭建

历史工程迁移

开发者使用HarmonyOS 6.0.0 Release及以上版本导入代码,使用一体化的历史工程迁移能力,帮助开发者快速完成工程转换。

代码结构解读

本篇代码非应用的全量代码,只包括脱敏后的应用框架代码,开发者可以通过链接下载全量的框架代码。

整个框架代码结构分为5个HAR包,所有的HAR在同一个IDE工程中维护开发。

图6 Entry集成的HAR列表

5个HAR分别为buyingCar,explore,mine,service,shoppingMall。

收起
自动换行
深色代码主题
复制
  1. ├── common/src/main/ets // 公共模块
  2. │ ├── components
  3. │ │ ├── NavItem.ets // nav组件
  4. │ │ ├── PageHeaderComp.ets // 二级页面头部组件
  5. │ │ └── ShopItem.ets // shop组件
  6. │ ├── constants
  7. │ │ ├── CommonConstants.ets // 公共样式
  8. │ │ ├── NavConstants.ets // nav样式
  9. │ │ └── TabConstants.ets // tab样式
  10. │ ├── model
  11. │ │ ├── BuyingCarModel.ets // 购车数据模型
  12. │ │ ├── CommodityModel.ets // 商城数据模型
  13. │ │ ├── ExploreModel.ets // 探索数据模型
  14. │ │ ├── LazyDataSource.ets // 懒加载数据
  15. │ │ ├── NavModel.ets // nav数据模型
  16. │ │ └── ShopModel.ets // shop数据模型
  17. │ └── utils
  18. │ ├── LoggerUtil.ets
  19. │ ├── PermissionsUtil.ets // 权限管理工具类
  20. │ └── PreferencesUtil.ets // 数据存储工具类
  21. ├── entry/src/main/ets // 主页面
  22. │ ├── constants
  23. │ │ └── TabConstants.ets // tab样式
  24. │ ├── entryability
  25. │ │ └── EntryAbility.ets // 程序入口
  26. │ └── pages
  27. │ ├── LoginPage.ets // 登录页
  28. │ ├── NavigationPage.ets // Navigation根页面
  29. │ ├── PrivacyPolicyPage.ets // 隐私政策页面
  30. │ ├── SplashScreenPage.ets // 闪屏页
  31. │ ├── SplashScreenPage2.ets // 闪屏页2
  32. │ └── TabPage.ets // tab页
  33. ├── features
  34. │ ├── buyingcar/src/main/ets // 购车
  35. │ │ ├── components
  36. │ │ │ ├── LearnMoreItemComp.ets // 了解更多item组件
  37. │ │ │ ├── MarqueeImageComp.ets // 走马灯图片
  38. │ │ │ ├── SwiperItemComp.ets // 购车swiperItem组件
  39. │ │ │ └── VehicleModelActivities.ets // 车型item组件
  40. │ │ └── pages
  41. │ │ ├── BuyingCarDetailPage.ets
  42. │ │ └── BuyingCarPage.ets // 购车tab页
  43. │ ├── explore/src/main/ets // 探索
  44. │ │ ├── components
  45. │ │ │ ├── ActivityComp.ets // 活动swiper页
  46. │ │ │ ├── ActivityItemComp.ets // 活动item组件
  47. │ │ │ ├── RealTimeInfoComp.ets // 咨询swiper页
  48. │ │ │ └── RecommendationComp.ets // 推荐swiper页
  49. │ │ ├── constants
  50. │ │ │ └── RecommendationConstants.ets // 探索tab页
  51. │ │ └── pages
  52. │ │ └── ExplorePage.ets
  53. │ ├── mine/src/main/ets // 我的
  54. │ │ ├── components
  55. │ │ │ └── MajorList.ets // 单个组件
  56. │ │ ├── constants
  57. │ │ │ ├── HeaderConstants.ets // 头部样式
  58. │ │ │ └── MajorConstants.ets // major样式
  59. │ │ ├── model
  60. │ │ │ └── MajorModel.ets // major模型
  61. │ │ └── pages
  62. │ │ ├── MinePage.ets // 我的tab页
  63. │ │ └── SettingsPage.ets // 设置页面
  64. │ ├── service/src/main/ets // 服务
  65. │ │ ├── components
  66. │ │ │ └── SheetTransition.ets // sheet模态框
  67. │ │ ├── constants
  68. │ │ │ └── ServiceConstants.ets // 服务样式
  69. │ │ ├── model
  70. │ │ │ └── StationModel.ets // station模型
  71. │ │ ├── pages
  72. │ │ │ ├── MyCharge.ets // 我的充电页
  73. │ │ │ ├── OptimalStation.ets // 最优站点页
  74. │ │ │ └── ServicePage.ets // 服务tab页
  75. │ └── shoppingMall/src/main/ets // 商城
  76. │ ├── components
  77. │ │ └── CommodityItemComp.ets // 商城列表item组件
  78. │ ├── constants
  79. │ │ └── ShoppingMallConstants.ets // 商城样式
  80. │ └── pages
  81. │ ├── CommodityDetailPage.ets // 商城详情
  82. │ └── ShoppingMallPage.ets // 商城tab页
  83. └── entry/src/main/resources // 资源文件目录

扫码充电代码实现

使用Scan Kit(统一扫码服务)实现扫码能力。本示例采用默认的扫码能力,调用默认界面扫码接口能力,具备相机预授权,集成简单,适用于通用扫码场景。
收起
自动换行
深色代码主题
复制
  1. // features\service\src\main\ets\pages\ServicePage.ets
  2. Row() {
  3. ForEach(this.mapShopList, (item: shopInfo, index: number) => {
  4. Row() {
  5. ShopItem({ itemData: item })
  6. }.onClick(() => {
  7. if (item.title === '扫码充电') {
  8. // 定义扫码参数options
  9. let options: scanBarcode.ScanOptions = {
  10. scanTypes: [scanCore.ScanType.ALL], // 设置扫码类型,默认扫码ALL(全部码类型)
  11. enableMultiMode: true, // 是否开启多码识别,默认false
  12. enableAlbum: true // 是否开启相册,默认true, 此参数只控制默认界面扫码能力中的相册扫码且只支持单码识别。
  13. };
  14. try {
  15. scanBarcode.startScanForResult(getContext(this), options).then((result: scanBarcode.ScanResult) => {
  16. // 收到扫码结果后返回
  17. Logger.info('Promise scan result: %{public}s', JSON.stringify(result));
  18. // 处理扫码结果
  19. this.showScanResult(result);
  20. }).catch((error: BusinessError) => {
  21. Logger.error('Promise error: %{public}s', JSON.stringify(error));
  22. });
  23. } catch (error) {
  24. Logger.error('failReason: %{public}s', JSON.stringify(error));
  25. }
  26. }
  27. if (item.title === '最优站点') {
  28. this.pageInfos.pushPath({ name: 'OptimalStation' });
  29. } else if (item.title === '我的充电') {
  30. this.pageInfos.pushPath({ name: 'MyCharge' });
  31. }
  32. })
  33. if (index !== this.mapShopList.length - 1) {
  34. Line().LineStyle();
  35. }
  36. })
  37. }
  38. .width(CommonConstants.COLUMN_WIDTH)
  39. .justifyContent(FlexAlign.SpaceEvenly)

开发者也可调用customScan (自定义界面扫码)接口能力,自定义实现扫码界面,需要申请相机权限,需要在配置文件module.json5里添加:ohos.permission.CAMERA,参见应用权限列表。适用于对扫码界面有个性化定制的场景。

最优站点代码实现

使用HarmonyOS Map Kit(地图服务)能力。

配置相关权限entry\src\main\module.json5
收起
自动换行
深色代码主题
复制
  1. "requestPermissions": [
  2. {
  3. "name": "ohos.permission.LOCATION",
  4. "reason": "$string:EntryAbility_desc",
  5. "usedScene": {
  6. "abilities": [
  7. "EntryAbility"
  8. ],
  9. "when": "always"
  10. }
  11. },
  12. {
  13. "name": "ohos.permission.APPROXIMATELY_LOCATION",
  14. "reason": "$string:EntryAbility_desc",
  15. "usedScene": {
  16. "abilities": [
  17. "EntryAbility"
  18. ],
  19. "when": "always"
  20. }
  21. }
  22. ]

使用MapComponent地图组件在页面中放置地图。MapComponentController是地图组件的主要功能入口类,用来操作地图,与地图有关的所有方法从此处接入。它所承载的工作包括:地图类型切换(如标准地图、空地图)、改变地图状态(中心点坐标和缩放级别)、添加点标记(Marker)、绘制几何图形(MapPolyline、MapPolygon、MapCircle)、各类事件监听等。

收起
自动换行
深色代码主题
复制
  1. // features\service\src\main\ets\pages\OptimalStation.ets
  2. @Entry
  3. @Component
  4. export struct OptimalStation {
  5. @StorageProp('avoidArea') topHeight: number = 0;
  6. private mapOption?: mapCommon.MapOptions;
  7. @State addressName: string = '';
  8. private callback?: AsyncCallback<map.MapComponentController>;
  9. private mapController?: map.MapComponentController;
  10. // 地图初始化经纬度,可自定义。
  11. private latLng: mapCommon.LatLng = {
  12. latitude: 31.97413747571286,
  13. longitude: 118.77314161376894
  14. }
  15. @State addressString: string = '';
  16. @Consume('pageInfos') pageInfos: NavPathStack;
  17. build() {
  18. NavDestination(){
  19. Stack({ alignContent: Alignment.Bottom }) {
  20. MapComponent({ mapOptions: this.mapOption, mapCallback: this.callback }).width('100%').height('100%');
  21. // ...
  22. Row() {
  23. // 半模态框
  24. SheetTransition({
  25. StationList: Station.getStationList(),
  26. addressName: this.addressName
  27. })
  28. }.margin({ bottom: 220 })
  29. }
  30. }
  31. .hideTitleBar(true)
  32. .onReady(()=>{
  33. // 地图初始化参数,设置地图中心点坐标及层级
  34. this.mapOption = {
  35. position: {
  36. target: this.latLng,
  37. zoom: 14
  38. },
  39. zoomControlsEnabled: false,
  40. myLocationControlsEnabled: true
  41. };
  42. // 地图初始化的回调
  43. this.callback = async (err, mapController) => {
  44. if (!err) {
  45. // 获取地图的控制器类,用来操作地图
  46. this.mapController = mapController;
  47. // 启用我的位置图层
  48. this.mapController?.setMyLocationEnabled(true);
  49. this.mapController.on("mapLoad", () => {
  50. });
  51. // 监听“我的位置”按钮点击事件
  52. this.mapController.on("myLocationButtonClick", () => {
  53. this.getMyLocation();
  54. });
  55. // 初始化我的位置
  56. this.getMyLocation();
  57. }
  58. };
  59. })
  60. }
  61. }

由于框架示例代码访问API受限,目前最优站点列表数据来源是本地数据,数据文件位置:features>service src/main/ets/model/StationModel.ets。

开发者可以基于此示例代码,使用位置搜索能力,查找相关POI,根据响应替换本地数据,在此基础上,根据响应使用地图绘制能力,在地图上设置图标,效果更佳。

代码下载链接

汽车类示例代码.zip

搜索
请输入您想要搜索的关键词