概述
如果一個應用需要在多個設備上提供同樣的內容,則需要適配不同的屏幕尺寸和硬件,開發成本較高。HarmonyOS 系統面向多終端提供了“一次開發,多端部署”(后文中簡稱為“一多”)的能力,可以基于一種設計,高效構建多端可運行的應用

定義和目標
定義:一套代碼工程,一次開發上架,多端按需部署。
目標:支撐開發者快速高效的開發支持多種終端設備形態的應用,實現對不同設備兼容的同時,提供跨設備的流轉、遷移和協同的分布式體驗。
關鍵問題
為了實現“一多”的目標,需要解決如下三個基礎問題:
問題1:頁面如何適配
不同設備間的屏幕尺寸、色彩風格等存在差異,頁面如何適配。
問題2:功能如何兼容
不同設備的系統能力有差異,如智能穿戴設備是否具備定位能力、智慧屏是否具備攝像頭等,功能如何兼容。
問題3:工程如何組織
如何實現一套代碼同時能部署到多種不同設備上,代碼工程如何組織。
關鍵問題的解決思路
針對“一多”提出的三個基礎問題,可以從界面級、功能級、工程級三個維度給出相關問題的解決思路:
界面級一多
頁面級一多需要考慮不同設備間的屏幕尺寸、色彩風格等存在差異,頁面如何適配。可以從布局能力、資源使用、交互歸一幾個方面去考慮。
布局能力
布局決定了頁面中的元素按照何種方式排布及顯示,是頁面設計及開發過程中首先需要考慮的問題。一般情況下,可以通過頁面(或自定義組件)內的組件結構(組件個數、組件的父子/兄弟關系、組件類型、組件的相對位置)來判斷使用何種布局能力。
- 對于隨尺寸變化組件結構相同的場景,可以在開發過程中靈活使用自適應布局能力來達到目標效果。
- 對于隨尺寸變化組件結構不同的場景,更適合使用響應式布局能力來實現不同尺寸下的不同顯示的效果。
布局可以分為自適應布局和響應式布局
名稱 | 簡介 |
---|---|
自適應布局 | 當外部容器大小發生變化時,元素可以根據相對關系自動變化以適應外部容器變化的布局能力。相對關系如占比、固定寬高比、顯示優先級等。當前自適應布局能力有7種:拉伸能力、均分能力、占比能力、縮放能力、延伸能力、隱藏能力、折行能力。自適應布局能力可以實現界面顯示隨外部容器大小連續變化。 |
響應式布局 | 當外部容器大小發生變化時,元素可以根據斷點、柵格或特定的特征(如屏幕方向、窗口寬高等)自動變化以適應外部容器變化的布局能力。當前響應式布局能力有3種:斷點、媒體查詢、柵格布局。響應式布局可以實現界面隨外部容器大小有不連續變化,通常不同特征下的界面顯示會有較大的差異。 |
說明
自適應布局多用于解決頁面各區域內的布局差異,響應式布局多用于解決頁面各區域間的布局差異。?
?
自適應布局和響應式布局常常需要借助容器類組件實現,或與容器類組件搭配使用。
-
自適應布局常常需要借助Row組件、Column組件或Flex組件實現。
容器組件
組件說明
拉伸能力
均分能力
占比能力
Row
沿水平方向布局子組件的容器
增加Blank子組件
將組件justifyContent屬性設置為FlexAlign.SpaceEvenly
通過百分比設置子組件寬高,或配置子組件layoutWeight屬性
Column
沿垂直方向布局子組件的容器
增加Blank子組件
將組件justifyContent屬性設置為FlexAlign.SpaceEvenly
通過百分比設置子組件寬高,或配置子組件layoutWeight屬性
Flex
使用彈性方式布局子組件的容器
增加Blank子組件,或配置子組件flexGrow和flexShrink屬性
將組件justifyContent屬性設置為FlexAlign.SpaceEvenly
通過百分比設置子組件寬高,或配置子組件layoutWeight屬性
容器組件
組件說明
縮放能力
延伸能力
隱藏能力
折行能力
Row
沿水平方向布局子組件的容器
配置組件aspectRatio屬性
增加Scroll父組件
配置子組件displayPriority屬性
—
Column
沿垂直方向布局子組件的容器
配置組件aspectRatio屬性
增加Scroll父組件
配置子組件displayPriority屬性
—
Flex
使用彈性方式布局子組件的容器
配置組件aspectRatio屬性
—
配置子組件displayPriority屬性
將組件wrap屬性,
設置為FlexWrap.Wrap
-
響應式布局常常與GridRow組件、Grid組件、List組件、Swiper組件或Tabs組件搭配使用。
容器組件
組件說明
響應式布局
GridRow
使用斷點和柵格方式布局子組件的容器。
需配合GridCol子組件使用。
柵格組件自身具有響應式布局能力。
Grid
使用“行”和“列”分割的單元格方式布局子組件的網格容器。
需配合GridItem子組件使用。
需配合斷點使用,通過改變不同斷點下的rowsTemplate和columnsTemplate等屬性,實現不同的布局效果。
List
包含一系列相同寬度列表項的容器。
需配合ListItem子組件使用。
需配合斷點使用,通過改變不同斷點下的lanes等屬性,實現不同的布局效果。
Swiper
輪播展示子組件的容器。
需配合斷點使用,通過改變不同斷點下的displayCount和indicator等屬性,實現不同的布局效果。
Tabs
使用頁簽控制內容切換的容器,每個頁簽對應一個內容視圖。
需配合TabContent子組件使用。
需配合斷點使用,通過改變不同斷點下的vertical和barPosition等屬性,實現不同的布局效果。
交互歸一
對于不同類型的智能設備,用戶可能有不同的交互方式,如通過觸摸屏、鼠標、觸控板等。如果針對不同的交互方式單獨做適配,會增加開發工作量同時產生大量重復代碼。為解決這一問題,我們統一了各種交互方式的API,即實現了交互歸一。
常見的基礎輸入方式及其在各輸入設備上的表現如下圖所示。
?資源使用
在頁面開發過程中,經常需要用到顏色、字體、間距、圖片等資源,在不同的設備或配置中,這些資源的值可能不同。有兩種方式處理:
-
應用資源:借助資源文件能力,開發者在應用中自定義資源,自行管理這些資源在不同的設備或配置中的表現。
-
系統資源:開發者直接使用系統預置的資源定義(即分層參數)。
資源目錄示例:
resources
|---base
| |---element
| | |---string.json
| |---media
| | |---icon.png
| |---profile
| | |---test_profile.json
|---en_US // 默認存在的目錄,設備語言環境是美式英文時,優先匹配此目錄下資源
| |---element
| | |---string.json
| |---media
| | |---icon.png
| |---profile
| | |---test_profile.json
|---zh_CN // 默認存在的目錄,設備語言環境是簡體中文時,優先匹配此目錄下資源
| |---element
| | |---string.json
| |---media
| | |---icon.png
| |---profile
| | |---test_profile.json
|---en_GB-vertical-car-mdpi // 自定義限定詞目錄示例,由開發者創建
| |---element
| | |---string.json
| |---media
| | |---icon.png
| |---profile
| | |---test_profile.json
|---rawfile // 其他類型文件,原始文件形式保存,不會被集成到resources.index文件中。文件名可自定義。
|---resfile // 其他類型文件,原始文件形式保存,不會被集成到resources.index文件中。文件名可自定義。
功能級一多
應用開發至少包含兩部分工作: UI頁面開發和底層功能開發(部分需要聯網的應用還會涉及服務端開發)。前面介紹了如何解決頁面適配的問題,本章節主要介紹應用如何解決設備系統能力差異的兼容問題。
系統能力
系統能力(即SystemCapability,縮寫為SysCap)指操作系統中每一個相對獨立的特性,如藍牙,WIFI,NFC,攝像頭等,都是系統能力之一。每個系統能力對應多個API,隨著目標設備是否支持該系統能力共同存在或消失。
可以在SysCap列表中查詢HarmonyOS的能力集
支持能力集,聯想能力集與要求能力集
- 支持能力集:設備具備的系統能力集合,在設備配置文件中配置。
- 要求能力集:應用需要的系統能力集合,在應用配置文件中配置。
- 聯想能力集:開發應用時DevEco Studio可聯想的API所在的系統能力集合,在應用配置文件中配置。
支持能力集,聯想能力集與要求能力集都是系統能力的集合。
支持能力集描述的是設備能力,要求能力集描述的是應用能力。若應用A的要求能力集是設備N的支持能力集的子集,則應用A可分發到設備N上安裝運行,否則不能分發。
聯想能力集是該應用開發時,DevEco Studio可聯想的API所在的系統能力集合。
?
設備與支持能力集
每個設備根據其硬件能力,對應不同的支持能力集。
SDK將設備分為兩組,典型設備和自定義設備,典型設備的支持能力集由HarmonyOS來定義,自定義設備由設備廠商給出。
設備與SDK能力的對應
SDK向DevEco Studio提供全量API,DevEco Studio識別開發者項目中選擇的設備形態,找到該設備的支持能力集,篩選支持能力集包含的API并提供API聯想。
加入自定義syscap
在某具體的設備型號上,能力可能超出工程默認設備定義的能力集范圍,如果需要使用此部分能力,需要額外配置自定義的syscap。
按如下格式填入所需要使用的SysCaps。以使用NFC能力為例,syscap.json文件示例如下。
{"devices": {"general": [// 每一個典型設備對應一個syscap支持能力集,可配置多個典型設備,應與工程所選擇的設備一致"phone"]},"development": {// addedSysCaps內的sycap集合與devices中配置的各設備支持的syscap集合的并集共同構成聯想能力集。"addedSysCaps": ["SystemCapability.Communication.NFC.Core","SystemCapability.Communication.NFC.CardEmulation","SystemCapability.Communication.NFC.Tag"]}
}
單設備應用開發
默認應用的聯想能力集,要求系統能力集和設備的支持系統能力集相等,開發者修改要求能力集需要慎重。
跨設備應用開發
默認應用的聯想能力集是多個設備支持能力集的并集,要求能力集則是交集。
判斷 API 是否可以使用
當前提供了ArkTS API和Native API用于幫助判斷某個API是否可以使用。
ArkTS API
方法1:系統定義了API canIUse幫助開發者來判斷該設備是否支持某個特定的syscap。
if (canIUse("SystemCapability.ArkUI.ArkUI.Full")) {console.log("該設備支持SystemCapability.ArkUI.ArkUI.Full");
} else {console.log("該設備不支持SystemCapability.ArkUI.ArkUI.Full");
}
方法2:開發者可通過import的方式將模塊導入,若當前設備不支持該模塊,import的結果為undefined,開發者在使用其API時,需要判斷其是否存在。
import geolocationManager from '@ohos.geoLocationManager';if (geolocationManager) {
geolocationManager.getCurrentLocation((location) => {console.log('current location: ' + JSON.stringify(location));
});
} else {
console.log('該設備不支持位置信息');
}
Native API
#include <stdio.h>
#include <stdlib.h>
#include "syscap_ndk.h"char syscap[] = "SystemCapability.ArkUI.ArkUI.Full";
bool result = canIUse(syscap);
if (result) {printf("SysCap: %s is supported!\n", syscap);
} else {printf("SysCap: %s is not supported!\n", syscap);
}
除此之外,開發者可以通過API參考文檔查詢API接口所屬的SysCap。
不同設備相同能力的差異檢查
即使是相同的系統能力,在不同的設備下,也會有能力的差異。比如同是攝像頭的能力,平板設備優于智能穿戴設備。
import userAuth from '@ohos.userIAM.userAuth';const authenticator = userAuth.getAuthenticator();
const result = authenticator.checkAbility('FACE_ONLY', 'S1');if (result == authenticator.CheckAvailabilityResult.AUTH_NOT_SUPPORT) {console.log('該設備不支持人臉識別');
}
//強行調用不支持的 API 會返回錯誤信息,但不會出現語法錯誤。
authenticator.execute('FACE_ONLY', 'S1', (err, result) => {if (err) {console.log(err.message);return;}
})
設備間的SysCap差異如何產生的?
設備的SysCap因產品解決方案廠商拼裝的部件組合不同而不同,整體流程如下圖:
-
一套操作系統源碼由可選和必選部件集組成,不同的部件為對外體現的系統能力不同,即部件與 SysCap 之間映射關系。
-
發布歸一化的SDK,API與SysCap之間存在映射關系。
-
產品解決方案廠商按硬件能力和產品訴求,可按需拼裝部件。
-
產品配置的部件可以是系統部件,也可以是三方開發的私有部件,由于部件與SysCap間存在映射,所有拼裝后即可得到該產品的SysCap集合。
-
SysCap集編碼生成 PCID (Product Compatibility ID, 產品兼容性標識),應用開發者可將PCID導入IDE解碼成SysCap,開發時對設備的SysCap差異做兼容性處理。
-
部署到設備上的系統參數中包含了SysCap集,系統提供了native的接口和應用接口,可供系統內的部件和應用查詢某個SysCap是否存在。
-
應用開發過程中,應用必要的SysCap將被編碼成RPCID(Required Product Compatibility ID),并寫入應用安裝包中。應用安裝時,包管理器將解碼RPCID得到應用需要的 SysCap,與設備當前具備的SysCap比較,若應用要求的SysCap都被滿足,則安裝成功。
-
應用運行時,可通過canIUse接口查詢設備的SysCap,保證在不同設備上的兼容性。
配置聯想能力集和要求能力集
DevEco Studio會根據創建的工程所支持的設備自動配置聯想能力集和要求能力集,同時也支持開發者修改。
// syscap.json
{"devices": {"general": [ // 每一個典型設備對應一個syscap支持能力集,可配置多個典型設備"default","tablet"],"custom": [ // 廠家自定義設備{"某自定義設備": ["SystemCapability.Communication.SoftBus.Core"]}]},"development": { // addedSysCaps內的sycap集合與devices中配置的各設備支持的syscap集合的并集共同構成聯想能力集"addedSysCaps": ["SystemCapability.Communication.NFC.Core"]},"production": { // 用于生成rpcid,慎重添加,可能導致應用無法分發到目標設備上"addedSysCaps": [], // devices中配置的各設備支持的syscap集合的交集,添加addedSysCaps集合再除去removedSysCaps集合,共同構成要求能力集"removedSysCaps": [] // 當該要求能力集為某設備的子集時,應用才可被分發到該設備上}
}
說明
- 對于要求能力集,開發者修改時要十分慎重,修改不當會導致應用無法分發和安裝到目標設備上。
- 對于聯想能力集,通過增加系統能力可以擴大IDE可聯想的API范圍。但要注意這些API可能在某些設備上不支持,使用前需要判斷。
?
工程級一多
工程級一多需要考慮如何實現一套代碼同時能部署到多種不同設備上,代碼工程如何組織。
應用程序包結構
在進行應用開發時,一個應用通常包含一個或多個Module。Module是HarmonyOS應用/服務的基本功能單元,包含了源代碼、資源文件、第三方庫及應用/服務配置文件,每一個Module都可以獨立進行編譯和運行。
Module分為“Ability”和“Library”兩種類型:
- “Ability”類型的Module編譯后生成HAP包。
- “Library”類型的Module編譯后生成HAR包。
HarmonyOS的應用以APP Pack形式發布,其包含一個或多個HAP包。HAP是HarmonyOS應用安裝的基本單位,HAP可以分為Entry和Feature兩種類型:
- Entry類型的HAP:應用的主模塊。在同一個應用中,同一設備類型只支持一個Entry類型的HAP,通常用于實現應用的入口界面、入口圖標、主特性功能等。
- Feature類型的HAP:應用的動態特性模塊。Feature類型的HAP通常用于實現應用的特性功能,一個應用程序包可以包含一個或多個Feature類型的HAP,也可以不包含。
說明
關于Entry類型的HAP包、Feature類型的HAP包、HAR包、HSP包以及APP Pack的詳細介紹請參考應用程序包結構說明
部署模型
“一多”有兩種部署模型:
- 部署模型A:不同類型的設備上按照一定的工程結構組織方式,通過一次編譯生成相同的HAP(或HAP組合)。
- 部署模型B:不同類型的設備上按照一定的工程結構組織方式,通過一次編譯生成不同的HAP(或HAP組合)。
開發者可以從應用UX設計及應用功能兩個維度,結合具體的業務場景,考慮選擇哪種部署模型。當然,也可以借助設備類型分類,快速做出判斷。
從屏幕尺寸、輸入方式及交互距離三個維度考慮,可以將常用類型的設備分為不同泛類:
- 默認設備、平板
- 車機、智慧屏
- 智能穿戴
- ……
對于相同泛類的設備,優先選擇部署模型A,對于不同泛類設備,優先選擇部署模型B。
說明
- 部署模型不同,相應的代碼工程結構也有差異。部署模型A和部署模型B的主要差異點集中在products層:部署模型A在products目錄下同一子目錄中做功能和特性集成;部署模型B在products目錄下不同子目錄中對不同的產品做差異化的功能和特性集成。
- 開發階段應考慮不同類型設備間最大程度的復用代碼,以減少開發及后續維護的工作量。
- 整個代碼工程最終構建出一個APP包,應用以APP包的形式發布到應用市場中。
工程結構
“一多”推薦在應用開發過程中使用如下的“三層工程結構”。
-
common(公共能力層):用于存放公共基礎能力集合(如工具庫、公共配置等)。
common層可編譯成一個或多個HAR包或HSP包(HAR中的代碼和資源跟隨使用方編譯,如果有多個使用方,它們的編譯產物中會存在多份相同拷貝;而HSP中的代碼和資源可以獨立編譯,運行時在一個進程中代碼也只會存在一份),其只可以被products和features依賴,不可以反向依賴。
-
features(基礎特性層):用于存放基礎特性集合(如應用中相對獨立的各個功能的UI及業務邏輯實現等)。
各個feature高內聚、低耦合、可定制,供產品靈活部署。不需要單獨部署的feature通常編譯為HAR包或HSP包,供products或其它feature使用,但是不能反向依賴products層。需要單獨部署的feature通常編譯為Feature類型的HAP包,和products下Entry類型的HAP包進行組合部署。features層可以橫向調用及依賴common層。
-
products(產品定制層):用于針對不同設備形態進行功能和特性集成。
products層各個子目錄各自編譯為一個Entry類型的HAP包,作為應用主入口。products層不可以橫向調用。
??可以看到DevEco Studio創建出的默認工程,僅包含一個的entry類型的模塊。
?更推薦使用本文部署模型小節中介紹的common、features、product三層工程結構。工程結構示例如下所示:
/application├── common # 公共特性目錄│├── features # 功能模塊目錄│ ├── feature1 # 子功能│ ├── feature2 # 子功能2│ └── ... # 子功能n│└── product # 產品層目錄├── wearable # 智能穿戴泛類目錄├── default # 默認設備泛類目錄└── ...
參考鏈接
“一次開發,多端部署”的參考指南中詳細講解了一多的相關知識、UX設計、架構規范等,可供參考。
?