mcpField
D
dotnet-uno-targets

dotnet-uno-targets

github.com/wshaddix开发8667 次安装35 周前更新
代码仓库

关于 dotnet-uno-targets

为 Uno Platform 应用开发者提供按目标平台划分的部署指南,涵盖 Web/WASM、移动端、桌面端和嵌入式环境。内容包括项目配置、调试、打包分发及平台特有注意事项。

主要功能

  1. 01按目标平台介绍项目配置
  2. 02说明调试工作流与工具
  3. 03介绍打包和分发方式
  4. 04涵盖 AOT 与裁剪影响
  5. 05整理平台特有的限制与差异

适用场景

  1. 01为 Uno 应用配置特定部署目标
  2. 02排查各平台的调试与运行问题
  3. 03准备应用打包和分发

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-uno-targets

安装后在 Claude Code 中输入/dotnet-uno-targets确认已加载。

详细介绍

dotnet-uno-targets

Uno Platform 应用的各目标部署指南:Web/WASM、iOS、Android、macOS (Catalyst)、Windows、Linux (Skia/GTK) 和 Embedded (Skia/Framebuffer)。每个目标章节涵盖项目设置、调试工作流、打包/分发、平台特有的注意事项、AOT/裁剪影响,以及与其他目标的行为差异。

范围边界: 此技能负责各目标的部署、调试、打包和平台特有的注意事项。Uno Platform 核心开发(Extensions、MVUX、Toolkit、主题)由 [skill:dotnet-uno-platform] 负责。实时文档的 MCP 集成由 [skill:dotnet-uno-mcp] 负责。

范围之外: Uno Platform 测试(WASM 的 Playwright、平台 Appium 测试)——请参阅 [skill:dotnet-uno-testing]。通用 AOT/裁剪模式——请参阅 [skill:dotnet-aot-wasm]。UI 框架选择——请参阅 [skill:dotnet-ui-chooser]。

交叉引用:[skill:dotnet-uno-platform](核心开发)、[skill:dotnet-uno-mcp](MCP 集成)、[skill:dotnet-uno-testing](测试)、[skill:dotnet-aot-wasm](通用 WASM AOT 模式)、[skill:dotnet-ui-chooser](框架选择)。


目标平台概览

目标TFM工具链打包方式主要限制
Web/WASMnet8.0-browserwasm浏览器开发者工具静态托管 / Azure SWA无法访问文件系统,建议使用 AOT,多线程能力有限
iOSnet8.0-iosXcode / VS Code / RiderApp Store / TestFlight配置描述文件、entitlements、不支持 JIT
Androidnet8.0-androidAndroid SDK / EmulatorPlay Store / APK 旁加载SDK 版本目标设置、权限
macOS (Catalyst)net8.0-maccatalystXcodeMac App Store / 公证沙盒限制、entitlements
Windowsnet8.0-windows10.0.19041Visual StudioMSIX / Windows StoreWinAppSDK 版本对齐
Linuxnet8.0-desktopSkia/GTK 主机AppImage / Flatpak / SnapGTK 依赖、Skia 渲染
Embeddednet8.0-desktopSkia/Framebuffer直接部署无窗口系统、无头渲染

TFM 说明: 以编程方式检测平台目标时,使用与版本无关的 glob(net*-ios、net*-android),以避免较旧或较新的 TFM 导致误判。


Web/WASM

项目设置
# Run the WASM target
dotnet run -f net8.0-browserwasm --project MyApp/MyApp.csproj

WASM 目标会在浏览器中渲染 XAML 控件。渲染器取决于项目配置:Skia(canvas/WebGL)或原生 HTML 映射。应用通过 JavaScript 引导程序(uno-bootstrap.js)加载,该程序会初始化 .NET WASM 运行时。

调试
  • 浏览器开发者工具: 在 Chrome/Edge 中按 F12 检查 DOM、网络和控制台输出
  • .NET 调试: Visual Studio 和 VS Code 支持通过浏览器 CDP 调试 .NET WASM 运行时
  • Uno DevServer: dotnet run 会启动支持实时重新加载的开发服务器
  • 控制台日志: ILogger 输出会显示在浏览器控制台中
打包/分发
# Publish for production
dotnet publish -f net8.0-browserwasm -c Release --output ./publish

# Output is a static site (HTML/JS/WASM)
# Deploy to: Azure Static Web Apps, GitHub Pages, Netlify, any static host

发布的输出是一个自包含的静态网站,无需服务器端运行时。

平台特有的注意事项
  • 无法访问文件系统: 通过 JS 互操作或 Uno.Storage 使用浏览器存储 API(IndexedDB、localStorage)
  • 线程限制: Web Workers 仅提供有限的多线程能力;Task.Run 在 WASM 上可能不会并行执行
  • CORS 限制: 来自 WASM 的 HTTP 请求受浏览器 CORS 策略约束
  • 初始加载时间: 应用可用前,必须下载 .NET WASM 运行时和程序集。使用程序集裁剪来减小下载体积。AOT 可提升运行时执行速度,但会增加生成产物的体积
  • 深层链接: 在 Uno Navigation Extensions 中配置 URL 路由,以支持通过浏览器地址栏导航
AOT/修剪

修剪通过移除未使用的代码来减小下载体积。AOT 会将 IL 预编译为 WebAssembly,从而提升运行时执行速度,但会增大产物体积。两者结合使用,并衡量它们对应用的影响。

<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0-browserwasm'">
  <WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>

**修剪对 WASM 至关重要。**未经修剪的应用可能超过 30MB。经过修剪后,典型应用的大小为 5-15MB。AOT 会增大产物体积,但能消除运行时解释器开销——请在目标环境下分别评估下载时间和执行速度。

有关 Uno 特有的 AOT 注意事项(链接器描述符、Uno 源生成器),请参阅 AOT 部分。有关通用的 WASM AOT 模式,请参阅 [skill:dotnet-aot-wasm]。

行为差异
  • **导航:**基于 URL 的深层链接可原生使用;路由映射应定义 URL 模式
  • **身份验证:**OAuth 流程使用浏览器重定向(弹出窗口或重定向);没有可用的原生浏览器。令牌存储使用浏览器安全存储
  • **调试:**可通过 CDP 使用完整的 .NET 调试器;断点可在 Visual Studio/VS Code 中使用
  • **文件选择器:**使用浏览器文件输入 API;FileOpenPicker 映射到 <input type="file">

iOS

项目设置
# Build for iOS simulator
dotnet build -f net8.0-ios

# Run on simulator
dotnet run -f net8.0-ios

需要在 macOS 上安装 Xcode。渲染器(Skia 或原生)取决于项目配置和 Uno 版本。

调试
  • **Visual Studio(配对到 Mac)/ VS Code + C# Dev Kit / Rider:**附加到 iOS 模拟器或设备
  • **Xcode Instruments:**分析 CPU、内存和能耗使用情况
  • **热重载:**通过 DOTNET_MODIFIABLE_ASSEMBLIES=debug 支持
打包/分发
# Publish for App Store
dotnet publish -f net8.0-ios -c Release \
  /p:CodesignKey="Apple Distribution: MyCompany" \
  /p:CodesignProvision="MyApp Distribution Profile"

分发渠道:App Store(需要 Apple Developer 账户)、TestFlight(Beta 测试)、Ad Hoc(企业分发)。

**必需:**配置文件、签名证书,以及用于各项功能的权利文件(推送通知、HealthKit 等)。

平台注意事项
  • **无 JIT 编译:**iOS 禁止 JIT。所有代码都必须使用 AOT 编译或解释执行。.NET 运行时默认使用 Mono 解释器
  • **配置文件:**必须与 bundle ID、team ID 和权利相匹配。配置文件过期会导致难以诊断的构建失败
  • **后台执行:**iOS 限制后台处理。请使用 BGTaskScheduler 执行后台工作
  • **应用传输安全(ATS):**默认要求 HTTPS;HTTP 需要在 Info.plist 中添加 NSAppTransportSecurity 例外
  • **内存压力:**iOS 会积极终止后台应用。请处理 MemoryWarning 事件
AOT/修剪

iOS 默认要求使用 AOT(不支持 JIT)。.NET 运行时会编译为原生 ARM64 代码。

<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
  <PublishTrimmed>true</PublishTrimmed>
  <TrimMode>link</TrimMode>
</PropertyGroup>

**注意:**使用大量反射的代码在 iOS 上会静默失败。开发期间就启用修剪进行测试,不要只在发布构建时测试。

行为差异
  • **导航:**使用 Uno Navigation 时,基于手势的返回导航(从左边缘向右滑动)会自动启用
  • **身份验证:**OAuth 使用 ASWebAuthenticationSession;生物识别身份验证通过 LocalAuthentication 框架实现
  • **调试:**模拟器速度快;设备调试需要 USB 连接和配置文件。支持通过热重载进行远程调试

Android

项目设置
# Build for Android
dotnet build -f net8.0-android

# Deploy to connected device or emulator
dotnet run -f net8.0-android

需要 Android SDK(通过 dotnet workload install android 或 Android Studio 安装)。

调试
  • **Android 模拟器:**使用 Android Studio 的模拟器或命令行 emulator
  • **ADB(Android 调试桥):**使用 adb logcat 查看运行时日志,使用 adb devices 验证连接
  • **Visual Studio / VS Code:**可在模拟器或设备上使用完整的断点调试
打包/分发
# Publish signed APK/AAB (use env vars or CI secrets for passwords — never hardcode)
dotnet publish -f net8.0-android -c Release \
  /p:AndroidKeyStore=true \
  /p:AndroidSigningKeyStore=mykey.keystore \
  /p:AndroidSigningStorePass="$ANDROID_KEYSTORE_PASS" \
  /p:AndroidSigningKeyAlias=myalias \
  /p:AndroidSigningKeyPass="$ANDROID_KEY_PASS"

Google Play 要求使用 Android App Bundle(AAB)格式。侧载使用 APK。

平台注意事项
  • SDK 版本目标: <SupportedOSPlatformVersion> 控制最低 API 级别。为符合 Google Play 要求,目标 API 需为 34+
  • 运行时权限: 危险权限(摄像头、位置、存储)需要在运行时请求。应在代码中检查并请求,而不只是添加到清单中
  • Activity 生命周期: 默认情况下,Android 会在屏幕旋转时销毁 Activity。Uno 会处理此情况,但自定义原生代码必须考虑生命周期
  • ProGuard/R8: 代码缩减可能会移除反射目标。对原生互操作类型使用 @Keep 注解或链接器配置
AOT/修剪
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
  <PublishTrimmed>true</PublishTrimmed>
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>

Android 上的 AOT 可以缩短启动时间。与 iOS 不同,未修剪的代码路径可回退到 JIT。

行为差异
  • 导航: 硬件或软件返回按钮会触发 Uno 导航返回。BackRequested 事件会自动触发
  • 身份验证: 使用 CustomTabs(Chrome)进行 OAuth;通过 AndroidX.Biometric 进行生物识别身份验证
  • 调试: 模拟器比 iOS Simulator 慢,但支持更多 API 级别。使用硬件加速(HAXM/KVM)提升性能

macOS(Catalyst)

项目设置
# Build for macOS
dotnet build -f net8.0-maccatalyst

# Run on macOS
dotnet run -f net8.0-maccatalyst

使用 Mac Catalyst(将 iOS API 适配到 macOS)。需要在 macOS 上安装 Xcode。

调试
  • Visual Studio(配对到 Mac)/ VS Code + C# Dev Kit / Rider: 原生 macOS 调试
  • Xcode Instruments: 分析性能和内存
  • Console.app: 查看应用进程的系统日志
打包/分发
# Publish for distribution
dotnet publish -f net8.0-maccatalyst -c Release \
  /p:CodesignKey="Developer ID Application: MyCompany" \
  /p:CodesignProvision="MyApp Mac Profile"

分发渠道:Mac App Store、经过公证的直接下载、企业部署。

必须进行公证: macOS Gatekeeper 要求在 App Store 之外分发的应用经过公证。使用 xcrun notarytool 提交。

平台注意事项
  • 沙盒限制: Mac App Store 应用运行在沙盒中。访问文件需要相应的权利和用户授权
  • Catalyst 限制: 并非所有 iOS API 都能适用于 macOS。请检查 SupportedOSPlatform 属性
  • 菜单栏: macOS 要求提供合适的菜单栏。Uno 提供默认菜单;可通过平台专用代码自定义
  • 窗口管理: macOS 应用支持多个窗口。Uno 的单窗口模型可能需要调整,以支持多窗口场景
AOT/修剪

与 iOS 使用相同的配置(Catalyst 默认使用 AOT)。建议在分发版本中进行修剪。

行为差异
  • 导航: 没有向后滑动手势;需使用工具栏上的返回按钮或键盘快捷键(Cmd+[)
  • 身份验证: 使用 ASWebAuthenticationSession(与 iOS 共用);通过 Secure Enclave 支持 Touch ID
  • 调试: 作为原生 macOS 进程运行;标准 .NET 调试工具均可使用。没有模拟器——以原生应用形式运行

Windows

项目设置
# Build for Windows
dotnet build -f net8.0-windows10.0.19041

# Run on Windows
dotnet run -f net8.0-windows10.0.19041

Windows 目标可以使用 Skia 渲染器,也可以使用原生 WinAppSDK/WinUI 3 渲染。

调试
  • Visual Studio: 提供完整调试功能,包括 XAML Hot Reload、Live Visual Tree、Live Property Explorer
  • WinUI 诊断: 内置诊断浮层,可用于检查布局
打包/分发
# Package as MSIX
dotnet publish -f net8.0-windows10.0.19041 -c Release \
  /p:PackageOutputPath=./packages

分发方式:Microsoft Store(MSIX)、旁加载(使用证书的 MSIX)、ClickOnce 或直接分发 EXE。

平台注意事项
  • WinAppSDK 版本对齐: Windows TFM 版本必须与最低 Windows 版本匹配。10.0.19041 = Windows 10 2004+
  • UAC 和提权: 应用无法自行提权。应针对标准用户权限进行设计
  • Windows 专用 API: Windows.Storage、Windows.Networking API 仅在 Windows 目标上可用。请使用条件编译或 Uno 抽象
  • MSIX 签名: MSIX 包必须经过签名才能安装。分发时请使用代码签名证书
AOT/修剪
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
  <PublishTrimmed>true</PublishTrimmed>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Windows 支持 JIT 和 AOT。AOT 会生成单个原生 EXE,启动速度更快。

行为差异
  • **导航:**标准 Windows 导航(Alt+Left 返回,标题栏返回按钮)
  • **身份验证:**使用系统浏览器或 WAM(Web Account Manager),通过 Microsoft 账户进行 SSO
  • **调试:**调试体验最丰富,支持 Visual Studio Live Visual Tree 和 XAML Hot Reload

Linux(Skia/GTK)

项目设置
# Build for Linux desktop
dotnet build -f net8.0-desktop

# Run on Linux
dotnet run -f net8.0-desktop

Linux 目标使用 Skia 渲染器和 GTK 宿主窗口。所有 XAML 渲染均由 Skia 完成,GTK 仅负责窗口和输入处理。

调试
  • **VS Code with C# Dev Kit:**在 Linux 上进行远程调试
  • **JetBrains Rider:**完整支持 Linux 调试
  • 控制台日志:dotnet run 会将日志输出到终端
打包/分发
# Publish self-contained for Linux
dotnet publish -f net8.0-desktop -c Release \
  --self-contained \
  -r linux-x64

# Package as AppImage, Flatpak, or Snap

分发方式:AppImage(便携,无需安装)、Flatpak(沙盒化)、Snap(Ubuntu Store)、DEB/RPM 包。

平台注意事项
  • **GTK 依赖项:**应用在运行时需要 GTK3 库。请打包或说明依赖项:libgtk-3-0、libskia*
  • **Skia 渲染:**所有渲染均基于 Skia。不使用原生 GTK 小部件。这可确保跨平台渲染的像素级精确,但意味着应用不会遵循宿主 GTK 主题
  • **字体渲染:**确保目标系统上有可用字体。请将字体嵌入应用,或声明字体依赖项
  • **显示缩放:**Skia 支持 HiDPI;请使用 GDK_SCALE=2 环境变量进行测试
AOT/裁剪
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0-desktop'">
  <PublishTrimmed>true</PublishTrimmed>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Linux 上的 AOT 会生成原生二进制文件。自包含部署可避免依赖系统范围的 .NET 运行时。

行为差异
  • **导航:**由键盘驱动(Alt+Left 返回)。不支持基于手势的导航
  • **身份验证:**OAuth 流程使用系统浏览器。不支持平台专用的身份验证 API
  • **调试:**标准 .NET 调试。不支持平台专用的调试器工具

嵌入式(Skia/Framebuffer)

项目设置

嵌入式目标使用 Skia 渲染器和 framebuffer 后端,可在无窗口系统的情况下进行无头或信息亭式渲染。

# Build for embedded (same TFM as desktop)
dotnet build -f net8.0-desktop -r linux-arm64

# Run directly on embedded device
dotnet run -f net8.0-desktop

嵌入式目标与 Linux 桌面共用 net8.0-desktop TFM。平台专用配置会选择 framebuffer 后端。

// Program.cs -- framebuffer host configuration
public static void Main(string[] args)
{
    SkiaHostBuilder.Create()
        .UseFrameBuffer()  // Use framebuffer instead of GTK
        .App(() => new App())
        .Build()
        .Run();
}
调试
  • **SSH 远程调试:**使用 VS Code Remote 或 dotnet-trace 进行远程性能分析
  • **串行控制台:**将日志重定向到串行输出,以便进行无头调试
  • **远程日志记录:**配置 Serilog 并使用网络接收器,以便集中收集远程日志
打包/分发
# Publish self-contained for ARM64
dotnet publish -f net8.0-desktop -c Release \
  --self-contained \
  -r linux-arm64

# Deploy binary directly to device filesystem
scp -r ./publish/* pi@device:/opt/myapp/

直接部署到设备文件系统。不使用应用商店或包管理器。

平台注意事项
  • **无窗口系统:**不支持 X11/Wayland。应用直接渲染到 Linux framebuffer(/dev/fb0)
  • **输入处理:**通过 Linux 输入事件(/dev/input/event*)处理触控输入。默认没有鼠标光标
  • **资源有限:**嵌入式设备通常受 RAM 和 CPU 资源限制。请仔细分析内存使用情况
  • **无浏览器:**无法使用需要浏览器的 OAuth 流程。请使用设备代码流程或预先配置的令牌
  • **显示分辨率:**必须与 framebuffer 分辨率一致。通过内核启动参数或 fbset 进行设置
AOT/裁剪

强烈建议嵌入式环境使用 AOT,以满足资源有限和启动时间方面的要求。

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'linux-arm64'">
  <PublishTrimmed>true</PublishTrimmed>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

InvariantGlobalization 会通过移除 ICU 数据(约 28 MB)来减小二进制文件大小。仅当应用不需要特定于区域设置的格式化时才使用。

行为差异
  • **导航:**仅支持触控或硬件按钮。不支持键盘快捷键或手势栏
  • **身份验证:**使用设备代码流程或预先配置的凭据。不支持基于浏览器的 OAuth
  • **调试:**仅支持远程调试。不支持本地 IDE。请使用 SSH 调试或远程日志记录

跨目标行为差异

导航
目标返回导航深层链接手势导航
Web/WASM浏览器后退按钮 / Alt+Left基于 URL 的路由无
iOS从左侧边缘向右滑动URL 方案 / 通用链接完整的手势支持
Android硬件/软件返回按钮Intent 过滤器 / 应用链接系统返回手势(Android 13+)
macOSCmd+[ / 工具栏返回URL 方案无
WindowsAlt+Left / 标题栏返回协议激活无
LinuxAlt+Left / 键盘无无
嵌入式仅硬件按钮无仅触控
身份验证
目标OAuth 流程令牌存储生物识别
Web/WASM浏览器重定向/弹出窗口浏览器安全存储WebAuthn(有限支持)
iOSASWebAuthenticationSessionKeychainTouch ID / Face ID
AndroidChrome Custom TabsAndroid KeystoreBiometricPrompt
macOSASWebAuthenticationSessionKeychainTouch ID
Windows系统浏览器 / WAMCredential ManagerWindows Hello
Linux系统浏览器Secret Service API无
嵌入式设备代码流程基于文件(加密)无
调试工具
目标IDE 调试器热重载性能分析
Web/WASMVS / VS Code (CDP)是浏览器 DevTools
iOSVS(配对到 Mac)/ VS Code / Rider是Xcode Instruments
AndroidVS / VS Code是Android Profiler
macOSVS(配对到 Mac)/ VS Code / Rider是Xcode Instruments
WindowsVisual Studio是(+ Live Visual Tree)VS Diagnostic Tools
LinuxVS Code / Rider是dotnet-counters / dotnet-trace
嵌入式VS Code Remote是(SSH)dotnet-trace(远程)

Agent 注意事项

  1. 不要在检测逻辑中硬编码 TFM 版本。 使用与版本无关的 glob(net*-ios、net*-android),以兼容 .NET 8 和未来的 .NET 版本。
  2. 不要假设所有目标都使用相同的调试工作流。 iOS 需要配置预配;Android 需要 ADB;WASM 使用浏览器 DevTools。每个目标都有不同的工具。
  3. 不要在 iOS 上使用依赖 JIT 的模式。 iOS 禁止 JIT 编译。使用 Reflection.Emit、Expression.Compile() 或动态程序集加载的代码会在运行时失败。
  4. 不要忘记特定于平台的权限。 Android 运行时权限、iOS 权限声明、macOS 沙盒权限和 WASM CORS 策略各不相同,必须针对每个目标分别处理。
  5. 不要部署未经裁剪的 WASM 应用。 未裁剪的 WASM 包会超过 30MB。务必启用裁剪,并考虑在生产环境的 WASM 部署中使用 AOT。
  6. 不要假设所有目标都能访问文件系统。 WASM 没有文件系统;iOS/macOS 有沙盒限制;嵌入式设备可能只有只读存储。请使用 Uno Storage 抽象。
  7. 不要对所有目标使用相同的身份验证流程。 WASM 使用浏览器重定向,移动平台使用原生身份验证会话,嵌入式设备使用设备代码流程。身份验证必须针对每个目标分别配置。

先决条件

  • .NET 8.0+ 及平台工作负载:dotnet workload install ios android maccatalyst wasm-tools
  • 平台 SDK:Xcode(iOS/macOS)、Android SDK(Android)、GTK3(Linux)
  • Uno Platform 5.x+

参考资料

评论

支持 Markdown