不是鸿蒙 ArkUI 不会写,而是 Flutter 更有性价比

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

遇到这个错误,请将你 sdkdependencies 中的文件复制到

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-enginesrc 下面 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.stampflutter_tools.snapshot, 执行 flutter doctor 命令,重新编译 flutter_tools
  • 增加环境变量 FLUTTER_OHOS_ENGINE 指向本地引擎的 src 目录。
  1. linux,macos

export FLUTTER_OHOS_ENGINE=/Users/xxx/Documents/ohos/flutter/engine/src

  1. windows

这样子就会根据你运行的模式自己设置本地引擎的参数了。

签名

如果在真机上面运行,需要签名。之前是使用工具进行签名的,但是对于需要频繁切换项目的情况下,不方便,我们可以使用 Deveco Studio 签名,对你想运行的项目进行签名。流程跟 Flutter Ios 端使用 Xcode 签名相似。

  • Deveco Studio 打开项目的 ohos 目录
  • 单击 File > Project Structure > Project > Signing Configs 界面勾选 Automatically generate signature,等待自动签名完成即可,单击 OK
  • 查看 build-profile.json5 配置信息,配置信息中增加自动签名生成的证书信息。

三方库进度

原生插件库

解决了 Flutter SDK 以及引擎的问题,最大的问题就是原生插件的适配,而社区也给出来适配计划。

社区适配

Flutter三方库适配计划 (qq.com)

社区三方库适配仓库地址:

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) 多达 6694Flutter Plugin,完全靠华为社区,是不现实的,剩下的就是等 Next 全面开放给个人开发者之后,官方和三方社区不断地适配插件了。

  • PlatformView 的状态跟 Flutter 当初开始一样,悬浮在 Flutter 图层之上的,改进方案还要依赖鸿蒙支持外接纹理。

  • 线上引擎也正在开发中,很快大家就不用自己编译引擎和引用本地引擎了。

鸿蒙,爱糖果,欢迎加入Harmony Candies,一起生产可爱的鸿蒙小糖果QQ群:981630644

相关推荐
dr李四维3 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
旭日猎鹰10 分钟前
Flutter踩坑记录(三)-- 更改入口执行文件
flutter
旭日猎鹰10 分钟前
Flutter踩坑记录(一)debug运行生成的项目,不能手动点击运行
flutter
️ 邪神11 分钟前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
雯0609~24 分钟前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ28 分钟前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z33 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
彭世瑜1 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish1 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue