前言
自 2023華為開(kāi)發(fā)者大會(huì) 之后聂使,HarmonyOS 后續(xù)版本將不再支持 Android應(yīng)用 的說(shuō)法愈演愈烈屯伞,雖然網(wǎng)絡(luò)上有很多相關(guān)的新聞,但大多都是基于 HarmonyOS NEXT 開(kāi)發(fā)者預(yù)覽版 不支持 Android應(yīng)用 安裝做的推測(cè)颅湘,目前未見(jiàn)華為官方正式發(fā)布說(shuō)明蕊苗。
也有人說(shuō)目前的鴻蒙開(kāi)發(fā)工具 DevEco Studio 里面都沒(méi)有集成 Android SDK,但這也只能說(shuō)明原生的鴻蒙應(yīng)用無(wú)法安裝在 Android 系統(tǒng)上刽锤,這個(gè)說(shuō)法尚未定論镊尺。
但是 HarmonyOS 的發(fā)展是必然的,作為移動(dòng)端的從業(yè)人員并思,自然不能停滯不前庐氮,今天我們就來(lái)走進(jìn) HarmonyOS 的世界。
準(zhǔn)備及注意
這篇文章是面向 Android開(kāi)發(fā)者 的宋彼,因此一些基本的東西我就不再贅述弄砍,相關(guān)文檔可以在華為開(kāi)發(fā)者聯(lián)盟查看。
以下內(nèi)容都是基于已經(jīng)搭建好 HarmonyOS 開(kāi)發(fā)環(huán)境(DevEco Studio输涕、HarmonyOS SDK)音婶;
DevEco Studio應(yīng)用簽名是和華為賬號(hào)綁定的,所以開(kāi)始前需要注冊(cè)一個(gè)華為賬號(hào)(首次運(yùn)行失敗會(huì)有提示)莱坎;
運(yùn)行 HarmonyOS 項(xiàng)目需要一部鴻蒙系統(tǒng)的手機(jī)衣式;(目前僅Mate 50、60系列手機(jī)能正常使用型奥,其它機(jī)型需要使用投屏工具進(jìn)行操作瞳收,直接在手機(jī)上操作會(huì)卡死)碉京;
讓我們從Hello World開(kāi)始
DevEco Studio
Android 開(kāi)發(fā)要使用 Android Studio 開(kāi)發(fā)厢汹,HarmonyOS 也提供了一個(gè) DevEco Studio 開(kāi)發(fā)工具,同樣是基于 IDEA 開(kāi)發(fā)的谐宙,因此功能界面和 Android Studio 大致相同烫葬,很容易上手,并且可以從 Import Sample
菜單里選擇官方提供的模板庫(kù)凡蜻,下載到本地運(yùn)行搭综。
工具下載地址:HUAWEI DevEco Studio和SDK下載和升級(jí) | 華為開(kāi)發(fā)者聯(lián)盟
創(chuàng)建項(xiàng)目
點(diǎn)擊歡迎界面的 Create Project
,創(chuàng)建新項(xiàng)目的流程也和 Android Studio 類似划栓,這里的 Ability
UI組件類似 Android 中的 Activity
兑巾,用于提供UI顯示及生命周期回調(diào),這里我們簡(jiǎn)單的用默認(rèn)模板創(chuàng)建一個(gè) Demo 項(xiàng)目忠荞;
Bundle name
等同于 Android 中的 package name
蒋歌,項(xiàng)目名帅掘、保存位置可以自選,其他配置保持默認(rèn)就可以了堂油,完成項(xiàng)目創(chuàng)建修档。
項(xiàng)目結(jié)構(gòu)
待項(xiàng)目創(chuàng)建完成,你就能看到如下的項(xiàng)目目錄結(jié)構(gòu)府框,文件看上去很多吱窝,但是我們只需要關(guān)注重點(diǎn)部分;
-
Demo/build-profile.json5
項(xiàng)目配置文件迫靖,等同于 Android 項(xiàng)目中的settings.gradle.kts
:{ "app": { "signingConfigs": [], // 簽名配置 "compileSdkVersion": 9, // SDK 版本配置 "compatibleSdkVersion": 9, // SDK 版本配置 "products": [ { "name": "default", "signingConfig": "default", } ] }, "modules": [ // 模塊配置 { "name": "entry", // 模塊名 "srcPath": "./entry", // 模塊路徑 "targets": [ { "name": "default", "applyToProducts": [ "default" ] } ] } ] }
Demo/AppScope
存放全局資源及配置的路徑院峡;Demo/AppScope/resources
應(yīng)用全局資源路徑;-
Demo/AppScope/app.json5
應(yīng)用配置袜香,定義包名撕予、版本、應(yīng)用圖標(biāo)蜈首、名稱等配置:{ "app": { "bundleName": "com.sample.demo", // 包名 "vendor": "example", // 供應(yīng)商 "versionCode": 1000000, // 版本號(hào) "versionName": "1.0.0", // 版本名 "icon": "$media:app_icon", // 應(yīng)用圖標(biāo)实抡,此處配置影響應(yīng)用管理中顯示 "label": "$string:app_name" // 應(yīng)用名,此處配置影響應(yīng)用管理中顯示 } }
使用的圖標(biāo):
app_icon.png
名稱資源:
{
"string": [
{
"name": "app_name",
"value": "Demo"
}
]
}
在應(yīng)用管理中顯示:
Demo/entry
應(yīng)用主模塊欢策,應(yīng)用入口吆寨,存放代碼、資源的路徑踩寇;-
Demo/entry/src/main/module.json5
模塊配置文件啄清,類似 Android 項(xiàng)目中的AndroidManifest.xml
:{ "module": { "name": "entry", // 當(dāng)前module的名字,module打包成hap后俺孙,表示hap的名稱辣卒,標(biāo)簽值采用字符串表示(最大長(zhǎng)度31個(gè)字節(jié)),該名稱在整個(gè)應(yīng)用要唯一 "type": "entry", // 表示模塊的類型睛榄,類型有三種荣茫,分別是entry、feature和har "srcEntry": "./ets/DemoAbilityStage.ts", // 模塊的入口文件路徑场靴,默認(rèn)沒(méi)有啡莉,需要手動(dòng)創(chuàng)建,類似 Android 中的 Application "description": "$string:module_desc", // 當(dāng)前模塊的描述信息 "mainElement": "EntryAbility", // 該標(biāo)簽標(biāo)識(shí)hap的入口ability名稱或者extension名稱旨剥。只有配置為mainElement的ability或者extension才允許在服務(wù)中心露出 "deviceTypes": [ // 該標(biāo)簽標(biāo)識(shí)hap可以運(yùn)行在哪類設(shè)備上 "phone", "tablet" ], "deliveryWithInstall": true, // 該模塊是否隨應(yīng)用一起安裝 "installationFree": false, // 釋放支持免安裝 "pages": "$profile:main_pages", // ability 中使用的 page 信息配置 "abilities": [ // ability 配置列表咧欣,類似 Android 中的 Activity 列表 { "name": "EntryAbility", // 邏輯名,整個(gè)應(yīng)用要唯一 "srcEntry": "./ets/entryability/EntryAbility.ts", // 入口代碼路徑 "description": "$string:EntryAbility_desc", // 描述信息 "icon": "$media:icon", // 圖標(biāo)轨帜,如果為 MainElement魄咕,必填,此處配置影響應(yīng)用列表顯示及任務(wù)棧顯示 "label": "$string:EntryAbility_label", // 標(biāo)簽名蚌父,此處配置影響應(yīng)用列表顯示及任務(wù)棧顯示 "startWindowIcon": "$media:icon", // 啟動(dòng)頁(yè)圖標(biāo) "startWindowBackground": "$color:start_window_background", // 啟動(dòng)頁(yè)背景顏色 "exported": true, "skills": [ { "entities": [ "entity.system.home" ], "actions": [ "action.system.home" ] } ] } ] } }
使用的圖標(biāo):
名稱資源:
{
"string": [
{
"name": "EntryAbility_label",
"value": "Ability1"
}
]
}
在桌面顯示:
在任務(wù)棧顯示:
如果有多個(gè) `UIAbility`哮兰,則配置了 `skills` 為 `entity.system.home` 的都會(huì)在桌面創(chuàng)建圖標(biāo):
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
Demo/entry/src/main/ets
源碼文件路徑烟具;Demo/entry/src/main/ets/entryability/EntryAbility.ts
UI 組件,類似 Android 中的Activity
奠蹬;Demo/entry/src/main/resources
資源文件路徑朝聋;
項(xiàng)目架構(gòu)及與Android對(duì)比
從總體的項(xiàng)目架構(gòu)來(lái)看,HarmonyOS 項(xiàng)目是比較貼近 Android 項(xiàng)目中 Compose + 單Activity 架構(gòu)的囤躁,并且我們?cè)?HarmonyOS 中也能找到一些與 Android 項(xiàng)目對(duì)應(yīng)的關(guān)系:
Android | HarmonyOS | ||
---|---|---|---|
settings.gradle.kts | 項(xiàng)目配置文件 | Demo/build-profile.json5 | 項(xiàng)目配置文件冀痕,不同的是將應(yīng)用的簽名、SDK版本狸演、多渠道配置移動(dòng)到了這里 |
build.gradle.kts | 模塊配置文件 | Demo/AppScope/app.json5 | 應(yīng)用配置文件言蛇,配置包名、版本宵距、圖標(biāo)腊尚、名稱 |
AndroidManifest.xml | 清單文件 | Demo/entry/src/main/module.json5 | 模塊配置文件,配置應(yīng)用入口满哪、路由等信息 |
Application | 應(yīng)用程序入口 | AbilityStage | 應(yīng)用程序入口 |
Activity | UI組件 | UIAbility | UI組件 |
Navgation | 頁(yè)面路由 | pages | 頁(yè)面路由 |
生命周期
在 module.json5
中的 module
節(jié)點(diǎn)聲明 srcEntry
婿斥,我們也能和 Android 應(yīng)用一樣配置一個(gè)全局的應(yīng)用程序入口,擁有類似的生命周期方法回調(diào):
import AbilityStage from '@ohos.app.ability.AbilityStage';
export default class DemoAbilityStage extends AbilityStage {
onCreate() {
// 應(yīng)用啟動(dòng)回調(diào)
}
}
而 HarmonyOS 中的UI組件 UIAbility
也和 Android 中的 Activity
有著類似的生命周期:
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 組件創(chuàng)建
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
// 組件銷毀
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// window 創(chuàng)建
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
// 設(shè)置布局哨鸭,顯示 ets/pages/Index.ets 的布局
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// window 銷毀
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// 進(jìn)入前臺(tái)
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// 進(jìn)入后臺(tái)
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
HarmonyOS 的 UIAbility
沒(méi)有 Android 中 Activity
的 onResume
onPause
生命周期回調(diào)方法民宿,當(dāng)然如果需要的話還是有方案可以實(shí)現(xiàn)的,需要在 onWindowStageCreate
方法里像鸡,通過(guò) windowStage
實(shí)現(xiàn):
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.on('windowStageEvent', (event) => {
// event 取值為枚舉類型 window.WindowStageEventType
if(event === window.WindowStageEventType.ACTIVE) {
// 獲取焦點(diǎn)
} else {
// 失去焦點(diǎn)
}
})
}
布局
HarmonyOS 使用 ArkTS 作為開(kāi)發(fā)語(yǔ)言活鹰,并且提供 ArkTS UI 組件用于UI布局,就像上面 UIAbility
中顯示的布局 ets/pages/Index.ets
:
@Entry // 聲明這個(gè)組件可作為頁(yè)面入口只估,即在 UIAbility 中加載或進(jìn)行頁(yè)面跳轉(zhuǎn)
@Component // 聲明這是一個(gè)UI組件
struct Index {
@State message: string = 'Hello World'
build() {
// 聲明布局
Row() { // 橫向布局
Column() { // 豎向布局
Text(this.message) // 文本控件
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%') // 寬度鋪滿
}
.height('100%') // 高度鋪滿
}
}
上面是新建項(xiàng)目默認(rèn)生成的布局志群,效果是在屏幕中間顯示 Hello World
文本,更多組件可參考組件參考(基于ArkTS的聲明式開(kāi)發(fā)范式蛔钙。
界面跳轉(zhuǎn)
Pages 跳轉(zhuǎn)
HarmonyOS 生成的項(xiàng)目里锌云,默認(rèn)只有一個(gè) UIAbility
,并通過(guò) windowStage.loadContent
來(lái)加載顯示布局夸楣,因此一種多界面的方式就是編寫不同的 Page宾抓,在不同的 Page 直接跳轉(zhuǎn)子漩;
首先豫喧,我們?cè)?ets/pages
路徑下新建一個(gè) Second.ets
文件,并參照 Index.ets
聲明布局幢泼,并添加按鈕用于返回上一級(jí):
import router from '@ohos.router'
@Entry
@Component
struct Second {
@State message: string = 'Second Page'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
// 添加按鈕
Button("點(diǎn)擊返回")
.onClick(() => {
// 按鈕點(diǎn)擊通過(guò) router 返回上一級(jí)
router.back()
})
}
.width('100%')
}
.height('100%')
}
}
然后紧显,我們需要在 resources/base/profile/main_pages.json
文件中添加這個(gè)界面的聲明:
{
"src": [
"pages/Index",
"pages/Second"
]
}
在之前的 Index.ets
布局中添加按鈕并配置點(diǎn)擊跳轉(zhuǎn)邏輯:
import router from '@ohos.router'
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
// 添加按鈕
Button("點(diǎn)擊跳轉(zhuǎn)")
.onClick(() => {
// 按鈕點(diǎn)擊通過(guò) router 跳轉(zhuǎn)到 pages/Second
router.pushUrl({
url: "pages/Second"
})
})
}
.width('100%')
}
.height('100%')
}
}
這樣通過(guò)點(diǎn)擊按鈕就能進(jìn)行界面的跳轉(zhuǎn)了。上面創(chuàng)建 Page 的方式推薦在 ets/pages
路徑使用 New -> Page
進(jìn)行創(chuàng)建缕棵,會(huì)自動(dòng)生成對(duì)應(yīng)的布局文件和配置孵班,更便捷且不容易出錯(cuò)涉兽。
UIAbility 跳轉(zhuǎn)
雖然 HarmonyOS 官方提供的模板里面都只有一個(gè) UIAbility
,但是它還是支持多 UIAbility
的篙程;
同樣的在 ets
路徑下參照 EntryAbility.ts
創(chuàng)建一個(gè)新的 SecondEntryAbility.ts
枷畏,在 onWindowStageCreate
中加載布局 pages/SecondAblity
,在 module.json5
中添加對(duì)應(yīng)的配置即可虱饿,這里還是推薦使用 New -> Ability
進(jìn)行創(chuàng)建拥诡;
在 ets/pages/SecondAbility.ets
中修改文本及添加返回按鈕:
import common from '@ohos.app.ability.common'
@Preview
@Entry
@Component
struct SecondAbility {
@State message: string = 'Second Ability'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("點(diǎn)擊返回")
.margin({ top: 30 })
.onClick(() => {
// 按鈕點(diǎn)擊關(guān)閉當(dāng)前 UIAbility
let context = getContext(this) as unknown as common.UIAbilityContext
context.terminateSelf()
})
}
.width('100%')
}
.height('100%')
}
}
然后我們修改 ets/pages/Index.ets
中的代碼,在之前的按鈕下方添加一個(gè)新的按鈕點(diǎn)擊跳轉(zhuǎn) SecondEntryAbility
:
import common from '@ohos.app.ability.common'
import Want from '@ohos.app.ability.Want'
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button("點(diǎn)擊跳轉(zhuǎn)")
.onClick(() => {
// 按鈕點(diǎn)擊跳轉(zhuǎn)到 SecondEntryAbility
let context = getContext(this) as unknown as common.UIAbilityContext
let want: Want = {
deviceId: "",
bundleName: "com.sample.demo",
abilityName: "SecondEntryAbility",
}
context.startAbility(want)
})
// 添加按鈕
Button("點(diǎn)擊跳轉(zhuǎn)Ability")
.onClick(() => {
// 按鈕點(diǎn)擊跳轉(zhuǎn)到 SecondEntryAbility
let context = getContext(this) as unknown as common.UIAbilityContext
let want: Want = {
deviceId: "",
bundleName: "com.sample.demo",
abilityName: "SecondEntryAbility",
}
context.startAbility(want)
})
}
.width('100%')
}
.height('100%')
}
}
這里我們就要提到 UIAbility
和 Activity
的區(qū)別了氮发,雖然他們同樣都是UI組件渴肉,但是在 HarmonyOS 中,每打開(kāi)一個(gè) UIAbility
爽冕,都會(huì)在任務(wù)棧中單獨(dú)顯示出來(lái)仇祭;
總結(jié)
一路看下來(lái),相信你對(duì) HarmonyOS 項(xiàng)目如何上手已經(jīng)有了思路颈畸,作為 Android 開(kāi)發(fā)者乌奇,我在寫這篇文章的時(shí)候更多的是在尋找 HarmonyOS 和 Android 開(kāi)發(fā)的相似之處,通過(guò)這樣的對(duì)比眯娱,我們不需要從頭了解 HarmonyOS 開(kāi)發(fā)华弓,就能更快的入手了。
文章作者: WangJie0822
文章鏈接: http://www.wangjie0822.top/posts/b8dc3748
版權(quán)聲明: 本博客所有文章除特別聲明外困乒,均采用 CC BY-NC-SA 4.0 許可協(xié)議寂屏。轉(zhuǎn)載請(qǐng)注明來(lái)自 WangJie0822!