关于 maui-platform-invoke
maui-platform-invoke 是面向 .NET MAUI 开发者的平台调用实践指南,介绍如何组织平台特定代码,并说明常见陷阱及规避方式。
主要功能
- 01选择平台代码组织方式
- 02跨平台使用分部类
- 03通过接口隔离实现
- 04规避条件编译问题
- 05处理 Android Activity 为空
适用场景
- 01组织平台特定服务逻辑
- 02提升共享代码的单元测试能力
- 03检查平台编译与回退问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill maui-platform-invoke安装后在 Claude Code 中输入/maui-platform-invoke确认已加载。
附带文件references/platform-invoke-api.md
详细介绍
Platform 调用 — 注意事项与最佳实践
决策框架
| 场景 | 方案 |
|---|---|
| 1–5 行,一次性检查 | 使用 #if ANDROID 条件编译 |
| 包含逻辑且可测试的服务 | 在 Platforms/ 文件夹中使用分部类 |
| 可替换实现、需要模拟 | 接口 + DI 注册 |
团队偏好 *.android.cs 命名 | 在 .csproj 中自定义文件模式 |
默认选择:分部类 + 接口 + DI。 仅在简单的内联检查中使用 #if。
常见错误
1. 过度使用 #if 指令
// ❌ Complex logic buried in #if blocks — untestable, hard to read
public async Task<bool> CheckConnectivity()
{
#if ANDROID
// 30 lines of Android networking code...
#elif IOS
// 25 lines of iOS networking code...
#endif
}
// ✅ Use partial classes — each platform file is clean and testable
// Services/ConnectivityService.cs (shared)
public partial class ConnectivityService
{
public partial Task<bool> CheckConnectivityAsync();
}
// Platforms/Android/Services/ConnectivityService.cs
public partial class ConnectivityService
{
public partial Task<bool> CheckConnectivityAsync() { /* Android impl */ }
}
2. 分部类的命名空间不匹配
所有分部类文件必须使用相同的命名空间,否则它们会成为不同的类。
// ❌ Different namespaces — creates TWO unrelated classes
// Services/MyService.cs
namespace MyApp.Services;
public partial class MyService { }
// Platforms/Android/MyService.cs
namespace MyApp.Platforms.Android; // WRONG!
public partial class MyService { }
// ✅ Same namespace everywhere
namespace MyApp.Services;
public partial class MyService { }
3. 在共享代码中依赖具体类
// ❌ Shared code depends on concrete platform type — can't mock in tests
public class MyViewModel
{
readonly DeviceOrientationService _service = new();
}
// ✅ Depend on interface — enables unit testing and swapping
public class MyViewModel
{
readonly IDeviceOrientationService _service;
public MyViewModel(IDeviceOrientationService service) => _service = service;
}
4. 忘记 #else 后备分支
// ❌ Fails compilation on unsupported platforms
public string GetDeviceName()
{
#if ANDROID
return Android.OS.Build.Model;
#elif IOS
return UIKit.UIDevice.CurrentDevice.Name;
#endif // No return for Windows or other platforms!
}
// ✅ Always include a fallback
#else
return "Unknown";
#endif
平台注意事项
⚠️ Android:Platform.CurrentActivity 可能为 null
在 OnCreate 完成之前,或应用在后台运行时,Platform.CurrentActivity 的值为 null。务必进行 null 检查,或抛出明确的异常。
⚠️ MSBuild 会自动包含 Platforms/{Platform}/ 中的文件
Platforms/Android/ 下的文件仅针对 Android 编译,无需使用 #if。
但如果将平台代码放在共享文件夹(例如 Services/)中,必须使用 #if 或条件 <Compile> 项。
⚠️ 自定义文件模式需要显式的 MSBuild 条件
如果使用 *.android.cs 命名,文件不会被自动包含。请在 .csproj 中添加带有平台条件的 <Compile> 项。
检查清单
- 所有文件中的分部类都使用相同的命名空间
- 复杂的平台代码使用分部类,而非
#if块 - 共享代码依赖接口,而非具体实现
- 在
MauiProgram.cs中通过 DI 注册接口 -
#if块包含针对不支持平台的#else后备分支 - 使用前检查
Platform.CurrentActivity是否为 null(Android) - 自定义文件模式(如有使用)包含 MSBuild
<Compile>条件
评论
支持 Markdown