用鴻蒙開(kāi)發(fā)AI應(yīng)用(六)UI篇
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
環(huán)境準(zhǔn)備
1. 安裝DevEco Studio
解壓相應(yīng)的壓縮包(文末附下載鏈接),這里以win10為例,雙擊`deveco-studio-2.0.12.201.exe`
同意用戶(hù)協(xié)議后,就能正常啟動(dòng)了。
同樣在`SDK Tools`中,選中新版的`Previewer`。
點(diǎn)擊Apply更新
新建項(xiàng)目
點(diǎn)擊菜單`File->New Project...`,選擇智慧屏`Smart Vision`,創(chuàng)建一個(gè)空模板應(yīng)用。
- https://services.gradle.org/distributions/
目錄結(jié)構(gòu)
我們先分析一下目錄結(jié)構(gòu),做`Android`開(kāi)發(fā)的會(huì)倍感親切。
1. APP
`HarmonyOS`的應(yīng)用軟件包以`APP Pack(Application Package)`形式發(fā)布,它是由一個(gè)或多個(gè)`HAP(HarmonyOS Ability Package)`以及描述每個(gè)`HAP`屬性的`pack.info`組成。`HAP`是`Ability`的部署包,`HarmonyOS`應(yīng)用代碼圍繞`Ability`組件展開(kāi)。
一個(gè)`HAP`是由代碼、資源、第三方庫(kù)及應(yīng)用配置文件組成的模塊包,可分為`entry`和`feature`兩種模塊類(lèi)型。
- **entry**:應(yīng)用的主模塊。一個(gè)APP中,對(duì)于同一設(shè)備類(lèi)型必須有且只有一個(gè)`entry`類(lèi)型的`HAP`,可獨(dú)立安裝運(yùn)行。
- **feature**:應(yīng)用的動(dòng)態(tài)特性模塊。一個(gè)`APP`可以包含一個(gè)或多個(gè)`feature`類(lèi)型的`HAP`,也可以不含。只有包含`Ability`的`HAP`才能夠獨(dú)立運(yùn)行。
2. Ability
Ability是應(yīng)用所具備的能力的抽象,一個(gè)應(yīng)用可以包含一個(gè)或多個(gè)`Ability`。`Ability`分為兩種類(lèi)型:`FA(Feature Ability)`和`PA(Particle Ability)`。`FA/PA`是應(yīng)用的基本組成單元,能夠?qū)崿F(xiàn)特定的業(yè)務(wù)功能。`FA`有`UI`界面,而`PA`無(wú)`UI`界面。
3. 資源文件
應(yīng)用的資源文件(字符串、圖片、音頻等)統(tǒng)一存放于`resources`目錄下,便于開(kāi)發(fā)者使用和維護(hù)。`resources`目錄包括兩大類(lèi)目錄,一類(lèi)為`base`目錄與限定詞目錄,另一類(lèi)為`rawfile`目錄。
4. 配置文件
配置文件` (config.json) `是應(yīng)用的`Ability`信息,用于聲明應(yīng)用的`Ability`,以及應(yīng)用所需權(quán)限等信息。
- 應(yīng)用的全局配置信息,包含應(yīng)用的包名、生產(chǎn)廠(chǎng)商、版本號(hào)等基本信息。
- 應(yīng)用在具體設(shè)備上的配置信息,包含應(yīng)用的備份恢復(fù)、網(wǎng)絡(luò)安全等能力。
- `HAP`包的配置信息,包含每個(gè)`Ability`必須定義的基本屬性(如包名、類(lèi)名、類(lèi)型以及`Ability`提供的能力),以及應(yīng)用訪(fǎng)問(wèn)系統(tǒng)或其他應(yīng)用受保護(hù)部分所需的權(quán)限等。
5. JS UI 框架
`JS UI`框架是一種跨設(shè)備的高性能`UI`開(kāi)發(fā)框架,支持聲明式編程和跨設(shè)備多態(tài)`UI`。
- 聲明式編程
`JS UI`框架采用類(lèi)`HTML`和`CSS`聲明式編程語(yǔ)言作為頁(yè)面布局和頁(yè)面樣式的開(kāi)發(fā)語(yǔ)言,頁(yè)面業(yè)務(wù)邏輯則支持`ECMAScript`規(guī)范的`JavaScript`語(yǔ)言。`JS UI`框架提供
的聲明式編程,可以讓開(kāi)發(fā)者避免編寫(xiě)`UI`狀態(tài)切換的代碼,視圖配置信息更加直觀。
- 跨設(shè)備
開(kāi)發(fā)框架架構(gòu)上支持`UI`跨設(shè)備顯示能力,運(yùn)行時(shí)自動(dòng)映射到不同設(shè)備類(lèi)型,開(kāi)發(fā)者無(wú)感知,降低開(kāi)發(fā)者多設(shè)備適配成本。
- 高性能
開(kāi)發(fā)框架包含了許多核心的控件,如列表、圖片和各類(lèi)容器組件等,針對(duì)聲明式語(yǔ)法進(jìn)行了渲染流程的優(yōu)化。
`JS UI`框架包括應(yīng)用層`(Application)`、前端框架層`(Framework)`、引擎層`(Engine)`和平臺(tái)適配層`(Porting Layer)`。
# 空氣質(zhì)量監(jiān)測(cè) UI
## 1. 創(chuàng)建首頁(yè)面
空氣質(zhì)量監(jiān)測(cè)App包含兩個(gè)界面`(Page)`,工程創(chuàng)建完成后會(huì)生成一個(gè)名為`index`的`Page`,可以作為首頁(yè)。
## 2. 創(chuàng)建詳情頁(yè)
在`pages`目錄按右鍵,彈出的菜單中選擇`New->JS Page`。
詳情頁(yè)創(chuàng)建完成后應(yīng)用工程目錄如下圖所示,每個(gè)`Page`包括三個(gè)文件:布局文件`hml`、樣式文件`css`、業(yè)務(wù)邏輯代碼`js`。
## 3. 開(kāi)發(fā)首頁(yè)
應(yīng)用首頁(yè)主要展示城市的空氣質(zhì)量概況。首頁(yè)總共有兩屏(可以根據(jù)需求設(shè)置多屏),每屏顯示一個(gè)城市的空氣質(zhì)量信息:主要包括AQI指數(shù)、城市名稱(chēng)、污染物指數(shù)、更新時(shí)間和信息來(lái)源等數(shù)據(jù)。
### 3.1 創(chuàng)建根節(jié)點(diǎn)
修改`entry/src/main/js/default/pages/index/index.hml`,加入根節(jié)點(diǎn)`div`:
- <div class="container">
- </div>
### 3.2 創(chuàng)建樣式
修改`entry/src/main/js/default/pages/index/index.css`
- container {
- flex-direction: column;
- height: 480px;
- width: 960px;
- }
標(biāo)題欄包括一個(gè)退出按鈕和一個(gè)標(biāo)題,兩個(gè)控件是橫向排列
- <div class="container">
- <div class="header" onclick="exitApp">
- <image class="back" src="common/ic_back.png"></image>
- <text class="title">
- 空氣質(zhì)量
- </text>
- </div>
- </div>
注意,這里要先導(dǎo)入common/ic_back.png圖標(biāo)資源。
3.4 添加標(biāo)題欄樣式
修改entry/src/main/js/default/pages/detail/detail.css,添加以下代碼,設(shè)置組件的高度、邊距、顏色等屬性。
- .header {
- width: 960px;
- height: 72px;
- }
- .back {
- width: 36px;
- height: 36px;
- margin-left: 39px;
- margin-top: 23px;
- }
- .title {
- width: 296px;
- height: 40px;
- margin-top: 20px;
- margin-left: 21px;
- color: #e6e6e6;
- }
### 3.5 添加退出事件
`onclick="exitApp"` 設(shè)置了`div`組件的`click`事件,當(dāng)在標(biāo)題欄上觸發(fā)點(diǎn)擊事件時(shí),就會(huì)執(zhí)行函數(shù)`exitApp`,該函數(shù)位于`index.js`文件中,代碼如下:
- exitApp() {
- console.log('start exit');
- app.terminate();
- console.log('end exit');
- }
`app.terminate()`函數(shù)實(shí)現(xiàn)了程序退出功能;在使用該函數(shù)前,需要引入`app`模塊,在`index.js`文件的最上方寫(xiě)如下代碼:
- import app from '@system.app'
在 Previewer 窗口中,可以預(yù)覽界面效果
### 3.6 滑動(dòng)組件
實(shí)現(xiàn)城市空氣質(zhì)量信息的多屏左右滑動(dòng),需要使用`“swiper”`組件。
在根節(jié)點(diǎn)中添加一個(gè)子節(jié)點(diǎn)`swiper`, 修改`index.hml`
- <swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
- </swiper>
- .swiper {
- height: 385px;
- width: 960px;
- }
- //引入router模塊,用戶(hù)頁(yè)面跳轉(zhuǎn)
- import router from'@system.router'
- import app from '@system.app'
- export default {
- //定義參數(shù)
- data: {
- //默認(rèn)是第一頁(yè)
- swiperPage: 0
- },
- onInit () {
- },
- exitApp(){
- console.log('start exit');
- app.terminate();
- console.log('end exit');
- },
- //swiper滑動(dòng)回調(diào)事件,保存當(dāng)前swiper的index值,每次滑動(dòng)都會(huì)將index值保存在swiperPage變量中
- swiperChange (e) {
- this.swiperPage = e.index;
- }
- }
在`swiper`中添加兩個(gè)子組件`stack`(絕對(duì)布局),每個(gè)`stack`組件內(nèi)分別添加`text、image、progress`等組件來(lái)顯示對(duì)應(yīng)的信息。
- <div class="container">
- <div class="header" onclick="exitApp">
- <image class="back" src="common/ic_back.png"></image>
- <text class="title">
- 空氣質(zhì)量
- </text>
- </div>
- <swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
- <!--第一屏-->
- <stack class="swiper">
- <!--空氣質(zhì)量-->
- <text class="airquality" style="color:{{textColor1}};">{{airData[0].airQuality}}</text>
- <!--城市名稱(chēng)-->
- <text class="location-text">{{airData[0].location}}</text>
- <!--進(jìn)度條-->
- <progress
- class="circleProgress"
- style="color:{{textColor1}};background-Color:{{bgColor1}};"
- type="arc"
- onclick="openDetail"
- percent="{{percent1}}">
- </progress>
- <!--云朵圖片-->
- <image class="image" src="{{src1}}"></image>
- <!--AQI數(shù)值-->
- <text class="pm25-value">{{ airData[0].detailData }}</text>
- <text class="pm25-name">AQI</text>
- <!--空氣指標(biāo)詳細(xì)信息-->
- <div class="detail">
- <div class="text-wrapper">
- <text class="gas-name">
- CO
- </text>
- <text class="gas-value">
- 100
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- NO2
- </text>
- <text class="gas-value">
- 90
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- PM10
- </text>
- <text class="gas-value">
- 120
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- PM2.5
- </text>
- <text class="gas-value">
- 40
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- SO2
- </text>
- <text class="gas-value">
- 150
- </text>
- </div>
- <input class="btn" type="button" onclick="openDetail" value="歷史記錄"></input>
- </div>
- <!--更新時(shí)間和網(wǎng)站等信息-->
- <div class="footer">
- <text class="update-time">
- 更新時(shí)間: 10:38
- </text>
- <text class="info-source">
- 信息來(lái)源: tianqi.com
- </text>
- </div>
- </stack>
- <!--第二屏-->
- <stack class="swiper">
- <text class="airquality" style="color: {{textColor2}};">{{airData[1].airQuality}}</text>
- <text class="location-text">{{airData[1].location}}</text>
- <progress class="circle-progress" style="color: {{textColor2}};background-Color: {{bgColor2}};" type="arc"
- percent="{{percent2}}"></progress>
- <image class="image" src="{{src2}}"></image>
- <text class="aqi-value">{{airData[1].detailData}}</text>
- <text class="aqi">
- AQI
- </text>
- <div class="detail">
- <div class="text-wrapper">
- <text class="gas-name">
- CO
- </text>
- <text class="gas-value">
- 10
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- NO2
- </text>
- <text class="gas-value">
- 50
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- PM10
- </text>
- <text class="gas-value">
- 60
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- PM2.5
- </text>
- <text class="gas-value">
- 40
- </text>
- </div>
- <div class="text-wrapper">
- <text class="gas-name">
- SO2
- </text>
- <text class="gas-value">
- 150
- </text>
- </div>
- <input class="btn" type="button" onclick="openDetail" value="歷史記錄"></input>
- </div>
- <div class="footer">
- <text class="update-time">
- 更新時(shí)間: 10:38
- </text>
- <text class="info-source">
- 信息來(lái)源: tianqi.com
- </text>
- </div>
- </stack>
- </swiper>
- </div>
### 3.7 頁(yè)面位置指示器
添加頁(yè)面位置指示器:由于當(dāng)前`swiper`不支持設(shè)置`indicator`,需要開(kāi)發(fā)者自己來(lái)實(shí)現(xiàn)該效果。在根節(jié)點(diǎn)中添加一個(gè)子組件`div`,并設(shè)置相應(yīng)樣式;然后在該`div`中添
加兩個(gè)子組件`div`,設(shè)置兩個(gè)`div`的`border-radius`,并在`swiper`滑動(dòng)事件中動(dòng)態(tài)改變對(duì)應(yīng)`div`的背景色來(lái)實(shí)現(xiàn)該效果。
修改`index.hml`,在`swiper`組件后加入以下代碼:
- <div class="images">
- <div class="circle-div" style="background-color: {{iconcheckedColor}};"></div>
- <div class="circle-div" style="background-color: {{iconUncheckedColor}};margin-left: 36px;"></div>
- </div>
### 3.8 新增文字樣式
修改 `index.css`
- aqi-value {
- text-align: center;
- font-size: 65px;
- color: #f0ffff;
- width: 156px;
- height: 92px;
- top: 134px;
- left: 210px;
- }
- .aqi {
- text-align: center;
- color: #a2c4a2;
- width: 156px;
- height: 45px;
- top: 90px;
- left: 210px;
- }
- .airquality {
- top: 222px;
- text-align: center;
- width: 156px;
- height: 45px;
- left: 210px;
- }
- .image {
- top: 285px;
- left: 274px;
- width: 32px;
- height: 32px;
- }
- .location-text {
- text-align: center;
- color: #ffffff;
- width: 250px;
- height: 52px;
- font-size: 40px;
- left: 380px;
- top: 16px;
- }
- .container {
- flex-direction: column;
- height: 480px;
- width: 960px;
- }
- .circle-progress {
- center-x: 128px;
- center-y: 128px;
- radius: 128px;
- startAngle: 198;
- totalAngle: 320;
- strokeWidth: 24px;
- width: 256px;
- height: 256px;
- left: 160px;
- top: 58px;
- }
- .detail {
- width: 256px;
- height: 265px;
- left: 544px;
- top: 58px;
- flex-direction: column;
- }
- .text-wrapper {
- width: 256px;
- height: 35px;
- margin-top: 6px;
- }
- .gas-name {
- width: 128px;
- height: 35px;
- text-align: left;
- }
- .gas-value {
- width: 128px;
- height: 35px;
- text-align: right;
- }
- .btn {
- width: 180px;
- height: 50px;
- margin-top: 6px;
- margin-left: 38px;
- background-color: #1a1a1a;
- color: #1085CE;
- }
- .footer {
- top: 326px;
- width: 960px;
- height: 28px;
- }
- .header {
- width: 960px;
- height: 72px;
- }
- .back {
- width: 36px;
- height: 36px;
- margin-left: 39px;
- margin-top: 23px;
- }
- .title {
- width: 296px;
- height: 40px;
- margin-top: 20px;
- margin-left: 21px;
- color: #e6e6e6;
- }
- .swiper {
- height: 385px;
- width: 960px;
- }
- .images {
- width: 60px;
- height: 15px;
- margin-left: 450px;
- }
- .update-time {
- width: 480px;
- height: 28px;
- font-size: 20px;
- color: #A9A9A9;
- text-align: right;
- }
- .info-source {
- width: 450px;
- height: 28px;
- font-size: 20px;
- color: #A9A9A9;
- text-align: left;
- margin-left: 24px;
- }
- .circle-div {
- width: 12px;
- height: 12px;
- border-radius: 6px;
- }
修改`index.js`,綁定頁(yè)面數(shù)據(jù)`data`。初始化時(shí),根據(jù)不同的數(shù)值顯示不同的字體和圖片`onInit`。實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)`openDetail`,將當(dāng)前頁(yè)面索引傳遞給`detail`頁(yè)面。滑動(dòng)觸發(fā)后`swiperChange`改變指示位置。
- //引入router模塊,用戶(hù)頁(yè)面跳轉(zhuǎn)
- import router from'@system.router'
- import app from '@system.app'
- export default {
- //定義參數(shù)
- data: {
- //頁(yè)面綁定數(shù)據(jù)
- textColor1: "#00ff00",
- textColor2: "#00ff00",
- bgColor1: "#669966",
- bgColor2: "#669966",
- //默認(rèn)是第一頁(yè)
- swiperPage: 0,
- percent1: 10,
- percent2: 90,
- iconUncheckedColor: '#262626',
- iconcheckedColor: '#ffffff',
- iconcheckedBR: '6px',
- src1: "common/cloud_green.png",
- src2: "common/cloud_green.png",
- airData: [
- {
- location: "HangZhou",
- airQuality: "Good",
- detailData: 10
- },
- {
- location: "ShangHai",
- airQuality: "Unhealth",
- detailData: 90
- }
- ]
- },
- onInit () {
- //根據(jù)數(shù)值的不同,設(shè)置不同的字體、背景顏色和圖片
- if(this.airData[0].detailData > 100){
- this.src1 = 'common/cloud_red.png';
- this.textColor1 = '#ff0000';
- this.bgColor1 = '#9d7462';
- } else if(50 < this.airData[0].detailData && this.airData[0].detailData <= 100){
- this.src1 = 'common/cloud_yellow.png';
- this.textColor1 = '#ecf19a';
- this.bgColor1 = '#9d9d62';
- }
- if(this.airData[1].detailData > 100){
- this.src2 = 'common/cloud_red.png';
- this.textColor2 = '#ff0000';
- this.bgColor2 = '#9d7462';
- } else if(50 < this.airData[1].detailData && this.airData[1].detailData <= 100){
- this.src2 = 'common/cloud_yellow.png';
- this.textColor2 = '#ecf19a';
- this.bgColor2 = '#9d9d62';
- }
- if(this.selectedCityIndex){
- this.swiperPage = this.selectedCityIndex;
- if(this.swiperPage == 0){
- this.iconcheckedColor = '#ffffff';
- this.iconUncheckedColor = '#262626';
- }else{
- this.iconcheckedColor = '#262626';
- this.iconUncheckedColor = '#ffffff';
- }
- }
- },
- //跳轉(zhuǎn)到詳情頁(yè)面
- openDetail () {
- router.replace({
- uri: 'pages/detail/detail',
- params: {selectedCityIndex:this.swiperPage}
- });
- },
- //退出應(yīng)用
- exitApp(){
- console.log('start exit');
- app.terminate();
- console.log('end exit');
- },
- //swiper滑動(dòng)回調(diào)事件,保存當(dāng)前swiper的index值,每次滑動(dòng)都會(huì)將index值保存在swiperPage變量中
- swiperChange (e) {
- this.swiperPage = e.index;
- if(e.index == 0){
- this.iconcheckedColor = '#ffffff';
- this.iconUncheckedColor = '#262626';
- }else{
- this.iconcheckedColor = '#262626';
- this.iconUncheckedColor = '#ffffff';
- }
- }
- }
## 4. 開(kāi)發(fā)詳情頁(yè)
詳情頁(yè)以圖表的形式展示一周內(nèi)空氣質(zhì)量指標(biāo)值。本頁(yè)面由兩部分組成:標(biāo)題欄和圖表欄;在圖表欄,考慮顯示效果,我們使用多個(gè)`div`替代`chart`組件來(lái)實(shí)現(xiàn)圖表功能。
### 4.1 添加標(biāo)題欄
修改 `entry/src/main/js/default/pages/detail/detail.hml`
- <div class="container">
- <div class="header" onclick="backMain">
- <image class="back" src="common/ic_back.png"></image>
- <text class="title">
- 歷史記錄
- </text>
- </div>
- <list class="chart-list">
- </list>
- </div>
### 4.2 添加圖表欄
添加城市位置到`list-item-title`,圖表到`list-item-chart`
- <list class="chart-list">
- <list-item class="list-item-title">
- <text class="location">{{location}}</text>
- </list-item>
- <list-item class="list-item-chart">
- </list-item>
- </list>
- <div class="chart-wrapper" style="margin-left: 128px;">
- <text class="gas-name">CO</text>
- <div class="chart">
- <div class="chart-item" style="height: 78px;background-color: #00ff00;"></div>
- <div class="chart-item" style="height: 52px;background-color: #00ff00;"></div>
- <div class="chart-item" style="height: 155px;background-color: #ff0000;"></div>
- <div class="chart-item" style="height: 134px;background-color: #ff0000;"></div>
- <div class="chart-item" style="height: 98px;background-color: #FF7500;"></div>
- <div class="chart-item" style="height: 88px;background-color: #FF7500;"></div>
- <div class="chart-item" style="height: 144px;background-color: #ff0000;"></div>
- </div>
- <div class="white-line"></div>
- <div class="week"></div>
- </div>
- .location {
- text-align: center;
- color: #ffffff;
- width: 960px;
- height: 52px;
- font-size: 40px;
- }
- .container {
- height: 480px;
- width: 960px;
- flex-direction: column;
- }
- .header {
- width: 960px;
- height: 72px;
- }
- .back {
- width: 36px;
- height: 36px;
- margin-left: 39px;
- margin-top: 23px;
- }
- .title {
- width: 296px;
- height: 40px;
- margin-top: 20px;
- margin-left: 21px;
- color: #e6e6e6;
- }
- .chart-list {
- width: 960px;
- height: 408px;
- }
- .list-item-title {
- width: 960px;
- height: 52px;
- }
- .list-item-chart {
- width: 960px;
- height: 280px;
- }
- .chart-wrapper {
- width: 308px;
- height: 256px;
- flex-direction: column;
- }
- .gas-name {
- width: 308px;
- height: 35px;
- text-align: left;
- }
- .chart {
- width: 308px;
- height: 155px;
- margin-top: 10px;
- justify-content: flex-start;
- align-items: flex-end;
- }
- .chart-item {
- width: 24px;
- margin-left: 18px;
- border-radius: 3px;
- }
- .white-line {
- width: 308px;
- height: 2px;
- background-color: #ffffff;
- margin-top: 22px;
- }
- .week {
- width: 308px;
- height: 17px;
- margin-top: 6px;
- border-color: #ffffff;
- border-radius: 2px;
- margin-top: 6px;
- }
- .day {
- width: 26px;
- height: 17px;
- font-size: 10px;
- margin-left: 16px;
- text-align: center;
- }
其中`onclick="backMain"`為返回主頁(yè)事件,根據(jù)傳遞的頁(yè)面索引,顯示不同的位置數(shù)據(jù),`detail.js`中的代碼實(shí)現(xiàn)如下:
- import router from '@system.router'
- export default {
- data: {
- location: ''
- },
- onInit() {
- if (this.selectedCityIndex === 0) {
- this.location = '杭州';
- } else {
- this.location = '上海';
- }
- },
- backMain() {
- router.replace({
- uri: 'pages/index/index',
- params: {
- selectedCityIndex: this.selectedCityIndex
- }
- });
- }
- }
5. 模擬器調(diào)試
菜單Tools->HVD Manager,可以打開(kāi)云端的模擬器
可惜還沒(méi)有可用于`smartVision`設(shè)備的模擬器,現(xiàn)階段我們還只能燒錄到設(shè)備中調(diào)試,總體上"富鴻蒙"的進(jìn)度比較快,期待一波更新。
## 6. 編譯打包
若開(kāi)發(fā)手機(jī)端的`App`,則需要申請(qǐng)證書(shū),對(duì)應(yīng)用程序進(jìn)行簽名。這樣才能發(fā)布到應(yīng)用市場(chǎng),才被允許安裝到真機(jī)上運(yùn)行。
`IPCamera`應(yīng)用**暫時(shí)不支持簽名模式**,所以需要將應(yīng)用發(fā)布為未簽名的應(yīng)用安裝包。
菜單`Build->Buildo APP(s)/Hap(s)->Build Release Hap(s)`,生成`Hap`文件。
輸出文件為 `build/outputs/hap/release/smartVision/entry-release-smartVision-unsigned.hap`,改名為`MyUiApp.hap`便于安裝。
## 7. 通過(guò)sdcard安裝
### 7.1 復(fù)制安裝包和工具
將IDE編譯的未簽名應(yīng)用安裝包和安裝工具(`Z:\openharmony\out\my_hi3516dv300\dev_tools`)放在`sdcard`中,將`sdcard`插入開(kāi)發(fā)板卡槽。
### 7.2 禁用簽名校驗(yàn)
應(yīng)用安裝默認(rèn)要校驗(yàn)簽名,需要執(zhí)行以下命令,關(guān)閉簽名校驗(yàn)。
- ./sdcard/dev_tools/bin/bm set -s disable
7.3 安裝應(yīng)用
- ./sdcard/dev_tools/bin/bm install -p /sdcard/MyUiApp.hap
## 8. 通過(guò)NFS安裝
每次插拔`sdcard`還是蠻不方便的,這里我們安裝一個(gè)`NFS`服務(wù)器,讓鴻蒙系統(tǒng)能直接訪(fǎng)問(wèn)`Win10`的目錄,后續(xù)安裝調(diào)試就會(huì)方便很多。
### 8.1 安裝NFS服務(wù)器
我們先安裝一個(gè)`haneWIN NFS服務(wù)器`, 雙擊文末網(wǎng)盤(pán)里的`nfs1169.exe`,一路下一步即可。
8.2 配置目錄參數(shù)
編輯輸出表文件,定義傳輸目錄
- # exports example
- # C:\ftp -range 192.168.1.1 192.168.1.10
- # c:\public -public -readonly
- # c:\tools -readonly 192.168.1.4
- D:\PycharmProjects\aiLearn\Harmony\tftp -public -name:nfs
右鍵管理員權(quán)限,重啟所有服務(wù),讓配置生效。
### 8.4 設(shè)置防火墻
防火墻設(shè)置`111、1058、2049`這些端口的`TCP`和`UDP`,入站規(guī)則放行。
### 8.5 鴻蒙上掛載目錄
主電腦的`ip`地址為`192.168.1.57`,`NFS`服務(wù)的別名為`nfs`,對(duì)應(yīng)的目錄為`D:\PycharmProjects\aiLearn\Harmony\tftp`
- mkdir nfs
- mount 192.168.1.57:/nfs /nfs nfs
8.6 安裝應(yīng)用
- cd nfs
- ./dev_tools/bin/bm set -s disable
- ./dev_tools/bin/bm install -p MyUiApp.hap
前面做了這么多的鋪墊,后續(xù)開(kāi)發(fā)只要復(fù)制`hap`安裝包,直接一條命令安裝即可,非常方便。
# 運(yùn)行程序
安裝完成后,點(diǎn)擊桌面上的`MyUiApp`就能看見(jiàn)界面效果了。
`Js UI框架`對(duì)開(kāi)發(fā)者還是比較友好的,有小程序或快應(yīng)用的開(kāi)發(fā)經(jīng)驗(yàn),上手應(yīng)該都比較順滑。
不過(guò)`HarmonyOS Device`的支持庫(kù)精簡(jiǎn)的非常嚴(yán)重,例如網(wǎng)絡(luò)訪(fǎng)問(wèn)的`@system.request`和`@system.fetch`都不可用,這些功能在“富鴻蒙”的設(shè)備上開(kāi)發(fā)就會(huì)比較方便。
# 資料下載
# 下一篇預(yù)告
> 本期主要介紹了一下JS框架下的界面開(kāi)發(fā),
> 下一篇我們將嘗試熟悉更多的設(shè)備能力,
> 并打通從框架用戶(hù)態(tài)到驅(qū)動(dòng)內(nèi)核態(tài)之間的聯(lián)系,
> 敬請(qǐng)期待...
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz