docs: 跨平台架构文档、共享库审计报告与 Android CI 构建

This commit is contained in:
lincube
2026-07-26 22:29:10 +09:00
parent 2335693fdd
commit 728a8d4861
4 changed files with 215 additions and 0 deletions

View File

@@ -165,6 +165,68 @@ jobs:
LanMountainDesktop/bin/Release/
retention-days: 7
build-android:
runs-on: ubuntu-latest
name: Build_Android
# Android head 尚未合入时允许跳过
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
submodules: recursive
- name: Check Android head exists
id: check
run: |
if [ -f "LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj" ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Setup .NET
if: steps.check.outputs.exists == 'true'
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
dotnet-quality: 'preview'
- name: Setup Java
if: steps.check.outputs.exists == 'true'
uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '17'
- name: Install Android workload
if: steps.check.outputs.exists == 'true'
run: dotnet workload install android
- name: Cache NuGet packages
if: steps.check.outputs.exists == 'true'
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.nuget/packages
key: ${{ runner.os }}-nuget-android-${{ hashFiles('**/Directory.Packages.props') }}
restore-keys: |
${{ runner.os }}-nuget-android-
${{ runner.os }}-nuget-
- name: Build Android head
if: steps.check.outputs.exists == 'true'
run: dotnet build LanMountainDesktop.Mobile.Android/LanMountainDesktop.Mobile.Android.csproj -c Release -v minimal
- name: Upload artifacts
if: steps.check.outputs.exists == 'true'
uses: actions/upload-artifact@v7
with:
name: build-android
path: |
LanMountainDesktop.Mobile.Android/bin/Release/**/*.apk
if-no-files-found: warn
retention-days: 7
pack-plugin-packages:
runs-on: ubuntu-latest
name: Pack_Plugin_Packages

View File

@@ -22,6 +22,11 @@
- `LanMountainDesktop/Views/` and `ViewModels/`: UI 页面、窗口与视图模型
- `LanMountainDesktop/Services/`: 设置、遥测、启动、持久化、业务服务
- `LanMountainDesktop.PluginSdk/`: 插件 SDK 公共接口和默认打包行为
- `LanMountainDesktop.Platform.Abstractions/`: 平台差异层接口(跨平台契约,禁止平台专属 API
- `LanMountainDesktop.Platform.Windows/`: Windows 平台实现P/Invoke、桌面层、点击穿透等
- `LanMountainDesktop.Platform.Android/`: Android 平台实现
- `LanMountainDesktop.Mobile/`: 共享移动 UI 壳(组件面板)
- `LanMountainDesktop.Mobile.Android/`: Android head入口
- `LanMountainDesktop.Shared.Contracts/`: 宿主/插件共享契约
- `LanMountainDesktop.Tests/`: 宿主与 SDK 测试
- `.trae/specs/`: feature 级规格、任务拆解和验收清单
@@ -91,6 +96,7 @@ dotnet test LanMountainDesktop.slnx -c Debug
- 视觉规范:`docs/VISUAL_SPEC.md`
- 圆角规范:`docs/CORNER_RADIUS_SPEC.md`
- 生态边界:`docs/ECOSYSTEM_BOUNDARIES.md`
- 跨平台架构:`docs/CROSS_PLATFORM.md`
- SDK v5 迁移:`docs/PLUGIN_SDK_V5_MIGRATION.md`
如果多个文档都提到同一件事,以 `docs/ai/DOC_SOURCES.md` 列出的权威来源为准。

92
docs/CROSS_PLATFORM.md Normal file
View File

@@ -0,0 +1,92 @@
# 跨平台架构说明
> 本文档描述阑山桌面的跨平台(桌面 + 移动)架构方案与分层约束。
> 当前目标平台Windows主力、Linux/macOS桌面构建、Android移动端。iOS 暂不在范围内。
## 1. 总体分层
```
┌─────────────────────────────────────────────────────┐
│ Heads平台入口
│ LanMountainDesktopWinExe 桌面宿主) │
│ LanMountainDesktop.Mobile.AndroidAndroid head
├─────────────────────────────────────────────────────┤
│ 共享 UI 层 │
│ LanMountainDesktop.Mobile移动壳/组件面板) │
│ ComponentSystem / Controls / Theme随桌面宿主
├─────────────────────────────────────────────────────┤
│ 平台差异层Platform
│ LanMountainDesktop.Platform.Abstractions接口
│ LanMountainDesktop.Platform.WindowsWindows 实现) │
│ (后续按需增加 Platform.Android / Platform.MacOS
├─────────────────────────────────────────────────────┤
│ 共享核心层(必须无平台依赖) │
│ Shared.Contracts / Shared.IPC / Settings.Core │
│ Appearance / DesktopComponents.Runtime / PluginSdk │
│ Host.Abstractions / PluginIsolation.Contracts │
└─────────────────────────────────────────────────────┘
```
## 1.1 当前落地状态
-`Platform.Abstractions`:接口 + NoOp 实现 + `PlatformLog` 日志桥
-`Platform.Windows`:电源管理、原生对话框、桌面层嵌入、窗口置底/区域穿透、
DWM 互操作、图标服务WindowsIconService/UwpManifestIconResolver、包标识查询
-`Platform.MacOS`MacIconService
-`Platform.Android`:骨架(后续按需填充)
-`Mobile` + `Mobile.Android`单视图组件面板壳APK 可构建
- ✅ 主工程 `LanMountainDesktop` 已无任何 DllImport/LibraryImport
- ✅ PluginIsolation.Ipc 新增 `InProcPluginIpcTransport`(进程内直通,含测试)
主工程保留的平台相关内容(有意为之):
- `WindowsNotificationListener` / `WindowsSmtcMusicControlService` / `LocationService`
的 WinRT **反射**调用路径(无编译期平台依赖,运行时 `OperatingSystem.IsWindows()` 保护),
P/Invoke 部分已抽到 `Platform.Windows.WindowsPackageIdentity`
- `LinuxPowerManagementService`(纯命令行调用,无平台 API
- 静态工厂门面(`*ServiceFactory`)留在 `LanMountainDesktop.Services` 命名空间,
保持既有调用点不变,内部委托平台实现。
## 2. Platform 层规则
- 所有 P/Invoke、`DllImport`/`LibraryImport`、Windows 注册表、COM/Office 互操作等平台专属代码,
一律放入 `LanMountainDesktop.Platform.<平台>` 项目,禁止出现在主工程与共享层。
- `Platform.Abstractions` 只包含接口、跨平台 DTO 与 Null/NoOp 兜底实现。
- Head 项目在启动时负责注册对应平台实现(桌面注册 Windows 实现Android 注册移动实现或 NoOp
## 3. 插件体系的平台策略
| 能力 | 桌面 | Android |
|---|---|---|
| 插件契约PluginSdk / PluginIsolation.Contracts | 保留 | 保留(不变) |
| 进程内加载AssemblyLoadContext | 保留 | 保留 |
| 进程外隔离(命名管道 + AirAppHost 子进程) | 保留 | 不可用,降级为进程内 |
| IPC 传输 | 命名管道dotnetCampus.Ipc | 进程内直通InProc transport同一契约 |
| AirApp 运行时(独立进程) | 保留 | 第一版不提供 |
插件代码不感知传输差异:同一套 `PluginIsolation` 契约在桌面走管道,在移动端走进程内直通。
## 4. 移动端形态
- 移动端不存在"桌面层自由摆放"的交互,组件以**组件面板**(可滚动卡片流/网格)呈现。
- 复用同一批组件控件与 Appearance 主题资源,仅替换容器布局。
- 单窗口生命周期(`ISingleViewApplicationLifetime`)。
## 5. 明确舍弃(移动端不提供)
- 电源管理PowerManagementService
- 桌面层嵌入 / 点击穿透MainWindowDesktopLayerService、WindowPassthroughService
- Office 互操作MudTools.OfficeInterop.*
- Harmony 运行时补丁Platform/Windows/Patches仅随 Windows head 编译)
- AirApp 独立进程运行时
## 6. 构建与 CI
- 桌面:`dotnet build LanMountainDesktop.slnx`Windows/Linux/macOS 三平台 CI
- Android`dotnet build LanMountainDesktop.Mobile.Android/...csproj`CI `build-android` job
需要 `dotnet workload install android`)。
- 共享层新增依赖时,必须确认该包支持 `net10.0-android`,否则放入 Platform 层。
## 7. 相关文档
- 共享库平台依赖审计报告:`docs/cross-platform-shared-audit.md`
- 架构总览:`docs/ARCHITECTURE.md`

View File

@@ -0,0 +1,55 @@
# 共享库跨平台依赖审计报告
> 审计目标:确认以下共享库可被 Android headnet10.0-android安全引用。
> 审计方法:源码级扫描 `DllImport`/`LibraryImport`/`Microsoft.Win32`/`System.Drawing`/`WindowsRuntime`/`System.Management` + csproj 包引用检查。
## 结论总览
| 项目 | 状态 | 说明 |
|---|---|---|
| LanMountainDesktop.Shared.Contracts | ✅ 干净 | 仅引用 Avalonia无平台 API |
| LanMountainDesktop.Shared.IPC | ⚠️ 可编译,运行时受限 | 依赖 dotnetCampus.Ipc命名管道。Android 上可编译但命名管道不可用,移动端必须走进程内传输 |
| LanMountainDesktop.Settings.Core | ✅ 干净 | 无包引用,纯托管 |
| LanMountainDesktop.Appearance | ✅ 干净 | 无包引用,纯托管 |
| LanMountainDesktop.DesktopComponents.Runtime | ✅ 干净 | 无包引用,纯托管 |
| LanMountainDesktop.PluginSdk | ⚠️ 需验证 | 引用 FluentAvaloniaUI / FluentIcons.AvaloniaExcludeAssets=runtime仅编译期与 dotnetCampus.IpcAndroid 引用时需实测还原 |
| LanMountainDesktop.Host.Abstractions | ✅ 干净 | 无包引用 |
## 详细发现
### 1. 源码扫描
7 个项目的 `.cs` 源码中均未发现:
- `DllImport` / `LibraryImport`P/Invoke
- `Microsoft.Win32`(注册表)
- `System.Drawing`
- `System.Runtime.WindowsRuntime`
- `System.Management`
平台专属代码全部集中在主工程 `LanMountainDesktop\`9 个服务文件,正在迁往
`LanMountainDesktop.Platform.Windows`)。
### 2. dotnetCampus.IpcShared.IPC、PluginSdk
- 编译期:跨平台 net 库Android 目标可编译。
- 运行期传输基于命名管道Android 不可用。
- 处置:移动端一律使用 PluginIsolation 的进程内传输InProc transport
Shared.IPC 在移动端应仅作为契约/类型来源,不建立管道连接。
- 后续(可选):若希望编译期硬隔离,可把"管道传输"从 Shared.IPC 拆到
Shared.IPC.Pipes 子项目,移动端不引用。当前不阻塞。
### 3. FluentAvaloniaUI / FluentIcons.AvaloniaPluginSdk
- `ExcludeAssets="runtime"`,仅编译期类型引用。
- 两者均为纯托管 Avalonia 库,预期可在 Android 还原;由 Mobile head 构建实测确认。
### 4. 面向未来移动 AOT 的裁剪风险(仅报告,不修复)
- 主工程使用 YamlDotNet、反射式配置读取——不在本次 7 个共享库范围内,
但如后续把相关逻辑下沉共享层,需加 `DynamicallyAccessedMembers` 注解或源生成序列化。
- Settings.Core 若存在基于 `Activator.CreateInstance` 的设置实例化路径,
迁移到移动端 AOT未来 iOS前需要审计AndroidJIT/interp 可用)不阻塞。
## 修复记录
本次审计未发现需要修改共享库源码的问题,未做代码改动。