@ohos-cpf/3rdloop 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cli.js +2 -2
- package/package.json +1 -1
- package/vendor/Server/Routes/controllers/LoopEngineController.js +36 -3
- package/vendor/Server/Routes/controllers/OrchestratorController.js +193 -9
- package/vendor/Server/Skills/flutter-build-test/SKILL.md +252 -0
- package/vendor/Server/Skills/flutter-build-test/assets/BUILDENV_TEMPLATE.md +42 -0
- package/vendor/Server/Skills/flutter-build-test/assets/BUILD_REPORT_TEMPLATE.md +64 -0
- package/vendor/Server/Skills/flutter-build-test/assets/README_SECTION_TEMPLATE.md +78 -0
- package/vendor/Server/Skills/flutter-build-test/references/BUILD_TROUBLESHOOTING.md +128 -0
- package/vendor/Server/Skills/flutter-build-test/references/DOC_UPDATE_GUIDE.md +119 -0
- package/vendor/Server/Skills/flutter-build-test/references/FLVM_GUIDE.md +89 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/build-matrix.cjs +374 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/locate-example.cjs +189 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/update-buildenv.cjs +171 -0
- package/vendor/Server/Skills/flutter-code-use/SKILL.md +316 -0
- package/vendor/Server/Skills/flutter-code-use/references/event-channel.md +440 -0
- package/vendor/Server/Skills/flutter-code-use/references/federated.md +295 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-binding-translate.md +130 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-compile-from-source.md +169 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-fetch-at-build.md +161 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-prebuilt-bundle.md +175 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-rhttp-guide.md +235 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-rust-cross-compile.md +514 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi.md +220 -0
- package/vendor/Server/Skills/flutter-code-use/references/method-channel.md +643 -0
- package/vendor/Server/Skills/flutter-code-use/references/monorepo.md +188 -0
- package/vendor/Server/Skills/flutter-code-use/references/ohos-api-pitfalls.md +717 -0
- package/vendor/Server/Skills/flutter-code-use/references/platform-view.md +448 -0
- package/vendor/Server/Skills/flutter-code-use/references/pure-dart.md +180 -0
- package/vendor/Server/Skills/flutter-code-use/references/texture.md +459 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/SKILL.md +270 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/assets/PAGE_TEMPLATES.md +544 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/CODE_STANDARDS.md +328 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/DEMO_DOC_PARSING.md +126 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/EXAMPLES.md +629 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/scripts/validate-flutter-demo.cjs +268 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/SKILL.md +227 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/assets/DEMO_DOC_TEMPLATE.md +78 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/COVERAGE_REPORT_PARSING.md +174 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/EXAMPLES.md +162 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/MCP_TOOL_GUIDE.md +123 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/OUTPUT_FORMAT.md +190 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/QUALITY_CHECKLIST.md +83 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/scripts/validate-skill.cjs +259 -0
- package/vendor/Server/Skills/flutter-library-demo-coverage/SKILL.md +175 -0
- package/vendor/VERSION +3 -3
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# FFI Strategy: fetch_at_build
|
|
2
|
+
|
|
3
|
+
## 适用条件
|
|
4
|
+
|
|
5
|
+
原生 `.so` 不在仓库内,而是在构建期通过 Gradle 脚本、cargokit hook、自定义 build.dart 脚本或其他下载机制从外部获取。
|
|
6
|
+
|
|
7
|
+
信号特征:
|
|
8
|
+
- `android/build.gradle` 中有 `download` / `fetch` / URL 下载逻辑
|
|
9
|
+
- `cargokit/build_tool/` 中有动态获取逻辑
|
|
10
|
+
- `tool/` 目录下有 build helper 脚本
|
|
11
|
+
- `pubspec.yaml` 中有 `build.yaml` 或自定义 builder
|
|
12
|
+
|
|
13
|
+
## 工程搭建
|
|
14
|
+
|
|
15
|
+
### 1. 创建 ohos 工程
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
flutter create -t plugin_ffi --platforms ohos .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. 分析原有获取机制
|
|
22
|
+
|
|
23
|
+
梳理原插件在 Android/iOS 上获取 `.so` 的方式:
|
|
24
|
+
|
|
25
|
+
| 获取方式 | OHOS 适配思路 |
|
|
26
|
+
|----------|-------------|
|
|
27
|
+
| Gradle download task | 改写为 CMake `file(DOWNLOAD ...)` 或预下载脚本 |
|
|
28
|
+
| cargokit build_tool | 扩展 cargokit 支持 OHOS target |
|
|
29
|
+
| build.dart + http | 在 `ohos/CMakeLists.txt` 中用 `execute_process` 调用下载 |
|
|
30
|
+
| GitHub Release 下载 | 确认是否有 arm64 版本可用 |
|
|
31
|
+
| 自定义 CI/CD | 本地预下载后放入 `ohos/src/main/cpp/libs/` |
|
|
32
|
+
|
|
33
|
+
### 3. CMakeLists.txt 中嵌入下载逻辑(推荐)
|
|
34
|
+
|
|
35
|
+
```cmake
|
|
36
|
+
cmake_minimum_required(VERSION 3.13)
|
|
37
|
+
project(xxx_library)
|
|
38
|
+
|
|
39
|
+
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
|
40
|
+
|
|
41
|
+
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH})
|
|
42
|
+
set(LIB_URL "https://example.com/path/to/libxxx-arm64.so")
|
|
43
|
+
|
|
44
|
+
if(NOT EXISTS ${LIB_DIR}/libxxx.so) # ← 重命名后的 .so(必须无 soname 版本号后缀)
|
|
45
|
+
file(MAKE_DIRECTORY ${LIB_DIR})
|
|
46
|
+
message(STATUS "Downloading native library from ${LIB_URL}")
|
|
47
|
+
file(DOWNLOAD ${LIB_URL} ${CMAKE_BINARY_DIR}/libxxx_download.zip SHOW_PROGRESS)
|
|
48
|
+
execute_process(
|
|
49
|
+
COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_BINARY_DIR}/libxxx_download.zip
|
|
50
|
+
WORKING_DIRECTORY ${LIB_DIR}
|
|
51
|
+
)
|
|
52
|
+
# 重命名 soname → .so(OHOS 安装器只识别 .so 后缀)
|
|
53
|
+
if(EXISTS "${LIB_DIR}/libxxx.so.2")
|
|
54
|
+
file(RENAME "${LIB_DIR}/libxxx.so.2" "${LIB_DIR}/libxxx.so")
|
|
55
|
+
endif()
|
|
56
|
+
endif()
|
|
57
|
+
|
|
58
|
+
add_library(xxx_ffi SHARED
|
|
59
|
+
${CMAKE_CURRENT_SOURCE_DIR}/dummy.c
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
target_link_libraries(xxx_ffi PUBLIC
|
|
63
|
+
${LIB_DIR}/libxxx.so # ← 重命名后的 .so(必须无 soname 版本号后缀)
|
|
64
|
+
libace_napi.z.so
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
install(FILES ${LIB_DIR}/libxxx.so # ← 文件名必须一致(重命名后的 .so)
|
|
68
|
+
DESTINATION ${CMAKE_INSTALL_PREFIX}/libs/${OHOS_ARCH}
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> **⚠️ build-profile.json5 必须配置**:CMakeLists.txt 不会自动生效。必须在 `ohos/build-profile.json5` 中添加 `externalNativeOptions`(见 `ffi.md` §H「CMakeLists.txt + build-profile.json5 双配置」),否则下载和打包都不会执行。
|
|
73
|
+
|
|
74
|
+
### 4. 或:预下载到仓库(替代方案)
|
|
75
|
+
|
|
76
|
+
如果网络不稳定或下载源不可控,提前下载 `.so` 放入仓库:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
ohos/src/main/cpp/libs/arm64-v8a/libxxx.so
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
此时 CMakeLists.txt 写法与 `prebuilt_bundle` 策略一致。
|
|
83
|
+
|
|
84
|
+
### 5. oh-package.json5
|
|
85
|
+
|
|
86
|
+
```json5
|
|
87
|
+
{
|
|
88
|
+
dependencies: {}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 编码实现
|
|
93
|
+
|
|
94
|
+
### .so 加载路径
|
|
95
|
+
|
|
96
|
+
```dart
|
|
97
|
+
import 'dart:ffi';
|
|
98
|
+
import 'dart:io' show Platform;
|
|
99
|
+
|
|
100
|
+
DynamicLibrary _openLibrary() {
|
|
101
|
+
if (Platform.isAndroid || Platform.isLinux || Platform.isOhos) {
|
|
102
|
+
return DynamicLibrary.open('libxxx.so');
|
|
103
|
+
}
|
|
104
|
+
if (Platform.isIOS || Platform.isMacOS) {
|
|
105
|
+
return DynamicLibrary.process();
|
|
106
|
+
}
|
|
107
|
+
if (Platform.isWindows) {
|
|
108
|
+
return DynamicLibrary.open('xxx.dll');
|
|
109
|
+
}
|
|
110
|
+
throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### pubspec.yaml 平台声明
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
flutter:
|
|
118
|
+
plugin:
|
|
119
|
+
platforms:
|
|
120
|
+
ohos:
|
|
121
|
+
ffiPlugin: true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 常见编译错误与修复
|
|
125
|
+
|
|
126
|
+
### 1. CMake DOWNLOAD 失败
|
|
127
|
+
|
|
128
|
+
网络不可达或 URL 失效。
|
|
129
|
+
修复:手动下载 `.so` 放入 `libs/arm64-v8a/`,改用 `prebuilt_bundle` 模式。
|
|
130
|
+
|
|
131
|
+
### 2. 下载的 .so ABI 不兼容
|
|
132
|
+
|
|
133
|
+
下载的是 x86 或 Android 特定 ABI 版本。
|
|
134
|
+
修复:确认下载 arm64-aarch64 版本,且为标准 Linux ELF 格式。可用 `file libxxx.so` 验证。
|
|
135
|
+
|
|
136
|
+
### 3. cargokit 无法识别 OHOS
|
|
137
|
+
|
|
138
|
+
修复:在 cargokit 的 target/platform 映射中添加 OHOS,或绕过 cargokit 直接提供预编译 `.so`。
|
|
139
|
+
|
|
140
|
+
### 4. 版本不匹配
|
|
141
|
+
|
|
142
|
+
下载的 `.so` 版本与 Dart 绑定期望的 API 版本不一致。
|
|
143
|
+
修复:确认下载 URL 对应的版本号与 Dart 绑定兼容。
|
|
144
|
+
|
|
145
|
+
### 5. 运行时 "Cannot find libxxx.so" 但下载成功
|
|
146
|
+
|
|
147
|
+
Dart 层 `DynamicLibrary.open('libxxx.so')` 失败,但下载的文件实际名为 `libxxx.so.2`(soname)。
|
|
148
|
+
|
|
149
|
+
**根因**:OHOS 安装器只识别 `.so` 后缀的文件,`.so.2` 等带版本号的文件在安装到设备时会被丢弃。
|
|
150
|
+
|
|
151
|
+
修复:
|
|
152
|
+
1. 在 CMakeLists.txt 下载/解压后,用 `file(RENAME)` 将 `libxxx.so.N` 重命名为 `libxxx.so`
|
|
153
|
+
2. `install()`、`target_link_libraries()` 和 Dart 层 `DynamicLibrary.open()` 统一使用重命名后的 `libxxx.so`
|
|
154
|
+
3. 清理构建缓存后重新构建
|
|
155
|
+
4. 用 `hdc shell find /data/app/el1/bundle/public/<bundleName> -name '*.so*'` 验证设备上文件是否存在
|
|
156
|
+
|
|
157
|
+
### 6. CMake DOWNLOAD 未执行
|
|
158
|
+
|
|
159
|
+
`build-profile.json5` 缺少 `externalNativeOptions`,CMake 未被调用,下载逻辑不执行。
|
|
160
|
+
|
|
161
|
+
修复:在 `ohos/build-profile.json5` 的 `buildOption` 中添加 `externalNativeOptions`(见 `ffi.md` §H)。
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# FFI Strategy: prebuilt_bundle
|
|
2
|
+
|
|
3
|
+
## 适用条件
|
|
4
|
+
|
|
5
|
+
仓库内无 C/C++ 源码(没有 `src/` 目录下的 `.c` / `.cpp`),仅有预编译 `.so` 文件(通常在 `android/src/main/jniLibs/`、`ios/` 等目录),或有 `.so` 但无对应源码。
|
|
6
|
+
|
|
7
|
+
典型代表:sodium(libsodium 预编译库)。
|
|
8
|
+
|
|
9
|
+
## 工程搭建
|
|
10
|
+
|
|
11
|
+
### 1. 创建 ohos 工程
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
flutter create -t plugin_ffi --platforms ohos .
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. 预编译 .so 准备
|
|
18
|
+
|
|
19
|
+
需要获取或构建 arm64-v8a 版本的 `.so`。来源优先级:
|
|
20
|
+
|
|
21
|
+
1. **仓库内已有 arm64 .so**:直接复用(通常在 `android/src/main/jniLibs/arm64-v8a/`)
|
|
22
|
+
2. **仓库内有其他架构 .so 但无 arm64**:需要用鸿蒙 NDK 重新编译(切换到 `compile_from_source` 策略)
|
|
23
|
+
3. **上游项目提供预编译 .so**:从上游下载 arm64 版本
|
|
24
|
+
4. **自行交叉编译**:从源码编译(切换到 `compile_from_source` 或 `rust_cross_compile`)
|
|
25
|
+
|
|
26
|
+
将 `.so` 放到:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
ohos/src/main/cpp/libs/arm64-v8a/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**⚠️ soname 重命名(必须)**:OHOS 安装器只识别 `.so` 后缀,会丢弃 `.so.2`、`.so.1.1` 等带版本号的文件。如果上游提供的文件名含 soname 后缀(如 `libmpv.so.2`),**必须在 CMakeLists.txt 中重命名为 `libxxx.so`**:
|
|
33
|
+
|
|
34
|
+
```cmake
|
|
35
|
+
# 解压后立即重命名
|
|
36
|
+
if(EXISTS "${LIB_DIR}/libmpv.so.2")
|
|
37
|
+
file(RENAME "${LIB_DIR}/libmpv.so.2" "${LIB_DIR}/libmpv.so")
|
|
38
|
+
endif()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
后续 CMakeLists.txt 的 `target_link_libraries()`、`install()` 和 Dart 层 `DynamicLibrary.open()` 统一使用重命名后的 `libxxx.so`。
|
|
42
|
+
|
|
43
|
+
### 3. CMakeLists.txt 配置(IMPORTED 模式)
|
|
44
|
+
|
|
45
|
+
```cmake
|
|
46
|
+
cmake_minimum_required(VERSION 3.13)
|
|
47
|
+
project(xxx_library)
|
|
48
|
+
|
|
49
|
+
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
|
50
|
+
|
|
51
|
+
set(LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/${OHOS_ARCH})
|
|
52
|
+
|
|
53
|
+
add_library(xxx_ffi SHARED
|
|
54
|
+
${CMAKE_CURRENT_SOURCE_DIR}/dummy.c
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
target_link_libraries(xxx_ffi PUBLIC
|
|
58
|
+
${LIB_DIR}/libxxx.so # ← 重命名后的 .so(必须无 soname 版本号后缀)
|
|
59
|
+
libace_napi.z.so
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
install(FILES ${LIB_DIR}/libxxx.so # ← 文件名必须与上面一致,且为 .so 格式
|
|
63
|
+
DESTINATION ${CMAKE_INSTALL_PREFIX}/libs/${OHOS_ARCH}
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**关键点**:
|
|
68
|
+
- `add_library` 用一个空的 `dummy.c` 作为编译入口
|
|
69
|
+
- 预编译 `.so` 通过 `target_link_libraries` 链接
|
|
70
|
+
- `install` 指令确保 `.so` 被打包到 HAP 的 `libs/arm64-v8a/` 目录
|
|
71
|
+
|
|
72
|
+
> **⚠️ build-profile.json5 必须配置**:CMakeLists.txt 不会自动生效。必须在 `ohos/build-profile.json5` 中添加 `externalNativeOptions`(见 `ffi.md` §H「CMakeLists.txt + build-profile.json5 双配置」),否则 `.so` 不会被打包到 HAR/HAP。
|
|
73
|
+
|
|
74
|
+
### 4. dummy.c
|
|
75
|
+
|
|
76
|
+
如果不存在则创建一个空文件:
|
|
77
|
+
|
|
78
|
+
```c
|
|
79
|
+
// dummy.c - 空编译入口,仅用于 CMake 构建系统
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 5. oh-package.json5
|
|
83
|
+
|
|
84
|
+
```json5
|
|
85
|
+
{
|
|
86
|
+
dependencies: {}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 编码实现
|
|
91
|
+
|
|
92
|
+
### .so 加载路径
|
|
93
|
+
|
|
94
|
+
```dart
|
|
95
|
+
import 'dart:ffi';
|
|
96
|
+
import 'dart:io' show Platform;
|
|
97
|
+
|
|
98
|
+
DynamicLibrary _openLibrary() {
|
|
99
|
+
if (Platform.isAndroid || Platform.isLinux || Platform.isOhos) {
|
|
100
|
+
return DynamicLibrary.open('libxxx.so');
|
|
101
|
+
}
|
|
102
|
+
if (Platform.isIOS || Platform.isMacOS) {
|
|
103
|
+
return DynamicLibrary.process();
|
|
104
|
+
}
|
|
105
|
+
if (Platform.isWindows) {
|
|
106
|
+
return DynamicLibrary.open('xxx.dll');
|
|
107
|
+
}
|
|
108
|
+
throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### pubspec.yaml 平台声明
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
flutter:
|
|
116
|
+
plugin:
|
|
117
|
+
platforms:
|
|
118
|
+
ohos:
|
|
119
|
+
ffiPlugin: true
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### @Native 注解处理
|
|
123
|
+
|
|
124
|
+
预编译库的 Dart 绑定经常使用 `@Native` 注解。**必须**检查并触发 binding-translate 流程(参见 `references/ffi-binding-translate.md`):
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
grep -r '@Native<' lib/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
如有命中,按 `references/ffi-binding-translate.md` 生成 OHOS 旁路 FFI 文件。
|
|
131
|
+
|
|
132
|
+
## 常见编译错误与修复
|
|
133
|
+
|
|
134
|
+
### 1. `dummy.c not found`
|
|
135
|
+
|
|
136
|
+
修复:创建空的 `ohos/src/main/cpp/dummy.c` 文件。
|
|
137
|
+
|
|
138
|
+
### 2. `undefined symbol: xxx` 运行时错误
|
|
139
|
+
|
|
140
|
+
预编译 `.so` 缺少符号或 ABI 不兼容。
|
|
141
|
+
修复:确认 `.so` 是为 aarch64-linux 编译的,且未被 strip 掉必要符号。可用 `nm -D libxxx.so | grep <symbol>` 检查。
|
|
142
|
+
|
|
143
|
+
### 3. `.so` 未被打包到 HAP
|
|
144
|
+
|
|
145
|
+
`install()` 指令缺失或路径不对。
|
|
146
|
+
修复:确认 `install(FILES ...)` 的源路径和 `DESTINATION` 正确。用 `unzip -l <hap>` 检查产物。
|
|
147
|
+
|
|
148
|
+
### 4. 库名不匹配
|
|
149
|
+
|
|
150
|
+
CMakeLists.txt 中的库名与 Dart 层加载名不一致。
|
|
151
|
+
修复:`add_library(xxx_ffi SHARED ...)` 生成的最终产物依赖链接的 `.so` 文件名。Dart 层应 `DynamicLibrary.open('libxxx.so')`(使用实际预编译库名)。
|
|
152
|
+
|
|
153
|
+
### 5. 运行时 "Cannot find libxxx.so" 但 .so 已打包
|
|
154
|
+
|
|
155
|
+
Dart 层 `DynamicLibrary.open('libxxx.so')` 失败,但 `unzip -l <hap>` 显示 `.so` 确实存在——只是文件名是带版本号的 soname(如 `libmpv.so.2`)。
|
|
156
|
+
|
|
157
|
+
**根因**:OHOS 安装器只识别 `.so` 后缀的文件,带版本号后缀的 `.so.2` / `.so.1.1` 等在安装到设备时会被丢弃。
|
|
158
|
+
|
|
159
|
+
**验证**:
|
|
160
|
+
```bash
|
|
161
|
+
hdc shell find /data/app/el1/bundle/public/<bundleName> -name '*.so*'
|
|
162
|
+
```
|
|
163
|
+
如果只看到 `libflutter.so` 和 `libc++_shared.so`,说明预编译库确实被丢弃了。
|
|
164
|
+
|
|
165
|
+
**修复**:
|
|
166
|
+
1. 在 CMakeLists.txt 中,解压/下载后用 `file(RENAME)` 将 `libxxx.so.N` 重命名为 `libxxx.so`
|
|
167
|
+
2. `install(FILES ...)` 和 `target_link_libraries()` 都使用重命名后的 `libxxx.so`
|
|
168
|
+
3. Dart 层 `DynamicLibrary.open('libxxx.so')` 与重命名后的文件名一致
|
|
169
|
+
4. 清理构建缓存后重新构建(`rm -rf ohos/build ohos/.cxx example/ohos/entry/build`)
|
|
170
|
+
|
|
171
|
+
### 6. .so 未被打包且 CMakeLists.txt 正确
|
|
172
|
+
|
|
173
|
+
`build-profile.json5` 缺少 `externalNativeOptions` 配置,CMakeLists.txt 未被调用。
|
|
174
|
+
|
|
175
|
+
修复:在 `ohos/build-profile.json5` 的 `buildOption` 中添加 `externalNativeOptions`(见 `ffi.md` §H)。
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# rhttp 鸿蒙化适配指南
|
|
2
|
+
|
|
3
|
+
> 本文档基于 rhttp 0.12.x 实际适配经验编写,记录了每个关键决策的实际操作路径。按本文档顺序执行可最大化适配成功率。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 一、rhttp 架构概览
|
|
8
|
+
|
|
9
|
+
rhttp 是基于 Rust 的 Flutter HTTP 客户端插件,采用三层架构:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─────────────────────────────────────────────────┐
|
|
13
|
+
│ Dart 层:Rhttp / RhttpClient / Interceptor │ ← 开发者直接使用
|
|
14
|
+
├─────────────────────────────────────────────────┤
|
|
15
|
+
│ FFI 桥接层:flutter_rust_bridge │ ← 自动生成胶水代码
|
|
16
|
+
├─────────────────────────────────────────────────┤
|
|
17
|
+
│ Rust 层:reqwest + rustls + hyper + tokio │ ← 实际执行 HTTP 请求
|
|
18
|
+
└─────────────────────────────────────────────────┘
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**关键依赖链**:`rhttp` → `flutter_rust_bridge` → Rust FFI → `reqwest` → `rustls`/`hyper`/`tokio`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 二、适配决策(基于实战验证)
|
|
26
|
+
|
|
27
|
+
### 2.1 TLS 后端:rustls(已知运行时风险)
|
|
28
|
+
|
|
29
|
+
**不要使用 native-tls**。native-tls 依赖 openssl-sys,编译会直接失败。
|
|
30
|
+
|
|
31
|
+
```toml
|
|
32
|
+
# Cargo.toml
|
|
33
|
+
[dependencies.reqwest]
|
|
34
|
+
version = "0.12"
|
|
35
|
+
default-features = false
|
|
36
|
+
features = [
|
|
37
|
+
"charset",
|
|
38
|
+
"cookies",
|
|
39
|
+
"http2",
|
|
40
|
+
# "http3", # ← 必须禁用
|
|
41
|
+
"rustls-tls-webpki-roots",
|
|
42
|
+
"stream",
|
|
43
|
+
"multipart",
|
|
44
|
+
"socks",
|
|
45
|
+
"brotli",
|
|
46
|
+
"gzip",
|
|
47
|
+
]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> **⚠️ 已知问题**:rustls 的 `ring` 加密后端在 OHOS 真机上存在 TLS 握手挂起的问题。HTTP 请求正常(返回 200),但 HTTPS 请求无限挂起无响应。编译不受影响,运行时才会出现。
|
|
51
|
+
>
|
|
52
|
+
> **缓解方案**:详见 `references/ffi-rust-cross-compile.md` §3 的 TLS 运行时风险说明。
|
|
53
|
+
|
|
54
|
+
### 2.2 HTTP/3:必须禁用
|
|
55
|
+
|
|
56
|
+
```toml
|
|
57
|
+
# Cargo.toml — 禁用 HTTP/3
|
|
58
|
+
features = [
|
|
59
|
+
# "http3", ← 注释掉或删除
|
|
60
|
+
]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
同时在 Rust 代码中处理 HTTP/3 相关分支,改为 no-op(返回默认客户端):
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
// rust/src/api/client.rs
|
|
67
|
+
HttpVersionPref::Http3 => client, // OHOS 不支持 HTTP/3,返回未配置版本偏好的 client
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2.3 flutter_rust_bridge:Patch 标准版(非 OHOS fork)
|
|
71
|
+
|
|
72
|
+
**实战发现**:OHOS fork 版本(2.7.0)与 rhttp 所需版本(^2.12.0)差距过大,`dependency_overrides` 降级会导致 `pub get` hang。**推荐方案是 patch 标准版**。
|
|
73
|
+
|
|
74
|
+
#### 步骤 A:Dart 侧 Platform.isOhos 补丁
|
|
75
|
+
|
|
76
|
+
1. 定位 pub cache 中的标准版路径:
|
|
77
|
+
```bash
|
|
78
|
+
PUB_CACHE=~/.pub-cache/hosted/pub.dev
|
|
79
|
+
FRB_DIR=$PUB_CACHE/flutter_rust_bridge-2.12.0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. 清空 checksum 以允许修改:
|
|
83
|
+
```bash
|
|
84
|
+
echo '{}' > $FRB_DIR/.cargo-checksum.json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
3. 修改 `lib/src/loader/_io.dart`(约第 55 行),在平台判断链中添加 OHOS:
|
|
88
|
+
```dart
|
|
89
|
+
// 在 Platform.isAndroid || Platform.isLinux 判断中添加 Platform.isOhos
|
|
90
|
+
if (Platform.isAndroid || Platform.isLinux || Platform.isOhos) {
|
|
91
|
+
return DynamicLibrary.open('lib{name}.so');
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
4. 对 `flutter_rust_bridge` 的其他文件做类似处理(搜索 `Platform.isAndroid` 和 `Platform.isLinux`)
|
|
96
|
+
|
|
97
|
+
#### 步骤 B:Rust 侧 Dart_* 符号补丁
|
|
98
|
+
|
|
99
|
+
OHOS 的 `libflutter.so` **不导出任何 `Dart_*` 符号**(如 `Dart_InitializeApiDL`),必须将 `dart_api_dl.c` 静态编译进 Rust `.so`:
|
|
100
|
+
|
|
101
|
+
1. 定位 Rust crate 的 build.rs:
|
|
102
|
+
```bash
|
|
103
|
+
CARGO_CACHE=~/.cargo/registry/src
|
|
104
|
+
FRB_RUST_DIR=$(find $CARGO_CACHE -path "*/flutter_rust_bridge-2.12.0" -type d | head -1)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
2. 清空 checksum:
|
|
108
|
+
```bash
|
|
109
|
+
echo '{}' > $FRB_RUST_DIR/.cargo-checksum.json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
3. 修改 `build.rs`,为 OHOS target 添加 `dart_api_dl.c` 编译:
|
|
113
|
+
```rust
|
|
114
|
+
// 在 build.rs 中添加 OHOS 检测
|
|
115
|
+
let target = std::env::var("TARGET").unwrap_or_default();
|
|
116
|
+
let is_ohos = target.contains("ohos");
|
|
117
|
+
|
|
118
|
+
if is_ohos {
|
|
119
|
+
let dart_api_dl_dir = /* flutter_rust_bridge 的 dart_api_dl.h 所在目录 */;
|
|
120
|
+
cc::Build::new()
|
|
121
|
+
.file(format!("{}/dart_api_dl.c", dart_api_dl_dir))
|
|
122
|
+
.include(dart_api_dl_dir)
|
|
123
|
+
.compile("dart_api_dl");
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
> **关键**:每次 `pub cache repair` 或依赖版本变更后 patch 会丢失。建议编写自动化脚本。
|
|
128
|
+
|
|
129
|
+
### 2.4 CMakeLists.txt:跳过 C 占位编译
|
|
130
|
+
|
|
131
|
+
rhttp 使用 `cargokit` 自动编译 Rust,但 OHOS 不支持 cargokit。需要手动编译 `.so` 并跳过 CMakeLists.txt 中的 C 编译:
|
|
132
|
+
|
|
133
|
+
```cmake
|
|
134
|
+
# src/CMakeLists.txt
|
|
135
|
+
if(OHOS)
|
|
136
|
+
# OHOS 使用预编译 Rust .so,跳过 C 编译
|
|
137
|
+
return()
|
|
138
|
+
endif()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 2.5 系统证书:默认可用
|
|
142
|
+
|
|
143
|
+
rustls 默认使用 `webpki-roots`(Mozilla 根证书列表),跨平台通用。
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 三、完整适配流程
|
|
148
|
+
|
|
149
|
+
### 步骤 1:环境配置
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# 1. 安装 OHOS target
|
|
153
|
+
rustup target add aarch64-unknown-linux-ohos
|
|
154
|
+
|
|
155
|
+
# 2. 设置环境变量
|
|
156
|
+
export OHOS_NDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony
|
|
157
|
+
export PATH="/path/to/flutter_ohos/bin:$PATH"
|
|
158
|
+
|
|
159
|
+
# 3. 配置 .cargo/config.toml(指向 NDK Clang 和 llvm-ar)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 步骤 2:应用 Patch
|
|
163
|
+
|
|
164
|
+
按 §2.3 应用 Dart 侧和 Rust 侧的补丁。
|
|
165
|
+
|
|
166
|
+
### 步骤 3:修改 Rust 代码
|
|
167
|
+
|
|
168
|
+
1. **禁用 HTTP/3**:`Cargo.toml` 中注释 `http3` feature
|
|
169
|
+
2. **HTTP/3 代码路径 no-op**:`rust/src/api/client.rs` 中 `HttpVersionPref::Http3` 分支返回默认 client
|
|
170
|
+
3. **修改 CMakeLists.txt**:OHOS 平台跳过 C 编译
|
|
171
|
+
|
|
172
|
+
### 步骤 4:交叉编译 Rust .so
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# 设置 ring/CC 编译所需环境变量
|
|
176
|
+
export CC_aarch64_unknown_linux_ohos=$OHOS_NDK_HOME/native/llvm/bin/aarch64-unknown-linux-ohos-clang
|
|
177
|
+
export AR_aarch64_unknown_linux_ohos=$OHOS_NDK_HOME/native/llvm/bin/llvm-ar
|
|
178
|
+
export CFLAGS_aarch64_unknown_linux_ohos="--sysroot=$OHOS_NDK_HOME/native/sysroot"
|
|
179
|
+
|
|
180
|
+
# 编译
|
|
181
|
+
cd rust/
|
|
182
|
+
cargo build --release --target aarch64-unknown-linux-ohos
|
|
183
|
+
|
|
184
|
+
# 拷贝 .so
|
|
185
|
+
cp target/aarch64-unknown-linux-ohos/release/librhttp.so \
|
|
186
|
+
../ohos/libs/arm64-v8a/librhttp.so
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 步骤 5:构建与测试 HAP
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# 清理缓存(每次修改 .so 后必须清理)
|
|
193
|
+
rm -rf ohos/.cxx ohos/build
|
|
194
|
+
|
|
195
|
+
# 构建
|
|
196
|
+
flutter build hap --debug
|
|
197
|
+
|
|
198
|
+
# 安装到真机
|
|
199
|
+
flutter install --debug
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 步骤 6:验证 HTTP/HTTPS
|
|
203
|
+
|
|
204
|
+
在 example app 中添加测试按钮,分别测试:
|
|
205
|
+
1. **HTTP**(`http://example.com`)→ 应返回 200
|
|
206
|
+
2. **HTTPS**(`https://reqres.in/api/users`)→ 观察是否挂起
|
|
207
|
+
|
|
208
|
+
> 如果 HTTPS 挂起,确认是 `ring` TLS 运行时问题,参见 `references/ffi-rust-cross-compile.md` §3 缓解方案。
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 四、已知问题与风险
|
|
213
|
+
|
|
214
|
+
| # | 问题 | 状态 | 影响 | 缓解方案 |
|
|
215
|
+
|---|------|------|------|----------|
|
|
216
|
+
| 1 | **ring TLS 运行时挂起** | 🔴 未解决 | HTTPS 不可用 | 尝试 aws-lc-rs / native-tls+ohos-openssl |
|
|
217
|
+
| 2 | **flutter_rust_bridge 版本兼容** | 🟡 已绕过 | 需手动 patch pub cache | Patch 标准版替代 OHOS fork |
|
|
218
|
+
| 3 | **Dart_* 符号缺失** | 🟢 已解决 | 无 | 编译 dart_api_dl.c 进 .so |
|
|
219
|
+
| 4 | **Platform.isOhos 补丁** | 🟡 已绕过 | 需手动 patch pub cache | 同 #2 一起处理 |
|
|
220
|
+
| 5 | **HTTP/3 不可用** | 🟢 已解决 | 无 | 禁用 http3 feature |
|
|
221
|
+
| 6 | **cargokit 不支持 OHOS** | 🟡 已绕过 | 手动编译 .so | 手动 cargo build + 拷贝 |
|
|
222
|
+
| 7 | **pub cache patch 持久性** | 🟡 需注意 | pub cache repair 后丢失 | 编写自动化脚本 |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 五、参考资源
|
|
227
|
+
|
|
228
|
+
| 用途 | 链接 |
|
|
229
|
+
|------|------|
|
|
230
|
+
| Rust 官方 OHOS 交叉编译 | https://doc.rust-lang.org/rustc/platform-support/openharmony.html |
|
|
231
|
+
| ohos-rs 快速入门 | https://ohos.rs/en/docs/basic/quick-start |
|
|
232
|
+
| ohos-rs 示例集(reqwest 等) | https://github.com/ohos-rs/example |
|
|
233
|
+
| flutter_rust_bridge OHOS fork | https://github.com/Aloereed/flutter_rust_bridge_ohos |
|
|
234
|
+
| ohos-openssl 预编译 | https://github.com/ohos-rs/ohos-openssl |
|
|
235
|
+
| ServoDemo(大型 Rust .so 打包案例) | https://github.com/jschwe/ServoDemo |
|