mcpField
M
maui-platform-invoke

maui-platform-invoke

github.com/davidortinau开发17648 次安装16 周前更新
代码仓库

关于 maui-platform-invoke

maui-platform-invoke 是面向 .NET MAUI 开发者的平台调用实践指南,介绍如何组织平台特定代码,并说明常见陷阱及规避方式。

主要功能

  1. 01选择平台代码组织方式
  2. 02跨平台使用分部类
  3. 03通过接口隔离实现
  4. 04规避条件编译问题
  5. 05处理 Android Activity 为空

适用场景

  1. 01组织平台特定服务逻辑
  2. 02提升共享代码的单元测试能力
  3. 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