Platform-agnostic调用原生API必须走Microsoft.Maui.Controls.Handlers.Compatibility
吗?
不需要。MAUI 从 6.0 开始已弃用兼容层,所有平台特定代码应通过
Microsoft.Maui.Platform(Android)和
Microsoft.Maui.Platforms.iOS(iOS)中的扩展方法或自定义处理程序实现。直接引用旧兼容命名空间会导致编译失败或运行时异常。
正确路径是:在
Platforms/Android或
Platforms/iOS目录下编写平台专属代码,利用 MAUI 的依赖注入机制或
DeviceInfo/
MainThread等跨平台抽象做桥接。
Android端调用Activity
或Context
常见报错和绕过方式
在 Android 平台代码中,直接访问
CurrentActivity或
ApplicationContext时容易遇到
NullReferenceException——尤其在启动早期(如
App.xaml.cs构造函数中)或后台线程里。
MauiApplication.Current?.Windows.FirstOrDefault()?.Handler?.MauiContext?.Context是较稳妥的 Context 获取路径,但需确保窗口已初始化 若需在 Activity 生命周期回调中操作(如
OnResume),应继承
Microsoft.Maui.MauiApplication并重写
OnCreate,再通过
RegisterActivityLifecycleCallbacks注册监听 避免在非 UI 线程直接调用
Toast.MakeText等 UI 方法;改用
MainThread.InvokeOnMainThreadAsync包裹
iOS端访问UIApplication
或UIViewController
的时机陷阱
iOS 上最常踩的坑是过早访问
UIApplication.SharedApplication.KeyWindow?.RootViewController—— MAUI 启动完成前该值为
null,且 iOS 15+ 后
KeyWindow已被弃用。 推荐使用
MauiUIApplicationDelegate.Window(在
Platforms/iOS/AppDelegate.cs中可安全获取)作为根视图控制器来源 若需在页面级调用原生 API(如弹出
UIAlertController),应在
OnAppearing中延迟一小段(
await Task.Delay(1))再获取
UIViewController,或通过
IVisualElementRenderer的
ViewController属性取当前页控制器 注意:iOS 所有 UI 操作必须在主线程,
DispatchQueue.MainQueue.DispatchSync是必需的,不能省略
如何安全暴露原生能力给共享项目(C#逻辑层)
不能让共享项目直接引用
Android.App.Activity或
UIKit.UIViewController,否则破坏平台隔离。标准做法是定义接口 + 平台实现 + DI 注册。
例如定义
IFilePickerService接口,然后: Android 实现类中用
ActivityResultLauncher启动文件选择器,并通过
TaskCompletionSource封装为异步方法 iOS 实现类中用
UIDocumentPickerViewController,在
DidPickDocumentAtUrls回调中设置
TCS.SetResult在
MauiProgram.CreateMauiApp()中注册:
builder.Services.AddSingleton<ifilepickerservice filepickerservice>()</ifilepickerservice>(平台项目中条件注册)
关键点:所有原生类型(
Intent、
NSUrl)必须在平台实现内部转换为跨平台模型(如
string路径或
Stream),不泄露任何平台特有类型到共享层。
