oh_tool 0.1.0
dotnet tool install --global oh_tool --version 0.1.0
dotnet new tool-manifest
dotnet tool install --local oh_tool --version 0.1.0
#tool dotnet:?package=oh_tool&version=0.1.0
nuke :add-package oh_tool --version 0.1.0
oh_dotnettool
HarmonyOS .NET 工具集。当前主要内容:
oh_tool— HarmonyOS 设备连接与调试 CLI- HAP 模板工作流 — 用 HAP 模板替换
.so实现快速迭代 csharp/logic/— C# NativeAOT 示例(编译成liblogic.so注入 HAP)
oh_tool 安装
依赖:
- .NET 10 SDK
- HarmonyOS 真机(已开启网络调试,
persist.hdc.mode == tcp) ~/bin在 PATH 中
./install.sh
脚本做三件事:dotnet build → symlink 到 ~/bin/oh_tool → 检查 PATH。
oh_tool 用法
用法: oh_tool <命令> [参数]
命令:
open 打开 URL 或文件(--webview / --webhost 修饰符)
view 用浏览器预览文件(open --webview 别名)
支持 .md .markdown .html .htm .cs .js .txt .json .xml + 图片
Markdown: marked.js 渲染
HTML: 原样,相对路径资源一并复制
代码 (.cs .js .json .xml): 内嵌高亮
文本 (.txt): <pre> 包裹
图片: 居中显示
Markdown/HTML 自动检测相对引用 (图片/css/js),复制并保持路径
host 以文件或目录为 webroot 起临时 HTTP 服务器(open --webhost 别名)
oh_tool host . 浏览当前目录(最常用)
oh_tool host ./docs 浏览指定目录
oh_tool host index.html 仅服务单个 HTML 文件
目录模式: 左侧目录树 + 右侧预览,懒加载子目录
hap HAP 操作(详细参数请输入 oh_tool hap)
常见用法
# 浏览当前目录(树形 + 预览)
oh_tool host .
# 用浏览器预览 Markdown / 代码 / 图片
oh_tool view README.md
oh_tool view src/Program.cs
oh_tool view docs/diagram.png
# 安装/启动 HAP
oh_tool hap install dist/entry.hap
oh_tool hap run light.hx.dotnet
HAP 模板工作流
为什么用模板
HAP 本质是 ZIP,包含 ArkTS 字节码、资源、libs/*.so、module.json 等。完整构建需要 DevEco Studio 跑完 ArkTS 编译 + 资源编译 + 打包 + 签名,单次 30-60 秒。
如果只改 native(C++/C#),ArkTS 和资源没动,重打整个 HAP 是浪费。模板替换法:把 DevEco 构建出的 HAP 作为模板,每次迭代只换里面的 .so + 重签,5-10 秒搞定。
传统: 改 .cpp → cmake → DevEco 全量构建 → 签名 → 安装 (30-60s)
模板替换: 改 .cpp → cmake → 解 HAP → 换 .so → 打包 → 签名 (5-10s)
准备模板(一次性)
用 DevEco Studio 构建 hapsrc/loader/,把产物复制为模板:
cp hapsrc/loader/entry/build/default/outputs/default/entry-default-signed.hap \
hapsrc/loader/dist/template.hap
何时需要重建模板:
- 改了 ArkTS 代码 (
*.ets) - 改了资源 (
resources/) - 改了
module.json - 新增了
.so依赖库
仅改 native 代码 → 不需要重建模板。
用 .NET (NativeAOT) 开发 native
C# 可以通过 NativeAOT 编译成 HarmonyOS 能加载的 .so。仓库里的 csharp/logic/ 是示例。
1. C# 项目配置(参考 csharp/logic/logic.csproj):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RuntimeIdentifier>ohos-arm64</RuntimeIdentifier>
<PublishAot>true</PublishAot>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>logic</AssemblyName>
<OutputType>Library</OutputType>
</PropertyGroup>
</Project>
关键点:
RuntimeIdentifier必须是ohos-arm64(不是linux-arm64,否则会链接到 HarmonyOS 缺失的系统库)PublishAot输出liblogic.so(基名取 AssemblyName)
2. C# 导出 app_init,C++ 通过 dlopen+dlsym 调用它并传入 bridge 的查询函数
bridge.cpp 维护一张 host 侧函数表,按名字(UTF-16 + strlen)查函数指针:
// bridge.cpp
static void* bridge_get_func_ptr(const char16_t* name, int strlen) {
u16sv key(name, (size_t)strlen);
if (key == u"log") return (void*)bridge_log_impl;
if (key == u"gl.get_proc_utf8raw") return (void*)bridge_gl_get_proc_impl;
if (key == u"asset.open") return (void*)bridge_asset_open_impl;
// ...
return nullptr;
}
static void load_logic(void) {
void* h = dlopen("liblogic.so", RTLD_NOW | RTLD_LOCAL);
auto init = (void (*)(OHBridge_GetFuncPtr))dlsym(h, "app_init");
init(&bridge_get_func_ptr); // 把 host 查询函数传给 C#
}
C# 侧 app_init 接收查询函数,缓存需要的 host 接口,然后注册自己的回调(on_render_frame 等):
// Logic.cs
private static delegate* unmanaged<char*, int, void*> _get; // bridge_get_func_ptr
private static delegate* unmanaged<int, char*, int, void> _log;
[UnmanagedCallersOnly(EntryPoint = "app_init")]
public static void AppInit(delegate* unmanaged<char*, int, void*> get)
{
_get = get;
_log = (delegate* unmanaged<int, char*, int, void>) Query("log");
// ... 查 gl.get_proc_utf8raw / asset.* / SetCallback 等
RegisterCallback("on_render_frame", &OnRenderFrame);
RegisterCallback("on_shutdown", &OnShutdown);
}
ABI 约定:
- 字符串参数:UTF-16
char*+ 显式strlen(C# 是 UTF-16,C++ 侧用char16_t) - 例外:
gl.get_proc_utf8raw是原始 UTF-8const char*不带 strlen,省一次转码 - 回调:C#
[UnmanagedCallersOnly]静态方法,通过 bridge 的SetCallback(name, ptr)注册
3. 编译:
dotnet publish csharp/logic -r ohos-arm64 -c Release
# 产物: csharp/logic/bin/Release/net10.0/ohos-arm64/publish/logic.so
4. 注入 HAP(推荐 oh_tool hap quickpack):
写一个 oh_tool_pack.json 描述怎么打包:
{
"output": "hapsrc/loader/dist/quickpack-test.hap",
"template": "hapsrc/loader/dist/template.hap",
"sign_config": "sign-config.json",
"libs": [
{"src": "hapsrc/loader/entry/src/main/cpp/build/libsurface_provider.so",
"dst": "libs/arm64-v8a/libsurface_provider.so"},
{"src": "csharp/logic/bin/Release/net10.0/ohos-arm64/publish/logic.so",
"dst": "libs/arm64-v8a/liblogic.so"}
],
"resource_dir": "hapsrc/loader/entry/src/main/resources/rawfile"
}
签名参数走单独的 JSON(密码不进配置文件):
// sign-config.json
{
"keystore": "/path/to/keystore.p12",
"cert": "/path/to/cert.cer",
"profile": "/path/to/profile.p7b",
"keyAlias": "app_key"
}
执行:
oh_tool hap quickpack -keyPwd 123456 -keystorePwd 123456
quickpack 自动:解模板 → 替换 .so → 注入 rawfile 资源 → 重新打包 → 签名。
5. 安装测试:
oh_tool hap install hapsrc/loader/dist/quickpack-test.hap
oh_tool hap run light.hx.dotnet
项目结构
oh_dotnettool/
├── src/
│ └── oh_tool/ # oh_tool CLI
│ ├── Program.cs
│ ├── OpenCommands.cs # open/view/host
│ ├── HapCommands.cs # hap install/unpack/pack/sign/quickpack/run/info
│ ├── WebHostCommands.cs # HTTP 服务器
│ ├── HtmlResources.cs # 模板渲染 + 资源扫描
│ └── content/ # HTML 模板(markdown/code/explorer)
├── hapsrc/loader/ # GLES loader HAP(DevEco 项目)
│ ├── entry/src/main/cpp/ # C++ bridge
│ └── dist/template.hap # HAP 模板
├── csharp/logic/ # C# NativeAOT 示例(产出 liblogic.so)
├── docs/
│ ├── hap-workflow/ # HAP 模板工作流详细文档
│ ├── native-bridge-api.md # bridge ⇄ logic 函数指针 ABI
│ └── native-bridge-arch.md # 架构
├── install.sh # oh_tool 安装脚本
└── rebuild-so.sh # 仓库内快速重编译(quickpack 的前身)
环境
- 运行:HarmonyOS 真机(HongMeng Kernel 1.12.0)
- hdc:
/data/service/hnp/bin/hdc - 签名证书:
/storage/Users/currentUser/Documents/signner/ - 打包/签名工具:从
builder_oh仓库获取
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 119 | 7/6/2026 |