OpenHarmony实战:Combo解决方案之W800芯片移植案例
本方案基于OpenHarmony LiteOS-M内核,使用联盛德W800芯片的润和软件海王星系列Neptune100开发板,进行开发移植。
移植架构采用Board
与SoC
分离方案,支持通过Kconfig图形化配置编译选项,增加玄铁ck804ef
架构移植,实现了HDF
、XTS
等子系统及组件的适配。
适配准备
准备ubuntu20.04系统环境,安装csky-abiv2-elf-gcc交叉编译工具链。
编译构建
目录规划
本方案的目录结构使用Board和Soc解耦的思路:
芯片适配目录规划为:
device
├── board --- 单板厂商目录
│ └── hihope --- 单板厂商名字:HiHope
│ └── neptune100 --- 单板名:Neptune100
└── soc --- SoC厂商目录└── winnermicro --- SoC厂商名字:联盛德└── wm800 --- SoC Series名:w800系列芯片
产品样例目录规划为:
vendor
└── hihope --- 开发产品样例厂商目录,润和软件的产品样例├── neptune_iotlink_demo --- 产品名字:Neptune100产品样例代码└── ...
产品定义
vendor/hihope/neptune_iotlink_demo/config.json
文件下,描述了产品使用的内核、单板、子系统等信息。其中,内核、单板型号、单板厂商需提前规划好,是预编译指令hb set
关注的。例如:
{"product_name": "neptune_iotlink_demo", --- 产品名"ohos_version": "OpenHarmony 3.1", --- 使用的OS版本"type":"mini", --- 系统类型: mini"version": "3.0", --- 系统版本: 3.0"device_company": "hihope", --- 单板厂商:hihope"board": "neptune100", --- 单板名:neptune100"kernel_type": "liteos_m", --- 内核类型:liteos_m"kernel_version": "3.0.0", --- 内核版本:3.0.0"subsystems": [] --- 子系统
}
填入的信息与规划的目录相对应,其中device_company
和board
用于关联出device/board/<device_company>/
目录。
单板配置
关联到的目录下,在device/board/hihope/neptune100/liteos_m
目录下放置config.gni
文件,该配置文件用于描述该单板信息,包括CPU型号、交叉编译工具链及全局编译、链接参数等重要信息:
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m"# Kernel version.
kernel_version = "3.0.0"# Board CPU type, e.g. "cortex-a7", "riscv32".
board_cpu = "ck804ef"# Board arch, e.g. "armv7-a", "rv32imac".
board_arch = "ck803"# Toolchain name used for system compiling.
# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf.
# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toolchain.
board_toolchain = "csky-elfabiv2-gcc"#use_board_toolchain = true# The toolchain path installed, it's not mandatory if you have added toolchain path to your ~/.bashrc.
board_toolchain_path = ""# Compiler prefix.
board_toolchain_prefix = "csky-elfabiv2-"# Compiler type, "gcc" or "clang".
board_toolchain_type = "gcc"# config.json parse
if (product_path != "") {product_conf = read_file("${product_path}/config.json", "json")product_name = product_conf.product_namebin_list = product_conf.bin_list
}# Board related common compile flags.
board_cflags = ["-mcpu=ck804ef","-mhard-float","-DGCC_COMPILE=1","-DTLS_CONFIG_CPU_XT804=1","-DNIMBLE_FTR=1","-D__CSKY_V2__=1","-DCPU_CK804","-O2","-g3","-Wall","-ffunction-sections","-MMD","-MP",
]board_cxx_flags = board_cflagsboard_asmflags = ["-mcpu=ck804ef","-DCPU_CK804",
]board_ld_flags = []# Board related headfiles search path.
board_include_dirs = []# Board adapter dir for OHOS components.
board_adapter_dir = ""# Sysroot path.
board_configed_sysroot = ""# Board storage type, it used for file system generation.
storage_type = ""
预编译
在工程根目录下输入预编译指令hb set
可显示相关产品信息,如下:
hb set
OHOS Which product do you need? (Use arrow keys)hihope> neptune_iotlink_demoOHOS Which product do you need? neptune_iotlink_demo
执行hb set
后,会在根目录下自动生成ohos_config.json
文件,文件中会列出待编译的产品信息。
通过hb env
可以查看选择出来的预编译环境变量。
[OHOS INFO] root path: /home/xxxx/openharmony_w800
[OHOS INFO] board: neptune100
[OHOS INFO] kernel: liteos_m
[OHOS INFO] product: neptune_iotlink_demo
[OHOS INFO] product path: /home/xxxx/openharmony_w800/vendor/hihope/neptune_iotlink_demo
[OHOS INFO] device path: /home/xxxx/openharmony_w800/device/board/hihope/neptune100/liteos_m
[OHOS INFO] device company: hihope
至此,预编译适配完成,但工程还不能执行hb build进行编译,还需要准备好后续的LiteOS-M内核移植。
内核移植
Kconfig适配
在kernel/liteos_m
的编译中,需要在相应的单板以及SoC目录下使用Kconfig
文件进行索引。
-
在
vendor/hihope/neptune_iotlink_demo
目录下创建kernel_configs目录,并创建debug.config
空文件。 -
打开
kernel/liteos_m/Kconfig
文件,可以看到在该文件通过orsource命令导入了device/board
和device/soc
下多个Kconfig
文件,后续需要创建并修改这些文件:orsource "../../device/board/*/Kconfig.liteos_m.shields" orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.defconfig.boards" orsource "../../device/board/$(BOARD_COMPANY)/Kconfig.liteos_m.boards" orsource "../../device/soc/*/Kconfig.liteos_m.defconfig" orsource "../../device/soc/*/Kconfig.liteos_m.series" orsource "../../device/soc/*/Kconfig.liteos_m.soc"
-
在
device/board/hihope
下创建相应的的Kconfig
文件:├── neptune100 --- neptune100单板配置目录 │ ├── Kconfig.liteos_m.board --- 单板的配置选项 │ ├── Kconfig.liteos_m.defconfig.board --- 单板的默认配置项 │ └── liteos_m │ └── config.gni --- 单板的配置文件 ├── Kconfig.liteos_m.boards --- 单板厂商下Boards配置信息 └── Kconfig.liteos_m.defconfig.boards --- 单板厂商下Boards默认配置信息
-
修改
Board
目录下Kconfig
文件内容:在
neptune100/Kconfig.liteos_m.board
中添加,config BOARD_NEPTUNE100bool "select board neptune100"depends on SOC_WM800
配置只有SOC_WM800被选后,BOARD_NEPTUNE100才可被选。
在
neptune100/Kconfig.liteos_m.defconfig.board
中添加,if BOARD_NEPTUNE100endif #BOARD_NEPTUNE100
用于添加 BOARD_NEPTUNE100默认配置
-
在
device/soc/winnermicro
下创建相应的的Kconfig
文件:├── wm800 --- W800系列 │ ├── Kconfig.liteos_m.defconfig.wm800 --- W800芯片默认配置 │ ├── Kconfig.liteos_m.defconfig.series --- W800系列默认配置 │ ├── Kconfig.liteos_m.series --- W800系列配置 │ └── Kconfig.liteos_m.soc --- W800芯片配置 ├── Kconfig.liteos_m.defconfig --- SoC默认配置 ├── Kconfig.liteos_m.series --- Series配置 └── Kconfig.liteos_m.soc --- SoC配置
-
修改
Soc
目录下Kconfig
文件内容:在
wm800/Kconfig.liteos_m.defconfig.wm800
中添加:config SOCstringdefault "wm800"depends on SOC_WM800
在
wm800/Kconfig.liteos_m.defconfig.series
中添加:if SOC_SERIES_WM800rsource "Kconfig.liteos_m.defconfig.wm800"config SOC_SERIESstringdefault "wm800"endif
在
wm800/Kconfig.liteos_m.series
中添加:config SOC_SERIES_WM800bool "winnermicro 800 Series"select ARMselect SOC_COMPANY_WINNERMICRO --- 选择 SOC_COMPANY_WINNERMICROselect CPU_XT804helpEnable support for winnermicro 800 series
在选择了 SOC_SERIES_WM800之后,才可选
wm800/Kconfig.liteos_m.soc
文件中的 SOC_WM800:choiceprompt "Winnermicro 800 series SoC"depends on SOC_SERIES_WM800config SOC_WM800 --- 选择 SOC_WM800bool "SoC WM800"endchoice
综上所述,要编译单板BOARD_NEPTUNE100,则要分别选中:SOC_COMPANY_WINNERMICRO、SOC_SERIES_WM800、SOC_WM800
-
在
kernel/liteos_m
中执行make menuconfig
进行选择配置,能够对SoC Series进行选择:配置后的文件会默认保存在
vendor/hihope/neptune_iotlink_demo/kernel_configs/debug.config
,也可以直接填写debug.config
:LOSCFG_PLATFORM_QEMU_CSKY_SMARTL=y LOSCFG_SOC_SERIES_WM800=y
模块化编译
Board
和SoC
的编译采用模块化的编译方法,从kernel/liteos_m/BUILD.gn
开始逐级向下递增。本方案的适配过程如下:
-
在
device/board/hihope
中新建文件BUILD.gn
,新增内容如下:if (ohos_kernel_type == "liteos_m") {import("//kernel/liteos_m/liteos.gni")module_name = get_path_info(rebase_path("."), "name")module_group(module_name) {modules = ["neptune100", --- 单板模块"shields",]} }
在上述
BUILD.gn
中,neptune100以及shields即是按目录层级组织的模块名。 -
在
device/soc/winnermicro
中,新建文件BUILD.gn
,按目录层级组织,新增内容如下:if (ohos_kernel_type == "liteos_m") {import("//kernel/liteos_m/liteos.gni")module_name = get_path_info(rebase_path("."), "name")module_group(module_name) {modules = ["hals","wm800",]} }
-
在
device/soc/winnermicro
各个层级模块下,同样新增文件BUILD.gn
,将该层级模块加入编译。以device/soc/winnermicro/wm800/board/platform/sys/BUILD.gn
为例:import("//kernel/liteos_m/liteos.gni") module_name = get_path_info(rebase_path("."), "name") kernel_module(module_name) { --- 编译的模块sources = [ --- 编译的源文件"wm_main.c",]include_dirs = [ --- 模块内使用到的头文件".",] }
-
为了组织链接以及一些编译选项,在
device/soc/winnermicro/wm800/board/BUILD.gn
下的config("board_config")
填入了相应的参数:config("board_config") {ldflags = [] --- 链接参数,包括ld文件libs = [] --- 链接库include_dirs = [] --- 公共头文件
-
为了组织一些产品侧的应用,需要强制链接到产品工程中来,本方案在vendor相应的
config.json
加入了相应的list来组织,在vendor/hihope/neptune_iotlink_demo/config.json
增加对应的list:"bin_list": [ --- demo list{"elf_name": "hihope","enable": "false", --- list开关"force_link_libs": ["bootstrap","broadcast",...]}
将demo应用作为模块库来管理,开启/关闭某个demo,在bin_list中增减相应库文件即可。bin_list在gn中可以直接被读取,在
device/board/hihope/neptune100/liteos_m/config.gni
新增内容:# config.json parse if (product_path != "") {product_conf = read_file("${product_path}/config.json", "json")product_name = product_conf.product_namebin_list = product_conf.bin_list }
读取list后即可在相应的链接选项上加入相关的组件库,在
//device/soc/winnermicro/wm800/BUILD.gn
添加内容:foreach(bin_file, bin_list) {build_enable = bin_file.enable...if(build_enable == "true"){...foreach(force_link_lib, bin_file.force_link_libs) {ldflags += [ "-l${force_link_lib}" ]}...} }
内核子系统适配
在vendor/hihope/neptune_iotlink_demo/config.json
添加内核子系统及相关配置,如下:
"subsystems": [{"subsystem": "kernel","components": [{ "component": "liteos_m", "features":[] }]
},
内核启动适配
由于Neptune100开发板的芯片架构为OpenHarmony不支持的ck804ef架构,需要进行ck804ef架构移植。适配 kernel\liteos_m\arch\include
中定义的通用的文件以及函数列表,并放在了 kernel\liteos_m\arch\csky\v2\ck804\gcc
文件夹下。
内核初始化示例如下:
osStatus_t ret = osKernelInitialize(); --- 内核初始化
if(ret == osOK)
{threadId = osThreadNew((osThreadFunc_t)sys_init,NULL,&g_main_task); --- 创建init线程if(threadId!=NULL){osKernelStart(); --- 线程调度}
}
board_main在启动OHOS_SystemInit之前,需要初始化必要的动作,如下:
...
UserMain(); --- 启动OpenHarmony OHOS_SystemInit的之前完成驱动的初始化
...
OHOS_SystemInit(); --- 启动OpenHarmony服务,以及组件初始化
...
UserMain函数在device/soc/winnermicro/wm800/board/app/main.c
文件中,如下:
...
if (DeviceManagerStart()) { --- HDF初始化printf("[%s] No drivers need load by hdf manager!",__func__);
}
...
HDF驱动框架适配
HDF驱动框架提供了一套应用访问硬件的统一接口,可以简化应用开发,添加HDF组件需要在//vendor/hihope/neptune_iotlink_demo/kernel_configs
添加:
LOSCFG_DRIVERS_HDF=y
LOSCFG_DRIVERS_HDF_PLATFORM=y
驱动适配相关文件放置在drivers/adapter/platform
中,对应有gpio,i2c,pwm,spi,uart,watchdog,都是通过HDF机制加载,本章节以GPIO和UART为例进行详细说明。
GPIO适配
-
芯片驱动适配文件位于
drivers/adapter/platform
目录,在gpio目录增加gpio_wm.c
文件,在BUILD.gn
文件中,描述了W800驱动的编译适配。如下:... if (defined(LOSCFG_SOC_COMPANY_WINNERMICRO)) {sources += [ "gpio_wm.c" ] } ...
-
gpio_wm.c
中驱动描述文件如下:/* HdfDriverEntry definitions */ struct HdfDriverEntry g_GpioDriverEntry = {.moduleVersion = 1,.moduleName = "WM_GPIO_MODULE_HDF",.Bind = GpioDriverBind,.Init = GpioDriverInit,.Release = GpioDriverRelease, }; HDF_INIT(g_GpioDriverEntry);
-
在
device/board/hihope/shields/neptune100/neptune100.hcs
添加gpio硬件描述信息, 添加内容如下:root {platform {gpio_config {match_attr = "gpio_config";groupNum = 1;pinNum = 48;}} }
-
在GpioDriverInit获取hcs参数进行初始化,如下:
...gpioCntlr = GpioCntlrFromHdfDev(device); --- gpioCntlr节点变量获取具体gpio配置if (gpioCntlr == NULL) {HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");return HDF_DEV_ERR_NO_DEVICE_SERVICE;}...
UART适配
-
芯片驱动适配文件位于
drivers/adapter/platform
目录,在uart目录增加uart_wm.c
文件,在BUILD.gn
文件中,描述了W800驱动的编译适配。如下:... if (defined(LOSCFG_SOC_COMPANY_WINNERMICRO)) {sources += [ "uart_wm.c" ] } ...
-
uart_wm.c
中驱动描述文件如下:/* HdfDriverEntry definitions */ struct HdfDriverEntry g_UartDriverEntry = {.moduleVersion = 1,.moduleName = "W800_UART_MODULE_HDF",.Bind = UartDriverBind,.Init = UartDriverInit,.Release = UartDriverRelease, };/* Initialize HdfDriverEntry */ HDF_INIT(g_UartDriverEntry);
-
在
device/board/hihope/shields/neptune100/neptune100.hcs
添加uart硬件描述信息, 添加内容如下:root {platform {uart_config {/*uart0 {match_attr = "uart0_config";num = 0;baudrate = 115200;parity = 0;stopBit = 1;data = 8;}*/uart1 {match_attr = "uart1_config";num = 1;baudrate = 115200;parity = 0;stopBit = 1;data = 8;}}} }
-
在UartDriverInit获取hcs参数进行初始化,如下:
...host = UartHostFromDevice(device);if (host == NULL) {HDF_LOGE("%s: host is NULL", __func__);return HDF_ERR_INVALID_OBJECT;}...
OpenHarmony子系统适配
子系统的编译选项入口在相应产品config.json
下,如:vendor/hihope/neptune_iotlink_demo/config.json
。
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的编译目标]
},
在本案例中,wifi
适配源码可见device/soc/winnermicro/wm800/board/src/wifi/wm_wifi.c
,如下:
int tls_wifi_netif_add_status_event(tls_wifi_netif_status_event_fn event_fn) ---用于增加wifi事件功能
{u32 cpu_sr;struct tls_wifi_netif_status_event *evt;//if exist, remove from event list first.tls_wifi_netif_remove_status_event(event_fn);evt = tls_mem_alloc(sizeof(struct tls_wifi_netif_status_event));if(evt==NULL)return -1;memset(evt, 0, sizeof(struct tls_wifi_netif_status_event));evt->status_callback = event_fn;cpu_sr = tls_os_set_critical();dl_list_add_tail(&wifi_netif_status_event.list, &evt->list);tls_os_release_critical(cpu_sr);return 0;
}
系统服务管理子系统适配
系统服务管理子系统适配添加samgr_lite
部件,直接在config.json
配置,如下:
{"subsystem": "systemabilitymgr","components": [{"component": "samgr_lite"}]
},
公共基础库子系统适配
公共基础库子系统适配添加了kv_store、file
部件,直接在config.json
配置,如下:
{"subsystem": "utils","components": [{"component": "kv_store","features": ["enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true"]},{ "component": "file", "features":[] }]
},
适配kv_store
部件时,键值对会写到文件中。在轻量系统中,文件操作相关接口有POSIX
接口与HalFiles
接口这两套实现。 因为对接内核的文件系统,采用POSIX
相关的接口,所以features
需要增加enable_ohos_utils_native_lite_kv_store_use_posix_kv_api = true
。
启动恢复子系统适配
启动恢复子系统适配添加了bootstrap_lite、syspara_lite
部件,直接在config.json
配置,如下:
{"subsystem": "startup","components": [{"component": "bootstrap_lite"},{"component": "syspara_lite","features": ["enable_ohos_startup_syspara_lite_use_posix_file_api = true","config_ohos_startup_syspara_lite_data_path = \"/data/\""]}]
},
适配bootstrap_lite部件时,需要在链接脚本文件device/soc/winnermicro/wm800/board/ld/w800/gcc_csky.ld
中手动新增如下段:
.zinitcall_array :
{. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_core_start = .);KEEP (*(SORT(.zinitcall.core*)))KEEP (*(.zinitcall.core*))PROVIDE_HIDDEN (__zinitcall_core_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_device_start = .);KEEP (*(SORT(.zinitcall.device*)))KEEP (*(.zinitcall.device*))PROVIDE_HIDDEN (__zinitcall_device_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_bsp_start = .);KEEP (*(SORT(.zinitcall.bsp*)))KEEP (*(.zinitcall.bsp*))PROVIDE_HIDDEN (__zinitcall_bsp_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_sys_service_start = .);KEEP (*(SORT(.zinitcall.sys.service*)))KEEP (*(.zinitcall.sys.service*))PROVIDE_HIDDEN (__zinitcall_sys_service_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_app_service_start = .);KEEP (*(SORT(.zinitcall.app.service*)))KEEP (*(.zinitcall.app.service*))PROVIDE_HIDDEN (__zinitcall_app_service_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_sys_feature_start = .);KEEP (*(SORT(.zinitcall.sys.feature*)))KEEP (*(.zinitcall.sys.feature*))PROVIDE_HIDDEN (__zinitcall_sys_feature_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_app_feature_start = .);KEEP (*(SORT(.zinitcall.app.feature*)))KEEP (*(.zinitcall.app.feature*))PROVIDE_HIDDEN (__zinitcall_app_feature_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_run_start = .);KEEP (*(SORT(.zinitcall.run*)))KEEP (*(.zinitcall.run*))PROVIDE_HIDDEN (__zinitcall_run_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_test_start = .);KEEP (*(SORT(.zinitcall.test*)))KEEP (*(.zinitcall.test*))PROVIDE_HIDDEN (__zinitcall_test_end = .);. = ALIGN(0x4) ;PROVIDE_HIDDEN (__zinitcall_exit_start = .);KEEP (*(SORT(.zinitcall.exit*)))KEEP (*(.zinitcall.exit*))PROVIDE_HIDDEN (__zinitcall_exit_end = .);
} > REGION_RODATA
需要新增上述段是因为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/hihope/neptune_iotlink_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/neptune100/neptune_iotlink_demo/libs
生成 libbootstrap.a
,如下:
static_library("bootstrap") {sources = ["bootstrap_service.c","system_init.c",]...
适配syspara_lite
部件时,系统参数会最终写到文件中进行持久化保存。在轻量系统中,文件操作相关接口有POSIX接口与HalFiles接口这两套实现。
因为对接内核的文件系统,采用POSIX相关的接口,所以features字段中需要增加enable_ohos_startup_syspara_lite_use_posix_file_api = true
。
XTS子系统适配
XTS子系统的适配,直接在config.json
中加入组件选项:
{"subsystem": "xts","components": [{ "component": "xts_acts","features":["config_ohos_xts_acts_utils_lite_kv_store_data_path = \"/data\"","enable_ohos_test_xts_acts_use_thirdparty_lwip = true"]},{ "component": "xts_tools", "features":[] }]
}
另外,XTS功能也使用了list来组织,在config.json
文件中增减相应模块:
"bin_list": [{"enable": "true","force_link_libs": ["module_ActsParameterTest","module_ActsBootstrapTest","module_ActsDfxFuncTest","module_ActsHieventLiteTest","module_ActsSamgrTest","module_ActsUtilsFileTest","module_ActsKvStoreTest","module_ActsWifiServiceTest"]}
],
其它组件的适配过程与官方以及其它厂商的过程类似,不再赘述。
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
鸿蒙(HarmonyOS NEXT)最新学习路线
-
HarmonOS基础技能
- HarmonOS就业必备技能
- HarmonOS多媒体技术
- 鸿蒙NaPi组件进阶
- HarmonOS高级技能
- 初识HarmonOS内核
- 实战就业级设备开发
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
《鸿蒙 (OpenHarmony)开发入门教学视频》
《鸿蒙生态应用开发V2.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
- ArkTS语言
- 安装DevEco Studio
- 运用你的第一个ArkTS应用
- ArkUI声明式UI开发
- .……
《鸿蒙开发进阶》
- Stage模型入门
- 网络管理
- 数据管理
- 电话服务
- 分布式应用开发
- 通知与窗口管理
- 多媒体技术
- 安全技能
- 任务管理
- WebGL
- 国际化开发
- 应用测试
- DFX面向未来设计
- 鸿蒙系统移植和裁剪定制
- ……
《鸿蒙进阶实战》
- ArkTS实践
- UIAbility应用
- 网络案例
- ……
获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。
相关文章:

OpenHarmony实战:Combo解决方案之W800芯片移植案例
本方案基于OpenHarmony LiteOS-M内核,使用联盛德W800芯片的润和软件海王星系列Neptune100开发板,进行开发移植。 移植架构采用Board与SoC分离方案,支持通过Kconfig图形化配置编译选项,增加玄铁ck804ef架构移植,实现了…...

【数据结构】数组(稀疏矩阵、特殊矩阵压缩、矩阵存储、稀疏矩阵的快速转置、十字链表)
稀疏矩阵、矩阵压缩、稀疏矩阵的快速转置、十字链表 目录 稀疏矩阵、矩阵压缩、稀疏矩阵的快速转置、十字链表1.数组2.数组的顺序表示和实现3.特殊矩阵的压缩存储(1). 上三角矩阵—列为主序压缩存储(2). 下三角矩阵—**行为主序压…...

nginx 配置访问地址和解决跨域问题(反向代理)
1、配置访问地址(通过ip访问) //配置ip访问地址 location ^~/auditApp{alias /usr/local/front-apps/cbd/auditApp;index index.html;if (!-e $request_filename) {rewrite ^/(.*) /auditApp/index.html last;break;}} 2、解决跨域问题&…...

支持向量机(SVM)白话之个人理解(学习记录)
本文仅有文字理解部分,没有相应的数学公式推导过程,便于新手理解。 一、什么是支持向量机 首先我们看下面这张图,在图中圆形和三角形分别代表不同的数据类型,如何画出一条直线使两者能够显著地区分开来呢? 答案可以多…...

【运输层】TCP 的可靠传输是如何实现的?
目录 1、发送和接收窗口(滑动窗口) (1)滑动窗口的工作流程 (2)滑动窗口和缓存的关系 (3)滑动窗口的注意事项 2、如何选择超时重传时间 (1)加权平均往返…...

K8s技术全景:架构、应用与优化
一、介绍 Kubernetes的历史和演进 Kubernetes(简称K8s)是一个开源的容器编排系统,用于自动化应用程序的部署、扩展和管理。它最初是由Google内部的Borg系统启发并设计的,于2014年作为开源项目首次亮相。 初始阶段 Kubernetes的诞生…...
Java的异常机制
异常机制 三种类型 检查型异常:程序员无法预见的运行时异常:在编译时会被忽略错误ERROR:错误在代码中被忽略,在编译时检查不到 异常处理机制 抛出异常捕获异常异常处理的五个关键字:try,catchÿ…...

考虑预同步的虚拟同步机T型三电平逆变器并离网MATLAB仿真模型
微❤关注“电气仔推送”获得资料(专享优惠) 模型简介 三相 T 型三电平逆变器电路如图所示,逆变器主回路由三个单相 T 型逆变器组成。 直流侧输入电压为 UPV,直流侧中点电位 O 设为零电位,交流侧输出侧是三相三线制连…...
记一次k8s取证检材过期的恢复
复盘盘古石k8s的时候碰到了证书过期的问题,在此记录解决方法 报错信息:192.168.91.171:6443 was refused - did you specify the right host or port? 查看证书是否过期 kubeadm alpha certs check-expiration或 openssl x509 -in /etc/kubernetes/…...

【网站项目】自助购药小程序
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...

Ubuntu22.04修改默认窗口系统为X11
Ubuntu22.04安装默认窗口系统为Wayland(通过设置->关于可以看到)。 一、用Ubuntu on Xorg会话登录 用户登录时,点“未列出”,输入用户名后,在登录界面底部的齿轮图标中,选择 "Ubuntu on Xorg&quo…...
延时队列实现实战:如何利用 RabbitMQ 实现延时队列,以满足特定延迟处理需求
实现延时队列,可以通过RabbitMQ的死信队列(Dead-letter queue)特性,“死信队列”是当消息过期,或者队列达到最大长度时,未消费的消息会被加入到死信队列。然后,我们可以对死信队列中的消息进行消…...
关于在Ubuntu上配置mysql踩的一些坑
最近准备换工作了,回顾了下学校时期做的那个webserver,又在linux下mysql踩了一些坑,特此记录下来 程序编译错误mysql.h: No such file or directory 云服务器缺少mysql必要的运行组件,安装: sudo apt-get install l…...

JSBridge原理 - 前端H5与客户端Native交互
1. 概述: 在混合应用开发中,一种常见且成熟的技术方案是将原生应用与 WebView 结合,使得复杂的业务逻辑可以通过网页技术实现。实现这种类型的混合应用时,就需要解决H5与Native之间的双向通信。JSBridge 是一种在混合应用中实现 …...

【Java EE】Spring请求如何传递参数详解
文章目录 🎍传递单个参数🌴传递多个参数🍀传递对象🎄后端参数重命名(后端参数映射)🌲传递数组🎍传递集合🌴传递JSON数据🌸JSON概念🌸JSON的语法&a…...
菜鸟笔记-Numpy常用函数用法汇总
NumPy(Numerical Python的简称)是Python中用于处理数组和矩阵的库,提供了大量的数学函数来操作这些数组。通过前面的学习,慢慢也能发现一些规律,以下是NumPy的一些常用函数及其用法汇总: 数组创建 numpy.a…...

tensorflow.js 如何使用opencv.js通过面部特征点估算脸部姿态并绘制示意图
文章目录 前言一、实现步骤1. 获取所需特征点的索引2. 使用opencv.js 计算俯仰角、水平角和翻滚角cv.solvePnP介绍cv.solvePnP原理运行代码查看效果 3.绘制姿态示意直线添加canvas元素计算姿态直线坐标并绘制 总结 前言 在计算机视觉领域,估算脸部姿态是一项具有挑…...
Linux命令-dpkg-divert命令(Debian Linux中创建并管理一个转向列表)
说明 dpkg-divert命令 是Debian Linux中创建并管理一个转向(diversion)列表,其使得安装文件的默认位置失效的工具。 语法 dpkg-divert(选项)(参数)选项 --add:添加一个转移文件; --remove:删除一个转移…...
flex: 1 是哪些属性的缩写?
flex:1是哪些属性的缩写? flex:1 是 flex-grow: 1, flex-shrink: 1,flex-basis: 0% 的缩写; 解释下flex-grow flex-grow是将剩余的空间,根据flex-grow的值平分,然后加到flex-basis上 <!doctype html> <htm…...

python基于opencv实现数籽粒
千粒重是一个重要的农艺性状,通过对其的测量和研究,我们可以更好地理解作物的生长状况,优化农业生产,提高作物产量和品质。但数籽粒数目是一个很繁琐和痛苦的过程,我们现在用一个简单的python程序来数水稻籽粒。代码的…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...