# oh_dotnettool **Repository Path**: lightsever/oh_dotnettool ## Basic Information - **Project Name**: oh_dotnettool - **Description**: 开发一组鸿蒙pc 使用的 命令行工具 使用dotnet gitee.com/lightsever/install-dotnet-harmonyos - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-20 - **Last Updated**: 2026-07-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 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 中 ```bash ./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):
包裹
图片: 居中显示
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)
```
### 常见用法
```bash
# 浏览当前目录(树形 + 预览)
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/`,把产物复制为模板:
```bash
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`):
```xml
net10.0
ohos-arm64
true
true
logic
Library
```
关键点:
- `RuntimeIdentifier` 必须是 `ohos-arm64`(不是 `linux-arm64`,否则会链接到 HarmonyOS 缺失的系统库)
- `PublishAot` 输出 `liblogic.so`(基名取 AssemblyName)
**2. C# 导出 `app_init`,C++ 通过 dlopen+dlsym 调用它并传入 bridge 的查询函数**
`bridge.cpp` 维护一张 host 侧函数表,按名字(UTF-16 + strlen)查函数指针:
```cpp
// 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` 等):
```csharp
// Logic.cs
private static delegate* unmanaged _get; // bridge_get_func_ptr
private static delegate* unmanaged _log;
[UnmanagedCallersOnly(EntryPoint = "app_init")]
public static void AppInit(delegate* unmanaged get)
{
_get = get;
_log = (delegate* unmanaged) 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-8 `const char*` 不带 strlen,省一次转码
- 回调:C# `[UnmanagedCallersOnly]` 静态方法,通过 bridge 的 `SetCallback(name, ptr)` 注册
详见 [docs/native-bridge-api.md](docs/native-bridge-api.md)。
**3. 编译**:
```bash
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` 描述怎么打包:
```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(密码不进配置文件):
```json
// sign-config.json
{
"keystore": "/path/to/keystore.p12",
"cert": "/path/to/cert.cer",
"profile": "/path/to/profile.p7b",
"keyAlias": "app_key"
}
```
执行:
```bash
oh_tool hap quickpack -keyPwd 123456 -keystorePwd 123456
```
`quickpack` 自动:解模板 → 替换 `.so` → 注入 rawfile 资源 → 重新打包 → 签名。
**5. 安装测试**:
```bash
oh_tool hap install hapsrc/loader/dist/quickpack-test.hap
oh_tool hap run light.hx.dotnet
```
详见 [docs/hap-workflow/](docs/hap-workflow/)。
## 项目结构
```
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` 仓库获取