OpenHarmony
子系统适配一般包含两部分:
- 在
config.json
中增加对应子系统和部件,这样编译系统会将该部件纳入编译目标中。 - 针对该部件的
HAL
层接口进行硬件适配,或者可选的软件功能适配。
分布式软总线子系统适配
wifi_lite部件适配
首先,在config.json
文件中,增加communication
子系统的wifi_lite
部件,如下:
{
"subsystem": "communication",
"components": [
{
"component": "wifi_lite",
"optional": "true"
}
]
},
wifi_lite
部件在//build/lite/components/communication.json
文件中,描述如下:
{
"component": "wifi_lite",
……
"targets": [
"//foundation/communication/wifi_lite:wifi" --- wifi_lite的编译目标
],
……
},
在//foundation/communication/wifi_lite/BUILD.gn
文件中,描述需要适配的接口头文件路径,如下:
config("include") {
include_dirs = [ "interfaces/wifiservice" ] --- 因为wifi_lite只提供头文件,不提供wifi的具体实现,所以wifi模块暴露出适配的目录路径提供给硬件厂商来适配,厂商提供wifi协议栈源码实现。
}
group("wifi") {
public_configs = [ ":include" ]
}
因为在本案例中,wifi
属于SoC
提供的功能,所以适配源码放在SoC
的//device/soc/bestechnic/hals/communication/wifi_lite/wifiservice
目录下,包含wifi_device.c
和wifi_hotspot.c
分别适配wifi_device.h
和wifi_hotspot.h
。如下:
……
WifiErrorCode Scan(void) --- wifi_device.c中扫描wifi热点的函数,对wifi_device.h中Scan函数的适配实现
{
WifiErrorCode ret = ERROR_WIFI_BUSY;
if (IsWifiActive() != WIFI_STA_ACTIVE)
return ERROR_WIFI_IFACE_INVALID;
if (g_HalHmosWifiInfo.scan_state == SCAN_REQUEST ||
g_HalHmosWifiInfo.scan_state == SCAN_TRIGGER)
return ERROR_WIFI_BUSY;
HalHmosWifiLock();
ret = ((HalHmosSendEvent(HMOS_ON_WIFI_SCAN_STATE_CHANGED, NULL) == 0) ? WIFI_SUCCESS : ERROR_WIFI_BUSY);
HalHmosWifiUnLock();
return ret;
}
……
int GetSignalLevel(int rssi, int band) --- wifi_hotspot.c中获取wifi信号热点函数,对wifi_hotspot.h中GetSignalLevel函数的适配实现。
{
if (band == HOTSPOT_BAND_TYPE_2G) {
if (rssi >= RSSI_LEVEL_4_2_G)
return RSSI_LEVEL_4;
if (rssi >= RSSI_LEVEL_3_2_G)
return RSSI_LEVEL_3;
if (rssi >= RSSI_LEVEL_2_2_G)
return RSSI_LEVEL_2;
if (rssi >= RSSI_LEVEL_1_2_G)
return RSSI_LEVEL_1;
}
if (band == HOTSPOT_BAND_TYPE_5G) {
if (rssi >= RSSI_LEVEL_4_5_G)
return RSSI_LEVEL_4;
if (rssi >= RSSI_LEVEL_3_5_G)
return RSSI_LEVEL_3;
if (rssi >= RSSI_LEVEL_2_5_G)
return RSSI_LEVEL_2;
if (rssi >= RSSI_LEVEL_1_5_G)
return RSSI_LEVEL_1;
}
return ERROR_WIFI_INVALID_ARGS;
}
LWIP部件适配
LiteOS-M kernel
目录下默认配置了lwip
,因而具有编译功能,可以在kernel
组件中指定lwip
编译的目录。如下:
{
"subsystem": "kernel",
"components": [
{
"component": "liteos_m",
"features": [
"ohos_kernel_liteos_m_lwip_path = \"//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1\"" --- 指定在芯片厂商目录中进行适配
]
}
]
},
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/BUILD.gn
文件中,描述了lwip
的编译,如下:
import("//kernel/liteos_m/liteos.gni")
import("$LITEOSTHIRDPARTY/lwip/lwip.gni")
import("$LITEOSTOPDIR/components/net/lwip-2.1/lwip_porting.gni")
module_switch = defined(LOSCFG_NET_LWIP_SACK)
module_name = "lwip"
kernel_module(module_name) {
sources = LWIP_PORTING_FILES + LWIPNOAPPSFILES -
[ "$LWIPDIR/api/sockets.c" ] + [ "porting/src/ethernetif.c" ] --- 增加ethernetif.c文件,用以适配ethernet网卡的初始化适配
defines = [ "LITEOS_LWIP=1" ]
defines += [ "CHECKSUM_BY_HARDWARE=1" ]
}
config("public") {
defines = [ "_BSD_SOURCE=1" ]
include_dirs =
[ "porting/include" ] + LWIP_PORTING_INCLUDE_DIRS + LWIP_INCLUDE_DIRS
}
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/include/lwip/lwipopts.h
文件中,说明原有lwip
配置选项保持不变,软总线会依赖这些配置选项,并且新增硬件适配的配置项,如下:
#ifndef _PORTING_LWIPOPTS_H_
#define _PORTING_LWIPOPTS_H_
#include_next "lwip/lwipopts.h" --- 保持原来的配置项不变
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_CHECKSUM_ON_COPY 0
#define CHECKSUM_GEN_UDP 0 --- 新增硬件适配选项
#endif /* _PORTING_LWIPOPTS_H_ */
在//device/soc/bestechnic/bes2600/liteos_m/components/net/lwip-2.1/porting/src/ethernetif.c
文件中,说明对ethernet
网卡初始化的适配,如下:
err_t
ethernetif_init(struct netif *netif)
{
……
#ifdef CHECKSUM_BY_HARDWARE
eth_hw_checksum_init();
#endif
……
netif->linkoutput = low_level_output;
netif->drv_send = liteos_low_level_output;
netif->hwaddr_len = NETIF_MAX_HWADDR_LEN;
low_level_init(netif);
driverif_init(netif);
return ERR_OK;
……
}
dsoftbus部件适配
在config.json
中增加dsoftbus
部件配置如下:
{
"component": "dsoftbus",
"features": [
"softbus_adapter_config = \"//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config\""
]
},
dsoftbus
部件在//foundation/communication/dsoftbus/dsoftbus.gni
文件中提供了softbus_adapter_config
配置选项可供移植过程进行配置,该配置设定了软总线移植适配的路径。
在本案例中,softbus_adapter_config
配置为//vendor/bestechnic/mini_distributed_music_player/dsoftbus_lite_config
路径,该路径下的内容为:
.
├── feature_config --- 软总线功能特性配置,例如是否开启自发现功能等
│ └── mini
│ └── config.gni
└── spec_config --- 软总线规格特性配置,例如设置软总线日志级别设置
├── softbus_config_adapter.c
├── softbus_config_adapter.h
└── softbus_config_type.h
在config.gni
文件中规定了以下配置项:
配置项 | 描述 |
---|---|
dsoftbus_feature_disc_ble | 是否开启BLE发现功能 |
dsoftbus_feature_disc_coap | 是否开启COAP发现功能 |
dsoftbus_feature_conn_tcp | 是否开启TCP连接功能 |
dsoftbus_feature_conn_br | 是否开启BR连接功能 |
dsoftbus_feature_conn_ble | 是否开启BLE连接功能 |
dsoftbus_feature_conn_p2p | 是否开启P2P连接功能 |
dsoftbus_feature_trans_udp | 是否开启UDP传输功能 |
dsoftbus_feature_trans_udp_stream | 是否开启UDP传输流功能 |
dsoftbus_feature_trans_udp_file | 是否开启UDP传输文件功能 |
dsoftbus_feature_ip_auth | 是否开启认证传输通道功能 |
dsoftbus_feature_auth_account | 是否开启基于账号认证功能 |
dsoftbus_feature_qos | 是否开启QoS功能 |
在softbus_config_adapter.c
文件中规定了以下配置项:
配置项 | 描述 |
---|---|
SOFTBUS_INT_MAX_BYTES_LENGTH | SendBytes发送最大Bytes长度 |
SOFTBUS_INT_MAX_MESSAGE_LENGTH | SendMessage发送最大消息的长度 |
SOFTBUS_INT_CONN_BR_MAX_DATA_LENGTH | 蓝牙最大接收数据量 |
SOFTBUS_INT_CONN_RFCOM_SEND_MAX_LEN | 蓝牙最大接收数据量 |
SOFTBUS_INT_ADAPTER_LOG_LEVEL | 日志级别设置 |
SOFTBUS_STR_STORAGE_DIRECTORY | 存储目录设置 |
因为软总线配置了后,不会默认启动,所以需要在通过启动框架调用InitSoftBusServer
函数,如下:
static void DSoftBus(void)
{
osThreadAttr_t attr;
attr.name = "dsoftbus task";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 65536;
attr.priority = 24;
extern void InitSoftBusServer(void);
if (osThreadNew((osThreadFunc_t) InitSoftBusServer, NULL, &attr) == NULL) {
printf("Failed to create WifiSTATask!\n");
}
}
APP_FEATURE_INIT(DSoftBus);
RPC部件适配
在config.json
中增加rpc
部件配置如下:
{
"component": "rpc"
},
同样地,rpc
部件需要通过启动框架调用StartDBinderService
函数,由于该函数正常运行依赖主机已经获取IP
地址,因此在LWIP
协议栈注册IP
地址变化事件的回调函数中调用该函数,如下:
static void RpcServerWifiDHCPSucCB(struct netif *netif, netif_nsc_reason_t reason,
const netif_ext_callback_args_t *args)
{
(void) args;
if (netif == NULL) {
printf("%s %d, error: input netif is NULL!\n", __FUNCTION__, __LINE__);
return;
}
if (reason == LWIP_NSC_IPSTATUS_CHANGE) {
if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr)) {
printf("%s %d, start rpc server!\n", __FUNCTION__, __LINE__);
StartDBinderService();
}
}
}
static void WifiDHCPRpcServerCB(void)
{
NETIF_DECLARE_EXT_CALLBACK(WifiReadyRpcServerCallback);
netif_add_ext_callback(&WifiReadyRpcServerCallback, RpcServerWifiDHCPSucCB);
}
APP_FEATURE_INIT(WifiDHCPRpcServerCB);
启动恢复子系统适配
启动恢复子系统适配bootstrap_lite
/syspara_lite
两个部件。请在vendor/bestechnic_bak/display_demo/config.json
中新增对应的配置选项。
{
"subsystem": "startup",
"components": [
{
"component": "bootstrap_lite" --- bootstrap_lite 部件
},
{
"component": "syspara_lite", --- syspara_lite 部件
"features": [
"enable_ohos_startup_syspara_lite_use_posix_file_api = true"
]
}
]
},
适配bootstrap_lite
部件时,需要在连接脚本文件//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds
中手动新增如下段:
__zinitcall_bsp_start = .;
KEEP (*(.zinitcall.bsp0.init))
KEEP (*(.zinitcall.bsp1.init))
KEEP (*(.zinitcall.bsp2.init))
KEEP (*(.zinitcall.bsp3.init))
KEEP (*(.zinitcall.bsp4.init))
__zinitcall_bsp_end = .;
__zinitcall_device_start = .;
KEEP (*(.zinitcall.device0.init))
KEEP (*(.zinitcall.device1.init))
KEEP (*(.zinitcall.device2.init))
KEEP (*(.zinitcall.device3.init))
KEEP (*(.zinitcall.device4.init))
__zinitcall_device_end = .;
__zinitcall_core_start = .;
KEEP (*(.zinitcall.core0.init))
KEEP (*(.zinitcall.core1.init))
KEEP (*(.zinitcall.core2.init))
KEEP (*(.zinitcall.core3.init))
KEEP (*(.zinitcall.core4.init))
__zinitcall_core_end = .;
__zinitcall_sys_service_start = .;
KEEP (*(.zinitcall.sys.service0.init))
KEEP (*(.zinitcall.sys.service1.init))
KEEP (*(.zinitcall.sys.service2.init))
KEEP (*(.zinitcall.sys.service3.init))
KEEP (*(.zinitcall.sys.service4.init))
__zinitcall_sys_service_end = .;
__zinitcall_sys_feature_start = .;
KEEP (*(.zinitcall.sys.feature0.init))
KEEP (*(.zinitcall.sys.feature1.init))
KEEP (*(.zinitcall.sys.feature2.init))
KEEP (*(.zinitcall.sys.feature3.init))
KEEP (*(.zinitcall.sys.feature4.init))
__zinitcall_sys_feature_end = .;
__zinitcall_run_start = .;
KEEP (*(.zinitcall.run0.init))
KEEP (*(.zinitcall.run1.init))
KEEP (*(.zinitcall.run2.init))
KEEP (*(.zinitcall.run3.init))
KEEP (*(.zinitcall.run4.init))
__zinitcall_run_end = .;
__zinitcall_app_service_start = .;
KEEP (*(.zinitcall.app.service0.init))
KEEP (*(.zinitcall.app.service1.init))
KEEP (*(.zinitcall.app.service2.init))
KEEP (*(.zinitcall.app.service3.init))
KEEP (*(.zinitcall.app.service4.init))
__zinitcall_app_service_end = .;
__zinitcall_app_feature_start = .;
KEEP (*(.zinitcall.app.feature0.init))
KEEP (*(.zinitcall.app.feature1.init))
KEEP (*(.zinitcall.app.feature2.init))
KEEP (*(.zinitcall.app.feature3.init))
KEEP (*(.zinitcall.app.feature4.init))
__zinitcall_app_feature_end = .;
__zinitcall_test_start = .;
KEEP (*(.zinitcall.test0.init))
KEEP (*(.zinitcall.test1.init))
KEEP (*(.zinitcall.test2.init))
KEEP (*(.zinitcall.test3.init))
KEEP (*(.zinitcall.test4.init))
__zinitcall_test_end = .;
__zinitcall_exit_start = .;
KEEP (*(.zinitcall.exit0.init))
KEEP (*(.zinitcall.exit1.init))
KEEP (*(.zinitcall.exit2.init))
KEEP (*(.zinitcall.exit3.init))
KEEP (*(.zinitcall.exit4.init))
__zinitcall_exit_end = .;
需要新增上述段是因为bootstrap_init
提供的对外接口,见//utils/native/lite/include/ohos_init.h
文件,采用的是灌段的形式,最终会保存到上述链接段中。主要的服务自动初始化宏如下表格所示:
接口名 | 描述 |
---|---|
SYS_SERVICE_INIT(func) | 标识核心系统服务的初始化启动入口 |
SYS_FEATURE_INIT(func) | 标识核心系统功能的初始化启动入口 |
APP_SERVICE_INIT(func) | 标识应用层服务的初始化启动入口 |
APP_FEATURE_INIT(func) | 标识应用层功能的初始化启动入口 |
说明: 通过上面加载的组件编译出来的lib文件需要手动加入强制链接。
如在 vendor/bestechnic/display_demo/config.json
中配置了bootstrap_lite
部件
{
"subsystem": "startup",
"components": [
{
"component": "bootstrap_lite"
},
...
]
},
bootstrap_lite
部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c
,该文件中,通过SYS_SERVICE_INIT
将Init
函数符号灌段到__zinitcall_sys_service_start
和__zinitcall_sys_service_end
中,由于Init
函数是没有显式调用它,所以需要将它强制链接到最终的镜像。如下:
static void Init(void)
{
static Bootstrap bootstrap;
bootstrap.GetName = GetName;
bootstrap.Initialize = Initialize;
bootstrap.MessageHandle = MessageHandle;
bootstrap.GetTaskConfig = GetTaskConfig;
bootstrap.flag = FALSE;
SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
}
SYS_SERVICE_INIT(Init); --- 通过SYS启动即SYS_INIT启动就需要强制链接生成的lib
在//base/startup/bootstrap_lite/services/source/BUILD.gn
文件中,描述了在out/v200zr/display_demo/libs
生成 libbootstrap.a
,如下:
static_library("bootstrap") {
sources = [
"bootstrap_service.c",
"system_init.c",
]
....
那么需要在 vendor/bestechnic/display_demo/config.json
配置强制链接库bootstrap
,如下:
"bin_list": [
{
"elf_name": "wifiiot",
"bsp_target_name": "best2600w_liteos",
"signature": "false",
"burn_name": "rtos_main",
"enable": "true",
"force_link_libs": [
"bootstrap", --- 强制链接libbootstrap.a
...
]
},
适配syspara_lite
部件时,系统参数会最终写到文件中进行持久化保存。在轻量系统中,文件操作相关接口有POSIX
接口与HalFiles
接口这两套实现。
因为对接内核的文件系统,采用POSIX
相关的接口,所以features
字段中需要增加enable_ohos_startup_syspara_lite_use_posix_file_api = true
。
如果对接HalFiles
相关的接口实现的,则无须修改。
在适配GetSerial
接口时,开发板不像产线生产过程那样,会写入一个具体的Serial Number
,因而需要确定一个数据对开发板进行唯一标识。本案例采用WiFi Mac
地址进行适配。
#define ETH_ALEN 6
#define MAC_BITS 4
#define MAC_HIGH_MASK 0xf0
#define MAC_LOW_MASK 0x0f
#define HEX_A 0xa
#define CHAR_NUM_OFFSET 0x30
#define CHAR_CAPITAL_OFFSET 0x37
#define STR_END_FLAG '\0'
typedef unsigned char u8;
static char serialNumber[2*ETH_ALEN + 1]; --- 最后一位留作'\0'结束符标识
static char Hex2Char(u8 hex)
{
if (hex < HEX_A) {
return hex + CHAR_NUM_OFFSET; --- 将数值0转为char的'0'
} else {
return hex + CHAR_CAPITAL_OFFSET; --- 将数值0xa转为char的'A'
}
}
const char* HalGetSerial(void)
{
char macAddr[ETH_ALEN];
// as devboard has no production serial number, we just
// use wifi mac address as device serial number.
if (serialNumber[0] == STR_END_FLAG) { --- 只有第一次调用时,才去获取mac地址
extern int bwifi_get_own_mac(u8 *addr);
bwifi_get_own_mac(macAddr); --- 获取mac地址
int j = 0;
for (int i = 0; i < ETH_ALEN; i++) {
u8 lowFour, highFour;
highFour = (macAddr[i] & MAC_HIGH_MASK) >> MAC_BITS;
serialNumber[j] = Hex2Char(highFour);
j++;
lowFour = macAddr[i] & MAC_LOW_MASK;
serialNumber[j] = Hex2Char(lowFour);
j++;
} --- 将mac地址值转化为serial number
}
return serialNumber;
}
DFX子系统适配
进行DFX
子系统适配需要添加hilog_lite
部件,直接在config.json
文件配置即可。
{
"subsystem": "hiviewdfx",
"components": [
{
"component": "hilog_lite",
"optional": "true"
}
]
},
配置完成之后,在//device/soc/bestechnic/bes2600/liteos_m/components/utils/src/hm_sys.c
中注册日志输出实现函数。
boolean HilogProc_Impl(const HiLogContent *hilogContent, uint32 len)
{
char tempOutStr[LOG_FMT_MAX_LEN] = {0};
if (LogContentFmt(tempOutStr, sizeof(tempOutStr), hilogContent) > 0) {
printf(tempOutStr);
}
return TRUE;
}
HiviewRegisterHilogProc(HilogProc_Impl);
系统服务管理子系统适配
进行系统服务管理子系统适配需要添加samgr_lite
部件,直接在config.json
配置即可。
{
"subsystem": "systemabilitymgr",
"components": [
{
"component": "samgr_lite",
"features": [
"config_ohos_systemabilitymgr_samgr_lite_shared_task_size = 4096"
]
}
]
},
在轻量系统中,samgr_lite
配置的共享任务栈大小默认为0x800
。当函数调用栈较大时,会出现栈溢出的问题。在本次适配过程中,将其调整为0x1000
。
安全子系统适配
进行安全子系统适配需要添加huks/deviceauth_lite
部件,直接在config.json
配置即可。
{
"subsystem": "security",
"components": [
{
"component": "huks",
"features": [
"huks_use_lite_storage = true",
"huks_use_hardware_root_key = true",
"huks_config_file = \"hks_config_lite.h\"",
"huks_key_store_path = \"/data/\"",
"ohos_security_huks_mbedtls_porting_path = \"//device/soc/bestechnic/hals/mbedtls\""
]
},
{
"component": "deviceauth_lite",
"features": [
"deviceauth_storage_path = \"/data/\"",
"deviceauth_hichain_thread_stack_size = 9472"
]
}
]
}
huks
部件适配时,huks_key_store_path
配置选项用于指定存放秘钥路径,ohos_security_huks_mbedtls_porting_path
配置选项用于指定进行mbedtls
适配的目录,用于芯片对mbedtls
进行硬件随机数等适配。
deviceauth_lite
部件适配时,deviceauth_storage_path
配置选项用于指定存放设备认证信息的路径,deviceauth_hichain_thread_stack_size
用于指定线程栈大小。
媒体子系统适配
进行媒体子系统适配需要添加histreamer
部件,直接在config.json
配置即可。
{
"subsystem": "multimedia",
"components": [
{
"component": "histreamer",
"features": [
"histreamer_enable_plugin_hdi_adapter = true",
"histreamer_enable_plugin_minimp3_adapter = true",
"histreamer_enable_plugin_ffmpeg_adapter = false",
"config_ohos_histreamer_stack_size = 65536"
]
}
]
},
histreamer
部件配置项说明如下:
配置项 | 说明 |
---|---|
histreamer_enable_plugin_hdi_adapter | 是否使能histreamer对接到hdi接口 |
histreamer_enable_plugin_minimp3_adapter | 是否使能插件适配minimp3 |
histreamer_enable_plugin_ffmpeg_adapter | 是否使能插件适配FFmpeg |
config_ohos_histreamer_stack_size | histreamer栈大小设置 |
公共基础库子系统适配
进行公共基础库子系统适配需要添加kv_store
/js_builtin
/timer_task
/kal_timer
部件,直接在config.json
配置即可。
{
"subsystem": "utils",
"components": [
{
"component": "kv_store",
"features": [
"enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true"
]
},
{
"component": "js_builtin"
},
{
"component": "timer_task"
},
{
"component": "kal_timer",
}
]
},
与适配syspara_lite
部件类似,适配kv_store
部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有POSIX
接口与HalFiles
接口这两套实现。因为对接内核的文件系统,采用POSIX
相关的接口,所以features
需要增加enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true
。如果对接HalFiles
相关的接口实现的,则无须修改。
图形子系统适配
进行图形子系统适配需要添加graphic_utils
部件,直接在config.json
配置即可。
{
"components": [
{
"component": "graphic_utils",
"features": [
"enable_ohos_graphic_utils_product_config = true"
]
},
{
"component": "ui"
}
]
},
graphic
配置文件见 //vendor/bestechnic/display_demo/graphic_config/product_graphic_lite_config.h
。
graphic
适配见//device/soc/bestechnic/bes2600/liteos_m/components/ui
, 主要功能如下:
display_device
:实例化BaseGfxEngine
。touch_input
:实例化PointerInputDevice
。UiMainTask
:初始化字体引擎,执行渲染任务等。
图形子系统层次:
aafwk_lite + appexecfwk_lite (AAFWK + APPEXECFWK)
|
ace_engine_lite + jerryscript + i18n_lite + resmgr_lite + utils/native/lite/... (ACE,JS引擎及其依赖)
|
arkui_ui_lite + graphic_utils (图形框架)
|
giflib + libjpeg + libpng + qrcodegen + freetype... (图形第三方库)
图形应用示例见文件//vendor/bestechnic/display_demo/tests/app.cpp
,如下:
/* ui app entry */
void RunApp()
{
#ifdef UI_TEST
AnimatorDemoStart(); --- native ui demo
#elif defined(ABILITY_TEST)
StartJSApp(); --- js demo
#endif
}
void AppEntry(void)
{
UiMain();
}
APP_FEATURE_INIT(AppEntry);
ACE开发框架子系统适配
进行ACE
开发框架子系统适配需要添加ace_engine_lite
部件,直接在config.json
配置即可。
{
"subsystem": "ace",
"components": [
{
"component": "ace_engine_lite",
"features": [
"enable_ohos_ace_engine_lite_product_config = true"
]
}
]
},
ace_engine_lite
部件配置文件见 //vendor/bestechnic/display_demo/ace_lite_config/product_acelite_config.h
。
ace_lite
的应用采用js语言进行开发,详细步骤如下:
- 用
DevEco Studio
编写js应用,参考轻量级智能穿戴开发。 - 使用预览功能进行预览,并且得到js包:
entry\.preview\intermediates\res\debug\lite\assets\js\default
。 - 将js包放到对应的文件系统目录下,文件系统路径为
vendor/bestechnic/display_demo/fs/data/data/js
,如下:
├── app.js
├── common
├── i18n
├── manifest.json
└── pages
- 最终编译生成系统镜像,烧录到单板后,系统会从
app.js
加载启动ace
的应用。
元能力子系统适配
进行元能力子系统适配需要添加aafwk_lite
部件,直接在config.json
配置即可。
{
"subsystem": "aafwk",
"components": [
{
"component": "aafwk_lite",
"features": [
"enable_ohos_appexecfwk_feature_ability = true", --- 支持FA特性,即包含图形能力
"config_ohos_aafwk_ams_task_size = 4096" --- 配置aafwk栈的大小
]
}
]
},
aafwk_lite
相关的应用样例见vendor/bestechnic/display_demo/tests/ability
目录,包含launcher
和js app
这两类应用,应用的函数调用流程描述如下:
-
launcher
应用,通过InstallLauncher
安装BundleName
为"com.example.launcher"
的native ui
应用,在AbilityMgrSliteFeature
启动后会调用AbilityMgrHandler::StartLauncher()
启动launcher
应用。 -
StartJSApp
应用,通过StartAbility
启动任意Want
,通过将want data
传递JS_APP_PATH
,SetWantData(&want, JS_APP_PATH, strlen(JS_APP_PATH) + 1)
。
包管理子系统适配
进行包管理子系统适配需要添加appexecfwk_lite
部件,直接在config.json
配置即可。
{
"subsystem": "appexecfwk",
"components": [
{
"component": "appexecfwk_lite"
}
]
},
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习
点击领取→纯血鸿蒙Next全套最新学习资料希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~~
一、鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。
获取以上完整版高清,请点击→纯血版全套鸿蒙HarmonyOS学习资料
二、HarmonyOS Next 最新全套视频教程
三、《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
四、大厂面试必问面试题
五、鸿蒙南向开发技术
六、鸿蒙APP开发必备
完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,对于大家来说ye是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。