飞道的博客

用鸿蒙开发AI应用(六)UI篇

367人阅读  评论(0)

前言

上一篇,我们在鸿蒙上写了一个HDF驱动并操作了一下LED硬件,这一篇我们来尝试一下构建一个有简单界面的App,体验一下鸿蒙的前端开发流程。

环境准备

1. 安装DevEco Studio

解压相应的压缩包(文末附下载链接),这里以win10为例,双击deveco-studio-2.0.12.201.exe

指定安装目录

设置可选快捷方式和环境变量

一路下一步即可。

同意用户协议后,就能正常启动了。

2. 更新sdk

在菜单 Setting->HarmonyOS SDK->SDK Platforms中,选择JsJava,安装新版的SDK

同样在SDK Tools中,选中新版的Previewer

点击Apply更新

新建项目

点击菜单File->New Project...,选择智慧屏Smart Vision,创建一个空模板应用。

填入项目名称MyUiAPP,点击完成就能创建一个工程了。

遇到 gradle下载太慢或版本差异的,可以直接在以下网址用工具下载

https://services.gradle.org/distributions/

目录结构

我们先分析一下目录结构,做Android开发的会倍感亲切。

1. APP

HarmonyOS的应用软件包以APP Pack(Application Package)形式发布,它是由一个或多个HAP(HarmonyOS Ability Package)以及描述每个HAP属性的pack.info组成。HAPAbility的部署包,HarmonyOS应用代码围绕Ability组件展开。

一个HAP是由代码、资源、第三方库及应用配置文件组成的模块包,可分为entryfeature两种模块类型。

  • 「entry」:应用的主模块。一个APP中,对于同一设备类型必须有且只有一个entry类型的HAP,可独立安装运行。

  • 「feature」:应用的动态特性模块。一个APP可以包含一个或多个feature类型的HAP,也可以不含。只有包含AbilityHAP才能够独立运行。

2. Ability

Ability是应用所具备的能力的抽象,一个应用可以包含一个或多个AbilityAbility分为两种类型:FA(Feature Ability)PA(Particle Ability)FA/PA是应用的基本组成单元,能够实现特定的业务功能。FAUI界面,而PAUI界面。

3. 资源文件

应用的资源文件(字符串、图片、音频等)统一存放于resources目录下,便于开发者使用和维护。resources目录包括两大类目录,一类为base目录与限定词目录,另一类为rawfile目录。

4. 配置文件

配置文件(config.json)是应用的Ability信息,用于声明应用的Ability,以及应用所需权限等信息。

  • 应用的全局配置信息,包含应用的包名、生产厂商、版本号等基本信息。

  • 应用在具体设备上的配置信息,包含应用的备份恢复、网络安全等能力。

  • HAP包的配置信息,包含每个Ability必须定义的基本属性(如包名、类名、类型以及Ability提供的能力),以及应用访问系统或其他应用受保护部分所需的权限等。

5. JS UI 框架

JS UI框架是一种跨设备的高性能UI开发框架,支持声明式编程和跨设备多态UI

  • 声明式编程

    JS UI框架采用类HTMLCSS声明式编程语言作为页面布局和页面样式的开发语言,页面业务逻辑则支持ECMAScript规范的JavaScript语言。JS UI框架提供的声明式编程,可以让开发者避免编写UI状态切换的代码,视图配置信息更加直观。

  • 跨设备

    开发框架架构上支持UI跨设备显示能力,运行时自动映射到不同设备类型,开发者无感知,降低开发者多设备适配成本。

  • 高性能

    开发框架包含了许多核心的控件,如列表、图片和各类容器组件等,针对声明式语法进行了渲染流程的优化。

JS UI框架包括应用层(Application)、前端框架层(Framework)、引擎层(Engine)和平台适配层(Porting Layer)

空气质量监测 UI

1. 创建首页面

空气质量监测App包含两个界面(Page),工程创建完成后会生成一个名为indexPage,可以作为首页。

2. 创建详情页

pages目录按右键,弹出的菜单中选择New->JS Page

输入页面名称detail

详情页创建完成后应用工程目录如下图所示,每个Page包括三个文件:布局文件hml、样式文件css、业务逻辑代码js

3. 开发首页

应用首页主要展示城市的空气质量概况。首页总共有两屏(可以根据需求设置多屏),每屏显示一个城市的空气质量信息:主要包括AQI指数、城市名称、污染物指数、更新时间和信息来源等数据。

3.1 创建根节点

修改entry/src/main/js/default/pages/index/index.hml,加入根节点div


   
  1. <div class= "container">
  2. </div>

3.2 创建样式

修改entry/src/main/js/default/pages/index/index.css


   
  1. .container {
  2. flex-direction: column;
  3. height: 480px;
  4. width: 960px;
  5. }

3.3 添加标题栏

标题栏包括一个退出按钮和一个标题,两个控件是横向排列


   
  1. <div class= "container">
  2. <div class= "header" onclick= "exitApp">
  3. <image class= "back" src= "common/ic_back.png"></image>
  4. <text class= "title">
  5. 空气质量
  6. </text>
  7. </div>
  8. </div>

注意,这里要先导入common/ic_back.png图标资源。

3.4 添加标题栏样式

修改entry/src/main/js/default/pages/detail/detail.css,添加以下代码,设置组件的高度、边距、颜色等属性。


   
  1. .header {
  2. width: 960px;
  3. height: 72px;
  4. }
  5. .back {
  6. width: 36px;
  7. height: 36px;
  8. margin-left: 39px;
  9. margin-top: 23px;
  10. }
  11. .title {
  12. width: 296px;
  13. height: 40px;
  14. margin-top: 20px;
  15. margin-left: 21px;
  16. color: #e6e6e6;
  17. }

3.5 添加退出事件

onclick="exitApp" 设置了div组件的click事件,当在标题栏上触发点击事件时,就会执行函数exitApp,该函数位于index.js文件中,代码如下:


   
  1. exitApp() {
  2. console.log( 'start exit');
  3. app.terminate();
  4. console.log( 'end exit');
  5. }

app.terminate()函数实现了程序退出功能;在使用该函数前,需要引入app模块,在index.js文件的最上方写如下代码:

import app from '@system.app'

在 Previewer 窗口中,可以预览界面效果

3.6 滑动组件

实现城市空气质量信息的多屏左右滑动,需要使用“swiper”组件。

在根节点中添加一个子节点swiper, 修改index.hml


   
  1. <swiper class= "swiper" index= "{{swiperPage}}" duration= "500" onchange= "swiperChange">
  2. </swiper>

添加样式,修改index.css


   
  1. .swiper {
  2. height: 385px;
  3. width: 960px;
  4. }

绑定swiperPage变量,swiperChange事件,修改index.js


   
  1. //引入router模块,用户页面跳转
  2. import router from '@system.router'
  3. import app from '@system.app'
  4. export default {
  5. //定义参数
  6. data: {
  7. //默认是第一页
  8. swiperPage: 0
  9. },
  10. onInit () {
  11. },
  12. exitApp(){
  13. console.log( 'start exit');
  14. app.terminate();
  15. console.log( 'end exit');
  16. },
  17. //swiper滑动回调事件,保存当前swiper的index值,每次滑动都会将index值保存在swiperPage变量中
  18. swiperChange (e) {
  19. this.swiperPage = e.index;
  20. }
  21. }

swiper中添加两个子组件stack(绝对布局),每个stack组件内分别添加text、image、progress等组件来显示对应的信息。


   
  1. <div class= "container">
  2. <div class= "header" onclick= "exitApp">
  3. <image class= "back" src= "common/ic_back.png"></image>
  4. <text class= "title">
  5. 空气质量
  6. </text>
  7. </div>
  8. <swiper class= "swiper" index= "{{swiperPage}}" duration= "500" onchange= "swiperChange">
  9. <!--第一屏-->
  10. <stack class= "swiper">
  11. <!--空气质量-->
  12. <text class= "airquality" style= "color:{{textColor1}};">{{airData[ 0].airQuality}}</text>
  13. <!--城市名称-->
  14. <text class= "location-text">{{airData[ 0].location}}</text>
  15. <!--进度条-->
  16. <progress
  17. class= "circleProgress"
  18. style= "color:{{textColor1}};background-Color:{{bgColor1}};"
  19. type= "arc"
  20. onclick= "openDetail"
  21. percent= "{{percent1}}">
  22. </progress>
  23. <!--云朵图片-->
  24. <image class= "image" src= "{{src1}}"></image>
  25. <!--AQI数值-->
  26. <text class= "pm25-value">{{ airData[ 0].detailData }}</text>
  27. <text class= "pm25-name">AQI</text>
  28. <!--空气指标详细信息-->
  29. <div class= "detail">
  30. <div class= "text-wrapper">
  31. <text class= "gas-name">
  32. CO
  33. </text>
  34. <text class= "gas-value">
  35. 100
  36. </text>
  37. </div>
  38. <div class= "text-wrapper">
  39. <text class= "gas-name">
  40. NO2
  41. </text>
  42. <text class= "gas-value">
  43. 90
  44. </text>
  45. </div>
  46. <div class= "text-wrapper">
  47. <text class= "gas-name">
  48. PM10
  49. </text>
  50. <text class= "gas-value">
  51. 120
  52. </text>
  53. </div>
  54. <div class= "text-wrapper">
  55. <text class= "gas-name">
  56. PM2 .5
  57. </text>
  58. <text class= "gas-value">
  59. 40
  60. </text>
  61. </div>
  62. <div class= "text-wrapper">
  63. <text class= "gas-name">
  64. SO2
  65. </text>
  66. <text class= "gas-value">
  67. 150
  68. </text>
  69. </div>
  70. <input class= "btn" type= "button" onclick= "openDetail" value= "历史记录"></input>
  71. </div>
  72. <!--更新时间和网站等信息-->
  73. <div class= "footer">
  74. <text class= "update-time">
  75. 更新时间: 10: 38
  76. </text>
  77. <text class= "info-source">
  78. 信息来源: tianqi.com
  79. </text>
  80. </div>
  81. </stack>
  82. <!--第二屏-->
  83. <stack class= "swiper">
  84. <text class= "airquality" style= "color: {{textColor2}};">{{airData[ 1].airQuality}}</text>
  85. <text class= "location-text">{{airData[ 1].location}}</text>
  86. <progress class= "circle-progress" style= "color: {{textColor2}};background-Color: {{bgColor2}};" type= "arc"
  87. percent= "{{percent2}}"></progress>
  88. <image class= "image" src= "{{src2}}"></image>
  89. <text class= "aqi-value">{{airData[ 1].detailData}}</text>
  90. <text class= "aqi">
  91. AQI
  92. </text>
  93. <div class= "detail">
  94. <div class= "text-wrapper">
  95. <text class= "gas-name">
  96. CO
  97. </text>
  98. <text class= "gas-value">
  99. 10
  100. </text>
  101. </div>
  102. <div class= "text-wrapper">
  103. <text class= "gas-name">
  104. NO2
  105. </text>
  106. <text class= "gas-value">
  107. 50
  108. </text>
  109. </div>
  110. <div class= "text-wrapper">
  111. <text class= "gas-name">
  112. PM10
  113. </text>
  114. <text class= "gas-value">
  115. 60
  116. </text>
  117. </div>
  118. <div class= "text-wrapper">
  119. <text class= "gas-name">
  120. PM2 .5
  121. </text>
  122. <text class= "gas-value">
  123. 40
  124. </text>
  125. </div>
  126. <div class= "text-wrapper">
  127. <text class= "gas-name">
  128. SO2
  129. </text>
  130. <text class= "gas-value">
  131. 150
  132. </text>
  133. </div>
  134. <input class= "btn" type= "button" onclick= "openDetail" value= "历史记录"></input>
  135. </div>
  136. <div class= "footer">
  137. <text class= "update-time">
  138. 更新时间: 10: 38
  139. </text>
  140. <text class= "info-source">
  141. 信息来源: tianqi.com
  142. </text>
  143. </div>
  144. </stack>
  145. </swiper>
  146. </div>

3.7 页面位置指示器

添加页面位置指示器:由于当前swiper不支持设置indicator,需要开发者自己来实现该效果。在根节点中添加一个子组件div,并设置相应样式;然后在该div中添加两个子组件div,设置两个divborder-radius,并在swiper滑动事件中动态改变对应div的背景色来实现该效果。

修改index.hml,在swiper组件后加入以下代码:


   
  1. <div class= "images">
  2. <div class= "circle-div" style= "background-color: {{iconcheckedColor}};"></div>
  3. <div class= "circle-div" style= "background-color: {{iconUncheckedColor}};margin-left: 36px;"></div>
  4. </div>

3.8 新增文字样式

修改 index.css


   
  1. .aqi-value {
  2. text-align: center;
  3. font-size: 65px;
  4. color: #f0ffff;
  5. width: 156px;
  6. height: 92px;
  7. top: 134px;
  8. left: 210px;
  9. }
  10. .aqi {
  11. text-align: center;
  12. color: #a2c4a2;
  13. width: 156px;
  14. height: 45px;
  15. top: 90px;
  16. left: 210px;
  17. }
  18. .airquality {
  19. top: 222px;
  20. text-align: center;
  21. width: 156px;
  22. height: 45px;
  23. left: 210px;
  24. }
  25. .image {
  26. top: 285px;
  27. left: 274px;
  28. width: 32px;
  29. height: 32px;
  30. }
  31. .location-text {
  32. text-align: center;
  33. color: #ffffff;
  34. width: 250px;
  35. height: 52px;
  36. font-size: 40px;
  37. left: 380px;
  38. top: 16px;
  39. }
  40. .container {
  41. flex-direction: column;
  42. height: 480px;
  43. width: 960px;
  44. }
  45. .circle-progress {
  46. center-x: 128px;
  47. center-y: 128px;
  48. radius: 128px;
  49. startAngle: 198;
  50. totalAngle: 320;
  51. strokeWidth: 24px;
  52. width: 256px;
  53. height: 256px;
  54. left: 160px;
  55. top: 58px;
  56. }
  57. .detail {
  58. width: 256px;
  59. height: 265px;
  60. left: 544px;
  61. top: 58px;
  62. flex-direction: column;
  63. }
  64. .text-wrapper {
  65. width: 256px;
  66. height: 35px;
  67. margin-top: 6px;
  68. }
  69. .gas-name {
  70. width: 128px;
  71. height: 35px;
  72. text-align: left;
  73. }
  74. .gas-value {
  75. width: 128px;
  76. height: 35px;
  77. text-align: right;
  78. }
  79. .btn {
  80. width: 180px;
  81. height: 50px;
  82. margin-top: 6px;
  83. margin-left: 38px;
  84. background-color: # 1a1a1a;
  85. color: # 1085CE;
  86. }
  87. .footer {
  88. top: 326px;
  89. width: 960px;
  90. height: 28px;
  91. }
  92. .header {
  93. width: 960px;
  94. height: 72px;
  95. }
  96. .back {
  97. width: 36px;
  98. height: 36px;
  99. margin-left: 39px;
  100. margin-top: 23px;
  101. }
  102. .title {
  103. width: 296px;
  104. height: 40px;
  105. margin-top: 20px;
  106. margin-left: 21px;
  107. color: #e6e6e6;
  108. }
  109. .swiper {
  110. height: 385px;
  111. width: 960px;
  112. }
  113. .images {
  114. width: 60px;
  115. height: 15px;
  116. margin-left: 450px;
  117. }
  118. .update-time {
  119. width: 480px;
  120. height: 28px;
  121. font-size: 20px;
  122. color: #A9A9A9;
  123. text-align: right;
  124. }
  125. .info-source {
  126. width: 450px;
  127. height: 28px;
  128. font-size: 20px;
  129. color: #A9A9A9;
  130. text-align: left;
  131. margin-left: 24px;
  132. }
  133. .circle-div {
  134. width: 12px;
  135. height: 12px;
  136. border-radius: 6px;
  137. }

3.9 实现页面逻辑

修改index.js,绑定页面数据data。初始化时,根据不同的数值显示不同的字体和图片onInit。实现页面跳转openDetail,将当前页面索引传递给detail页面。滑动触发后swiperChange改变指示位置。


   
  1. //引入router模块,用户页面跳转
  2. import router from '@system.router'
  3. import app from '@system.app'
  4. export default {
  5. //定义参数
  6. data: {
  7. //页面绑定数据
  8. textColor1: "#00ff00",
  9. textColor2: "#00ff00",
  10. bgColor1: "#669966",
  11. bgColor2: "#669966",
  12. //默认是第一页
  13. swiperPage: 0,
  14. percent1: 10,
  15. percent2: 90,
  16. iconUncheckedColor: '#262626',
  17. iconcheckedColor: '#ffffff',
  18. iconcheckedBR: '6px',
  19. src1: "common/cloud_green.png",
  20. src2: "common/cloud_green.png",
  21. airData: [
  22. {
  23. location: "HangZhou",
  24. airQuality: "Good",
  25. detailData: 10
  26. },
  27. {
  28. location: "ShangHai",
  29. airQuality: "Unhealth",
  30. detailData: 90
  31. }
  32. ]
  33. },
  34. onInit () {
  35. //根据数值的不同,设置不同的字体、背景颜色和图片
  36. if(this.airData[ 0].detailData > 100){
  37. this.src1 = 'common/cloud_red.png';
  38. this.textColor1 = '#ff0000';
  39. this.bgColor1 = '#9d7462';
  40. } else if( 50 < this.airData[ 0].detailData && this.airData[ 0].detailData <= 100){
  41. this.src1 = 'common/cloud_yellow.png';
  42. this.textColor1 = '#ecf19a';
  43. this.bgColor1 = '#9d9d62';
  44. }
  45. if(this.airData[ 1].detailData > 100){
  46. this.src2 = 'common/cloud_red.png';
  47. this.textColor2 = '#ff0000';
  48. this.bgColor2 = '#9d7462';
  49. } else if( 50 < this.airData[ 1].detailData && this.airData[ 1].detailData <= 100){
  50. this.src2 = 'common/cloud_yellow.png';
  51. this.textColor2 = '#ecf19a';
  52. this.bgColor2 = '#9d9d62';
  53. }
  54. if(this.selectedCityIndex){
  55. this.swiperPage = this.selectedCityIndex;
  56. if(this.swiperPage == 0){
  57. this.iconcheckedColor = '#ffffff';
  58. this.iconUncheckedColor = '#262626';
  59. } else{
  60. this.iconcheckedColor = '#262626';
  61. this.iconUncheckedColor = '#ffffff';
  62. }
  63. }
  64. },
  65. //跳转到详情页面
  66. openDetail () {
  67. router.replace({
  68. uri: 'pages/detail/detail',
  69. params: {selectedCityIndex:this.swiperPage}
  70. });
  71. },
  72. //退出应用
  73. exitApp(){
  74. console.log( 'start exit');
  75. app.terminate();
  76. console.log( 'end exit');
  77. },
  78. //swiper滑动回调事件,保存当前swiper的index值,每次滑动都会将index值保存在swiperPage变量中
  79. swiperChange (e) {
  80. this.swiperPage = e.index;
  81. if(e.index == 0){
  82. this.iconcheckedColor = '#ffffff';
  83. this.iconUncheckedColor = '#262626';
  84. } else{
  85. this.iconcheckedColor = '#262626';
  86. this.iconUncheckedColor = '#ffffff';
  87. }
  88. }
  89. }

预览效果如下:

4. 开发详情页

详情页以图表的形式展示一周内空气质量指标值。本页面由两部分组成:标题栏和图表栏;在图表栏,考虑显示效果,我们使用多个div替代chart组件来实现图表功能。

4.1 添加标题栏

修改 entry/src/main/js/default/pages/detail/detail.hml


   
  1. <div class= "container">
  2. <div class= "header" onclick= "backMain">
  3. <image class= "back" src= "common/ic_back.png"></image>
  4. <text class= "title">
  5. 历史记录
  6. </text>
  7. </div>
  8. <list class= "chart-list">
  9. </list>
  10. </div>

4.2 添加图表栏

添加城市位置到list-item-title,图表到list-item-chart


   
  1. <list class= "chart-list">
  2. <list-item class= "list-item-title">
  3. <text class= "location">{{location}}</text>
  4. </list-item>
  5. <list-item class= "list-item-chart">
  6. </list-item>
  7. </list>

4.3 添加图表


   
  1. <div class= "chart-wrapper" style= "margin-left: 128px;">
  2. <text class= "gas-name">CO</text>
  3. <div class= "chart">
  4. <div class= "chart-item" style= "height: 78px;background-color: #00ff00;"></div>
  5. <div class= "chart-item" style= "height: 52px;background-color: #00ff00;"></div>
  6. <div class= "chart-item" style= "height: 155px;background-color: #ff0000;"></div>
  7. <div class= "chart-item" style= "height: 134px;background-color: #ff0000;"></div>
  8. <div class= "chart-item" style= "height: 98px;background-color: #FF7500;"></div>
  9. <div class= "chart-item" style= "height: 88px;background-color: #FF7500;"></div>
  10. <div class= "chart-item" style= "height: 144px;background-color: #ff0000;"></div>
  11. </div>
  12. <div class= "white-line"></div>
  13. <div class= "week"></div>
  14. </div>

4.4 添加样式


   
  1. .location {
  2. text-align: center;
  3. color: #ffffff;
  4. width: 960px;
  5. height: 52px;
  6. font-size: 40px;
  7. }
  8. .container {
  9. height: 480px;
  10. width: 960px;
  11. flex-direction: column;
  12. }
  13. .header {
  14. width: 960px;
  15. height: 72px;
  16. }
  17. .back {
  18. width: 36px;
  19. height: 36px;
  20. margin-left: 39px;
  21. margin-top: 23px;
  22. }
  23. .title {
  24. width: 296px;
  25. height: 40px;
  26. margin-top: 20px;
  27. margin-left: 21px;
  28. color: #e6e6e6;
  29. }
  30. .chart-list {
  31. width: 960px;
  32. height: 408px;
  33. }
  34. .list-item-title {
  35. width: 960px;
  36. height: 52px;
  37. }
  38. .list-item-chart {
  39. width: 960px;
  40. height: 280px;
  41. }
  42. .chart-wrapper {
  43. width: 308px;
  44. height: 256px;
  45. flex-direction: column;
  46. }
  47. .gas-name {
  48. width: 308px;
  49. height: 35px;
  50. text-align: left;
  51. }
  52. .chart {
  53. width: 308px;
  54. height: 155px;
  55. margin-top: 10px;
  56. justify-content: flex-start;
  57. align-items: flex-end;
  58. }
  59. .chart-item {
  60. width: 24px;
  61. margin-left: 18px;
  62. border-radius: 3px;
  63. }
  64. .white-line {
  65. width: 308px;
  66. height: 2px;
  67. background-color: #ffffff;
  68. margin-top: 22px;
  69. }
  70. .week {
  71. width: 308px;
  72. height: 17px;
  73. margin-top: 6px;
  74. border-color: #ffffff;
  75. border-radius: 2px;
  76. margin-top: 6px;
  77. }
  78. .day {
  79. width: 26px;
  80. height: 17px;
  81. font-size: 10px;
  82. margin-left: 16px;
  83. text-align: center;
  84. }

4.5 实现页面跳转

其中onclick="backMain"为返回主页事件,根据传递的页面索引,显示不同的位置数据,detail.js中的代码实现如下:


   
  1. import router from '@system.router'
  2. export default {
  3. data: {
  4. location: ''
  5. },
  6. onInit() {
  7. if (this.selectedCityIndex === 0) {
  8. this.location = '杭州';
  9. } else {
  10. this.location = '上海';
  11. }
  12. },
  13. backMain() {
  14. router.replace({
  15. uri: 'pages/index/index',
  16. params: {
  17. selectedCityIndex: this.selectedCityIndex
  18. }
  19. });
  20. }
  21. }

5. 模拟器调试

菜单Tools->HVD Manager,可以打开云端的模拟器

注册华为开发者账号,授权登录后

就能看到模拟器列表了,相比beta版只有PhoneTVWearable三种,增加了不少的设备。

可惜还没有可用于smartVision设备的模拟器,现阶段我们还只能烧录到设备中调试,总体上"富鸿蒙"的进度比较快,期待一波更新。

6. 编译打包

若开发手机端的App,则需要申请证书,对应用程序进行签名。这样才能发布到应用市场,才被允许安装到真机上运行。

IPCamera应用「暂时不支持签名模式」,所以需要将应用发布为未签名的应用安装包。

菜单Build->Buildo APP(s)/Hap(s)->Build Release Hap(s),生成Hap文件。

输出文件为 build/outputs/hap/release/smartVision/entry-release-smartVision-unsigned.hap,改名为MyUiApp.hap便于安装。

7. 通过sdcard安装

7.1 复制安装包和工具

将IDE编译的未签名应用安装包和安装工具(Z:\openharmony\out\my_hi3516dv300\dev_tools)放在sdcard中,将sdcard插入开发板卡槽。

7.2 禁用签名校验

应用安装默认要校验签名,需要执行以下命令,关闭签名校验。

./sdcard/dev_tools/bin/bm set -s disable

7.3 安装应用

./sdcard/dev_tools/bin/bm install -p /sdcard/MyUiApp.hap

8. 通过NFS安装

每次插拔sdcard还是蛮不方便的,这里我们安装一个NFS服务器,让鸿蒙系统能直接访问Win10的目录,后续安装调试就会方便很多。

8.1 安装NFS服务器

我们先安装一个haneWIN NFS服务器, 双击文末网盘里的nfs1169.exe,一路下一步即可。

8.2 配置目录参数

编辑输出表文件,定义传输目录


   
  1. # exports example
  2. # C:\ftp - range 192.168 .1 .1 192.168 .1 .10
  3. # c:\public -public -readonly
  4. # c:\tools -readonly 192.168 .1 .4
  5. D:\PycharmProjects\aiLearn\Harmony\tftp -public -name:nfs

8.3 重启服务

右键管理员权限,重启所有服务,让配置生效。

8.4 设置防火墙

防火墙设置111、1058、2049这些端口的TCPUDP,入站规则放行。

8.5 鸿蒙上挂载目录

主电脑的ip地址为192.168.1.57NFS服务的别名为nfs,对应的目录为D:\PycharmProjects\aiLearn\Harmony\tftp


   
  1. mkdir nfs
  2. mount 192.168 .1 .57:/nfs /nfs nfs

挂载到鸿蒙的刚新建的 /nfs目录下,我们可以复制安装包和安装工具

8.6 安装应用


   
  1. cd nfs
  2. ./dev_tools/bin/bm install -p MyUiApp.hap

前面做了这么多的铺垫,后续开发只要复制hap安装包,直接一条命令安装即可,非常方便。

运行程序

安装完成后,点击桌面上的MyUiApp就能看见界面效果了。

Js UI框架对开发者还是比较友好的,有小程序或快应用的开发经验,上手应该都比较顺滑。

不过HarmonyOS Device的支持库精简的非常严重,例如网络访问的@system.request@system.fetch都不可用,这些功能在“富鸿蒙”的设备上开发就会比较方便。

资料下载

本期相关文件资料,可在公众号“深度觉醒”,后台回复:“ohos06”,获取下载链接。

下一篇

本期主要介绍了一下JS框架下的界面开发,

下一篇我们将尝试熟悉更多的设备能力,

并打通从框架用户态到驱动内核态之间的联系,

敬请期待...

往期推荐


转载:https://blog.csdn.net/weixin_47479625/article/details/112343440
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场