# wango **Repository Path**: ckunkun/wango ## Basic Information - **Project Name**: wango - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-31 - **Last Updated**: 2024-05-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1 介绍 > 本篇Codelab将介绍如何使用ArkTS声明式语法和基础组件,开发两轮电动车管理APP——智骑行。效果为操作交互控件,可查看车辆电量、温度、位置等信息;可远程开关锁、响铃找车。基于ArkTS声明式语法和基础组件、服务卡片、键值数据持久化,实现两轮电动车管理APP。 > > ![image.png](https://dl-harmonyos.51cto.com/images/202311/b247e6e41895b110623030448e6bde68b150f3.png?x-oss-process=image/resize,w_376,h_372) **演示视频链接**:[智骑行](http://iot.hellokun.cn/) ## 相关概念 - [ArkTS语言](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-get-started-0000001820879561):ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。 - [Text组件](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-text-0000001815927600):显示一段文本的组件。 - [Column组件](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-column-0000001862607437):沿垂直方向布局的容器。 - [Row组件](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-row-0000001815767836):沿水平方向布局的容器。 - [ArkWeb](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-component-overview-0000001774120270):提供了Web组件,用于在应用程序中显示Web页面内容。 ## 完整示例 [gitee源码地址]([ckunkun/wango (gitee.com)](https://gitee.com/ckunkun/wango)) # 2 环境搭建 我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。 ## 软件要求 - DevEco Studio版本:DevEco Studio NEXT Developer Preview2及以上。 - HarmonyOS SDK版本:HarmonyOS NEXT Developer Preview2 SDK及以上。 ![img](https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyManage/011/111/111/0000000000011111111.20240117194604.36618030562474264221190081854905:50001231000000:2800:2DC71D74FE5266A3370DA95B88310CF3F36BD8F6EA7A7FA1BF90C947DEAFD27F.png?needInitFileName=true) ## 硬件要求 - 设备类型:华为手机。 - HarmonyOS系统:HarmonyOS NEXT Developer Preview2及以上。 ## 环境搭建 1. 安装DevEco Studio,详情请参考[下载](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-software-download-0000001507075446)和[安装软件](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-software-install-0000001558013317)。 2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,详情请参考[配置开发环境](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-environment-config-0000001507213638)。 3. 开发者可以参考以下链接,完成设备调试的相关配置: - [使用真机进行调试](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-debug-device-0000001053822404) # 3 代码结构解读 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载中提供。 ```sh ├──entry/src/main/ets // ArkTS代码区 |-- ets | |-- common | | `-- Constant.ts // 通用常量 | |-- entryability | | |-- EntryAbility.ts // 应用入口 | |-- entryformability | | `-- EntryFormAbility.ts // 卡片入口 | |-- model | | |-- SettingItem.ts // 设置项自定义组件 | |-- pages | | |-- Index.ets // 主页 | |-- widget24 | | `-- pages // 2*4卡片 | `-- widget_bike | `-- pages // 2*2卡片 |-- module.json5 `-- resources // 本地资源文件 |-- rawfile | |-- index.html // 本地html网页 加载地图 ``` # 4 构建主界面 本章节将介绍应用主页面的实现,采用Column容器嵌套Tab完成页面整体布局,页面分为三个部分(加载地图依赖网络,需要配置[ohos.permission.INTERNET](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions-0000001820999665)网络访问权限。): - 首页:使用Stack容器和Image等基础组件展示车辆信息。 - 地图:使用Web组件加载本地html文件,显示地图。 - 设置:使用List与自定义组件渲染设置项 ```js // Index.ets build() { Column(){ Tabs({ barPosition: BarPosition.End, controller: this.controller }) { TabContent() {...} .tabBar(this.TabBuilder(0,'首页')) TabContent() { // Web component loading H5. Web({ src: $rawfile('index.html'), controller: this.webviewController }) .zoomAccess(true) .width('100%') .height('100%') } .width(Const.WebConstant_FULL_WIDTH) .height(Const.WebConstant_FULL_HEIGHT)} .tabBar(this.TabBuilder(1,'地图')) TabContent() {...} .tabBar(this.TabBuilder(2,'我的')) } .vertical(false) .barHeight(100) .onChange((index: number) => { this.currentIndex = index }) .width('100%') .height('100%') } .height('100%') .backgroundImage($r('app.media.background_lite')) .backgroundImageSize({ width: '100%', height: '100%' }) } ``` ![image-20240531190805378](C:\Users\jingwen liang\AppData\Roaming\Typora\typora-user-images\image-20240531190805378.png) # 5 自定义子组件 在Index.ets中为了便于区分当前的Tabs的TabContent,自定义一个Tab bar,选中时显示不同图标与文字效果。 ```js // Index.ets @Builder TabBuilder(index: number ,name:string) { Column() { Image(this.currentIndex === index ? $r("app.media.bar_on") : $r("app.media.bar_off")) .width(50) .height(50) .margin({ bottom: 8 }) .objectFit(ImageFit.Contain) Text(name) .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor) .fontSize(this.my_font_size) .lineHeight(this.my_font_size+2) }.width('100%') } ``` 在SettingItem.ets文件中,显示的内容为设置项目图标、内容、文本输入框。在Index.ets中的”我的“ Tab标签中使用List渲染出设置项目。 ```js // SettingItem.ets ... @Entry @Component struct SettingItem { @Link Icon: Resource; @Link Title: string; @Link Content: string; build() { Row() { Image(this.Icon) Column() { Text(this.Title) } Text(this.Content) } } } ``` ![](C:\Users\jingwen liang\AppData\Roaming\Typora\typora-user-images\image-20240531190842126.png) # 6 数据管理 ## 数据存储 为方便使用和管理数据,使用首选项存储设置项内容,在EntryAbility.ets中, 加载Index页面前先创建首选项示例,并封装了两个接口用于创建和修改Key和对应的value ```js import dataPreferences from '@ohos.data.preferences'; export let SettingPreferences: dataPreferences.Preferences | null = null; // key不重复写入 export function SettingSet(key:string,value:string){ if(SettingPreferences!=undefined) { if (SettingPreferences.hasSync(key)) { console.info("The key "+key+" is contained."); return } else { console.info("The key "+key+" does not contain."); // 此处以此键值对不存在时写入数据为例 SettingPreferences.putSync(key, value); SettingPreferences.flush((err: BusinessError) => { if (err) { console.error(`The key Failed to flush. Code:${err.code}, message:${err.message}`); return; } console.info('The key Succeeded in flushing.'); }) } } } //只在有key时修改 export function SettingChange(key:string,value:string){ if(SettingPreferences!=undefined) { if (SettingPreferences.hasSync(key)) { console.info("The key "+key+" is contained."); // 此处以此键值对不存在时写入数据为例 SettingPreferences.putSync(key, value); SettingPreferences.flush((err: BusinessError) => { if (err) { console.error(`The key Failed to flush. Code:${err.code}, message:${err.message}`); return; } console.info('The key Succeeded in flushing.'); }) }else{ console.info("The key "+key+" is NOT contained."); } } } // 使用首选项实例 SettingPreferences = dataPreferences.getPreferencesSync(this.context, options); // 创建 SettingSet('ALLPOWER','1519') SettingSet('Duration','999') SettingSet('Distance','520') SettingSet('BikeIP','192.168.56.101') // 设置值,如果有了就不需要设定默认值了 AppStorage.setOrCreate('ALLPOWER', SettingPreferences.getSync('ALLPOWER','1519')); AppStorage.setOrCreate('Duration', SettingPreferences.getSync('Duration','999')); AppStorage.setOrCreate('Distance', SettingPreferences.getSync('Distance','520')); AppStorage.setOrCreate('BikeIP', SettingPreferences.getSync('BikeIP','192.168.56.101')); ``` 后续根据业务需求进行存取,如在点击刷数据按钮时,获取传入的数据。 ```js // Index.ets @StorageLink('ALLPOWER') ALLPOWER: string | undefined = AppStorage.get('ALLPOWER'); @StorageLink('Duration') Duration: string | undefined = AppStorage.get('Duration'); @StorageLink('Distance') Distance: string | undefined = AppStorage.get('Distance'); ``` ## WEB与ArkTS交换数据 真实情况下,车辆的数据是从MQTT等物联网服务器获取,在html中可以轻易的获取车辆实时的电量、位置等信息。这里讲解如何实现html与ArkTS之间数据交互。 首先,在启动app时,要在Index.ets的aboutToAppear()中创建一个和H5页面通信的消息通道,实现如下: ```js TryWebPort(): void { try { // 1、创建两个消息端口。 this.ports = this.webviewController.createWebMessagePorts(); // 2、在应用侧的消息端口(如端口1)上注册回调事件。 this.ports[1].onMessageEvent((result: web_webview.WebMessage) => { let msg = 'Got msg from HTML:'; ... }) // 3、将另一个消息端口(如端口0)发送到HTML侧,由HTML侧保存并使用。 this.webviewController.postMessage('__init_port__', [this.ports[0]], '*'); } catch (error) { promptAction.showToast({duration:2000,message:'发送失败'}) let e: business_error.BusinessError = error as business_error.BusinessError; console.error(`ErrorCode: ${e.code}, Message: ${e.message}`); } } ``` 其次,需要在本地src/main/resources/rawfile/index.html 中创建一个用于接收的监听端口,具体实现如下: ```js // 页面 var h5Port; var output = document.querySelector('.output'); window.addEventListener('message', function (event) { if (event.data === '__init_port__') { if (event.ports[0] !== null) { h5Port = event.ports[0]; // 1. 保存从ets侧发送过来的端口 h5Port.onmessage = function (event) { // 2. 接收ets侧发送过来的消息. var msg = 'Got message from ets:'; var result = event.data; if (typeof(result) === 'string') { console.info(`received string message from html5, string is: ${result}`); msg = result; } else if (typeof(result) === 'object') { if (result instanceof ArrayBuffer) { console.info(`received arraybuffer from html5, length is: ${result.byteLength}`); msg = msg + 'lenght is ' + result.byteLength; } else { console.info('not support'); } } else { console.info('not support'); } // this.PositionName = msg.toString(); } } } }) ``` 本地的H5可以通过与ets建立的消息通道,直接发送数据到用户页面,这个通道也可以用来接收H5发送回来的数据. ```js // 使用h5Port往ets侧发送消息. function PostMsgToEts(data) { console.info('H5 to Ets data:'+data); if (h5Port) { h5Port.postMessage(data); } else { console.error('h5Port is null, Please initialize first'); } } // 调用接口发送数据到ets用户页面,便于存储和展示 this.PostMsgToEts(PilotPower.toString()+PositionName); // 电量+位置 ``` # 7 服务卡片 右键点击main文件夹,新建widget,创建服务卡片,用于展示车辆的电量、地理等信息位置,每1min自动刷新,当前只实现了点击对应控件或者定时刷新固定的数据。 ![image-20240531201943682](C:\Users\jingwen liang\AppData\Roaming\Typora\typora-user-images\image-20240531201943682.png) ![image.png](https://dl-harmonyos.51cto.com/images/202311/f6603023843fa2bd8c09679a51d78d2c23dcf6.png?x-oss-process=image/resize,w_350,h_173)