写
ArkUI
是不可能写的,这辈子不可能写ArkUI
的。老板又不加人又不加钱,就只能写Flutter
了,才能维持生活这样子,进FlutterCandies
群感觉像回家一样,在FlutterCandies
的感觉比家里感觉好多了!里面个个都是人才,说话又好听,我超喜欢里面的。
前言
从 Flutter 移植了几个组件到 ArkUI
, 原理跟 Flutter 有很大的不同,开发体验不是很舒适。
不是鸿蒙 ArkUI 不会写,而是 Flutter 更有性价比
而距离 Flutter Love 鸿蒙 - 掘金 (juejin.cn) 已经有一段时间了,我们来看看 Flutter
鸿蒙化的进展如何了。
重要提示,Flutter 鸿蒙化,需要华为提供的真机和最新的SDK或者自己申请了开发者预览 Beta 招募,没有的,暂时不要尝试。
最近 华为纯血鸿蒙 HarmonyOS NEXT 开发者预览版首批 Beta 招募开启,支持 Mate 60 / Pro、X5 机型, 这给一些个人开发者提前体验鸿蒙 NEXT
的机会。
后续内容全部基于 OpenHarmony-SIG/flutter_flutter (gitee.com) 和 OpenHarmony-SIG/flutter_engine (gitee.com) 的 dev 分支。参考文档也以 dev 分支 的文档为准。另外最新支持的是
ohos api11
。
编译引擎
社区已经提供了编译好的 引擎产物下载,如果你不需要时刻跟进问题修复的小伙伴,可以跳过下面的关于编译引擎的内容。
linux
Flutter Love 鸿蒙 - 掘金 (juejin.cn) 是基于在 linux
上面构造的,有一些东西需要补充一下。
wsl
中无法识别设备
如果你使用的是 windows
,并且基于 wsl 2.0
下载安装 usbipd-win
arduino
C:\Windows\System32>usbipd wsl list
BUSID VID:PID DEVICE STATE
2-1 093a:2533 USB 输入设备 Not attached
2-2 12d1:107f HDC Interface, "HDC Device" Not attached
2-3 2717:5013 USB 输入设备 Not attached
2-6 30c9:00a9 Integrated Camera, Integrated IR Camera, APP Mode Not attached
2-10 8087:0033 英特尔(R) 无线 Bluetooth(R) Not attached
用管理员权限启动 cmd
arduino
usbipd wsl attach --busid 2-2
js
C:\Windows\System32>usbipd wsl list
BUSID VID:PID DEVICE STATE
2-1 093a:2533 USB 输入设备 Not attached
2-2 12d1:107f HDC Interface, "HDC Device" Attached - WSL
2-3 2717:5013 USB 输入设备 Not attached
2-6 30c9:00a9 Integrated Camera, Integrated IR Camera, APP Mode Not attached
2-10 8087:0033 英特尔(R) 无线 Bluetooth(R) Not attached
在 wsl
中执行
bash
sudo apt install linux-tools-generic hwdata
sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/*-generic/usbip 20
再执行 lsusb
,可以看到 HDC Device
设备了。
ruby
zmtzawqlp@localhost:~/ohos/flutter/demo/flutter_ohos$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 12d1:107f Huawei Technologies Co., Ltd. "HDC Device"
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
最后执行 sudo chmod -R 777 /dev/bus/usb/
ruby
zmtzawqlp@localhost:~/ohos/flutter/demo/flutter_ohos$ flutter devices
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
2 connected devices:
xxxxxxxxxxx (mobile) • xxxxxxxxxxx • ohos-arm64 • Ohos OpenHarmony-4.x.x.x (API 10)
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.2 LTS 5.15.90.1-microsoft-standard-WSL2
macos
和 Flutter Love 鸿蒙 - 掘金 (juejin.cn) 中的基本一致。
注意一下,命令的区别
js
brew install unzip
brew install npm
brew install cmake
brew install clang
brew install libgtk-3-dev
brew install ninja-build
windows
开发者权限
安装 python
参考官方的 windows
引擎编译的环境
Chromium Docs - Checking out and Building Chromium for Windows (googlesource.com)
Visual Studio
下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux (microsoft.com)
安装之后, 将 Debuging Tools for Windows
也开启。
除了C++ 桌面开发组件,还需要安装下面 2 个。
环境配置
更新引擎
当引擎代码更新的时候,我们需要重新更新引擎代码,并且重新同步。 但是因为引擎代码拉取( gclient sync
)之后会做 git apply
一些 patch
(修改), 所以我们同步之前需要把本地修改先重置掉。
下面是方便更新的脚本,注意这里默认拉取的是 dev
分支。
mac,linux
在 engine
目录下创建 update_engine.sh
文件,把下面内容复制进去。
bash
#!/bin/bash
# 获取所有的 git 项目
git_projects=$(find . -name .git -type d -prune)
# 遍历每个 git 项目并取消本地修改
for project in $git_projects; do
echo "Discarding changes in $project"
(cd "$project/.." && git reset --hard HEAD)
done
call git -C .\src\flutter checkout dev && git -C .\src\flutter pull origin dev
call git -C .\src\flutter log -1
gclient sync
windows
在 engine
目录下创建 update_engine.bat
文件,把下面内容复制进去。
bash
@echo off
REM 输出脚本执行时的目录
echo Current directory: %CD%
REM 获取所有的 git 项目
for /f "tokens=*" %%I in ('dir /s /b /ad .git') do (
echo Discarding changes in %%~dpI
git -C %%~dpI reset --hard HEAD
git -C %%~dpI clean -fd
)
git -C ./src/flutter checkout dev && git -C ./src/flutter pull origin dev
git -C ./src/flutter log -1
gclient sync
问题汇总
python 版本问题
不要安装 python 12 ,有 api 移除了
,不然会出现下面的错误
js
PS D: \ohos \engine> gclient sync Syncing projects: 100%(127/127), done.Running hooks: 16% ( 2/12) Generate sdk/version
running 'python3 src/third_party/dart/tools/generate_sdk_version_file.py' in 'D: \ohos\engine
Traceback (most recent call last):
File "D:\ohos\engine\src\third_party\dart\tools\generate_sdk_version_file.py", line 7, in <module>
import utils
File "D:\ohos \engine \sre\third_party\dart\tools\utils.py", line 13, in <module>
import imp
ModuleNotFoundError: No module named 'imp'
Error: Command 'python3 src/third_party/dart/tools/generate_sdk_version_file.py' returned non-zero exit status 1 in D:\o
hos\engine
Traceback (most recent call last):
File "D:\ohos\engine\src\third_party\dart\tools\generate_sdk_version_file.py",line 7, in <module>
import utils
File "D:\ohos\engine\src\third_party\dart\tools\utils.py", line 13, in <module>
import imp
ModuleNotFoundError: No module named 'imp'
c++ 组件安装
如果出现下面的错误,需要安装以下组件
arduino
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Redist\\MSVC\\14.38.33130\\arm64\\Microsoft.VC143.CRT\\msvcp140.dll'
Executing //build/vs_toolchain.py took 159ms
ERROR at //build/toolchain/win/BUILD.gn:59:3: Script returned non-zero exit code.
exec_script("//build/vs_toolchain.py",
^----------
创建 .npmrc
配置
若~/
目录下未创建.npmrc
配置,构建hap时可能报错:Error: The hvigor depends on the npmrc file. Configure the npmrc file first,届时请在用户目录~
下创建文件.npmrc
,该配置也可参考官方文档,编辑内容如下:
ruby
registry=https://repo.huaweicloud.com/repository/npm/
@ohos:registry=https://repo.harmonyos.com/npm/
手动复制依赖 hvigor
遇到这个错误,请将你 sdk
的 dependencies
中的文件复制到
src\flutter\shell\platform\ohos\flutter_embedding\dependencies
中
perl
flutter\enigne
Hvigor cleaning...
Hvigor installing...
ENOENT ENOENT: no such file or directory, open 'D:\ohos\flutter\enigne\src\flutter\shell\platform\ohos\flutter_embedding\dependencies\hvigor-3.2.1-s.tgz'
手动复制进去
C++ 编译错误
在初始化列表中对类型进行窄化转换的问题。在C++中,窄化转换是指将一个值从较大的类型转换为较小的类型,可能会造成精度丢失或者溢出。
bash
[55/2300] CXX obj/flutter/impeller/renderer/backend/vulkan/vulkan.context_vk.obj
FAILED: obj/flutter/impeller/renderer/backend/vulkan/vulkan.context_vk.obj
ninja -t msvc -e environment.arm64 -- ../../buildtools/windows-x64/clang/bin/clang-cl.exe /nologo /showIncludes @obj/flutter/impeller/renderer/backend/vulkan/vulkan.context_vk.obj.rsp /c ../../flutter/impeller/renderer/backend/vulkan/context_vk.cc /Foobj/flutter/impeller/renderer/backend/vulkan/vulkan.context_vk.obj /Fdobj/flutter/impeller/renderer/backend/vulkan/vulkan_cc.pdb
../../flutter/impeller/renderer/backend/vulkan/context_vk.cc(41,58): error: non-constant-expression cannot be narrowed from type 'VkDebugUtilsMessageSeverityFlagBitsEXT' to 'impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT' in initializer list [-Wc++11-narrowing]
impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT{severity});
^~~~~~~~
1 error generated.
[72/2300] CXX obj/flutter/impeller/compiler/compiler_lib.reflector.obj
ninja: build stopped: subcommand failed.
到这个文件中src\flutter\impeller\renderer\backend\vulkan\context_vk.cc
添加以下注解
#pragma clang diagnostic ignored "-Wc++11-narrowing"
运行调试
设置本地引擎
我们可以通过下面三种方法在运行调试项目的时候,设置我们编译出来的引擎。
launch.json
通过 vscode
我们可以创建 launch.json
.
其中 --local-engine-src-path
是你编译出来引擎目录下面 src
的路径。
--local-engine
是 src
下面 out
文件夹中
json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ohos_demo",
"request": "launch",
"type": "dart",
"args": [
"--local-engine-src-path",
"/Users/xxx/Documents/ohos/flutter/engine/src",
"--local-engine",
"ohos_debug_unopt_arm64",
]
},
{
"name": "ohos_demo (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile",
"args": [
"--local-engine-src-path",
"/Users/xxx/Documents/ohos/flutter/engine/src",
"--local-engine",
"ohos_profile_arm64",
]
},
{
"name": "ohos_demo (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release",
"args": [
"--local-engine-src-path",
"/Users/xxx/Documents/ohos/flutter/engine/src",
"--local-engine",
"ohos_release_arm64",
]
}
]
}
缺点每个项目都需要创建一个,并且只能点击这里的按钮启动。
命令
直接使用命令运行,当然也需要配置参数。
flutter run --local-engine-src-path /Users/xxx/Documents/ohos/flutter/engine/src --local-engine ohos_debug_unopt_arm64
修改 flutter_tools 的流程
- 创建一个
ohos_local_engine.patch
文件,将下面的内容复制到里面去。
diff
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
index 28dc9f587a..bf94f57750 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:io';
+
import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:completion/completion.dart';
@@ -172,7 +174,54 @@ class FlutterCommandRunner extends CommandRunner<void> {
}
}
- return super.run(args);
+ ArgResults argResults = super.parse(args);
+
+ var ohosArgs = <String>[];
+ // 没有设置过本地引擎
+ if (!args.contains('--local-engine-src-path') &&
+ !args.contains('--local-engine')) {
+ final String? flutterOhosEngine =
+ Platform.environment['FLUTTER_OHOS_ENGINE'];
+
+ print('FLUTTER_OHOS_ENGINE -----$flutterOhosEngine');
+ if (flutterOhosEngine != null) {
+ Directory outDirectory = globals.fs
+ .directory(globals.fs.path.join(flutterOhosEngine, 'out'));
+ var buildMode = 'debug';
+ var command = argResults.command;
+ if (command != null) {
+ if (command.options.contains('release') &&
+ command['release'] == true) {
+ buildMode = 'release';
+ } else if (command.options.contains('profile') &&
+ command['profile'] == true) {
+ buildMode = 'profile';
+ }
+ }
+ var localEngine = '';
+ if (outDirectory.existsSync()) {
+ for (final FileSystemEntity file in outDirectory.listSync()) {
+ if (file is Directory && file.basename.contains(buildMode)) {
+ localEngine = file.basename;
+ }
+ }
+ }
+ if (localEngine.isNotEmpty) {
+ ohosArgs = [
+ '--local-engine-src-path',
+ flutterOhosEngine,
+ '--local-engine',
+ localEngine,
+ ];
+ print('自动设置本地引擎位\n${ohosArgs.join('\n')}');
+ }
+ }
+ }
+
+ return super.run(<String>[
+ ...ohosArgs,
+ ...args,
+ ]);
}
@override
- 到你本地
Flutter SDK
的目录中去,执行git apply ohos_local_engine.patch
。 - 删除
Flutter SDK
目录下面bin\cache
中的flutter_tools.stamp
和flutter_tools.snapshot
, 执行flutter doctor
命令,重新编译flutter_tools
。 - 增加环境变量
FLUTTER_OHOS_ENGINE
指向本地引擎的src
目录。
- linux,macos
export FLUTTER_OHOS_ENGINE=/Users/xxx/Documents/ohos/flutter/engine/src
- windows
这样子就会根据你运行的模式自己设置本地引擎的参数了。
签名
如果在真机上面运行,需要签名。之前是使用工具进行签名的,但是对于需要频繁切换项目的情况下,不方便,我们可以使用 Deveco Studio
签名,对你想运行的项目进行签名。流程跟 Flutter Ios
端使用 Xcode
签名相似。
- 用
Deveco Studio
打开项目的ohos
目录 - 单击
File > Project Structure > Project > Signing Configs
界面勾选Automatically generate signature
,等待自动签名完成即可,单击OK
。 - 查看
build-profile.json5
配置信息,配置信息中增加自动签名生成的证书信息。
三方库进度
原生插件库
解决了 Flutter SDK
以及引擎的问题,最大的问题就是原生插件的适配,而社区也给出来适配计划。
社区适配
社区三方库适配仓库地址:
OpenHarmony-SIG/flutter_packages (gitee.com)
仓库名 | 依赖路径 | 类型 |
---|---|---|
pigeon | packages/pigeons | 工具库 |
file_selector | packages/file_selector/file_selector | 插件 |
image_picker | packages/image_picker/image_picker | 插件 |
animations | packages/animations | 新增示例 |
url_launcher | packages/url_launcher/url_launcher | 插件 |
shared_preferences | packages/shared_preferences/shared_preferences | 插件 |
path_provuder | packages/path_provuder/path_provuder | 插件 |
local_auth | packages/local_auth/local_auth | 插件 |
device_info_plus_ohos
device_info_plus
在 OpenHarmony 平台的实现。
yaml
dependencies:
device_info_plus: any
device_info_plus_ohos: any
package_info_plus_ohos
package_info_plus
在 OpenHarmony 平台的实现。
yaml
dependencies:
package_info_plus: 4.2.0
package_info_plus_ohos: any
纯 Flutter 组件库
除了插件,有一些三方库也需要做适配,因为一些库里面有对平台的判断,比如主题样式。
yaml
dependencies:
extended_text: 10.0.1-ohos
extended_text_field: 11.0.1-ohos
结语
总体来说,Flutter
鸿蒙化已经解决了大部分的问题。
-
目前 Search results for is:plugin (flutter-io.cn) 多达
6694
的Flutter Plugin
,完全靠华为社区,是不现实的,剩下的就是等Next
全面开放给个人开发者之后,官方和三方社区不断地适配插件了。 -
PlatformView
的状态跟Flutter
当初开始一样,悬浮在Flutter
图层之上的,改进方案还要依赖鸿蒙支持外接纹理。 -
线上引擎也正在开发中,很快大家就不用自己编译引擎和引用本地引擎了。
爱 鸿蒙
,爱糖果
,欢迎加入Harmony Candies,一起生产可爱的鸿蒙小糖果QQ群:981630644