From 1b962b47e1ea8ad51e46305caa1b8572ec7ebb69 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Fri, 17 Jul 2026 19:53:43 -0400 Subject: [PATCH 1/2] [MessageUI] Update bindings up to Xcode 27.0 Beta 3 Bind MFMailDraft and MFComposeAssistantViewController for iOS and Mac Catalyst. Model the draft properties, initializer, compose-assistant delegate, and required callback with Xcode 27 availability and nullability. Hide native initialization paths that produce invalid state or abort, and identify initWithDelegate: as the valid designated initializer. Remove the resolved xtro todo files and document the SDK-header/runtime mismatch for the designated initializer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 153b8939-99d0-4969-9178-e1f2fc5ce69a --- src/messageui.cs | 62 +++++++++++++++++++ .../MacCatalyst-MessageUI.ignore | 3 + .../MacCatalyst-MessageUI.todo | 10 --- .../iOS-MessageUI.ignore | 2 + .../api-annotations-dotnet/iOS-MessageUI.todo | 10 --- 5 files changed, 67 insertions(+), 20 deletions(-) delete mode 100644 tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.todo create mode 100644 tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore delete mode 100644 tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.todo diff --git a/src/messageui.cs b/src/messageui.cs index 549daa86a67d..7e1f5911a526 100644 --- a/src/messageui.cs +++ b/src/messageui.cs @@ -22,6 +22,68 @@ enum MFMailComposeControllerDeferredAction : long { AddMissingRecipients, } + /// Represents the contents of an email draft. + [NoTV, NoMac, iOS (27, 0), MacCatalyst (27, 0)] + [BaseType (typeof (NSObject))] + [DisableDefaultCtor] // init leaves the non-null properties uninitialized + interface MFMailDraft { + /// Gets the sender address, or if the draft does not specify one. + [NullAllowed, Export ("from")] + string From { get; } + + /// Gets the subject. + [Export ("subject")] + string Subject { get; } + + /// Gets the attributed message body. + [Export ("body")] + NSAttributedString Body { get; } + + /// Gets the primary recipient addresses. + [Export ("to")] + string [] To { get; } + + /// Gets the carbon-copy recipient addresses. + [Export ("cc")] + string [] Cc { get; } + + /// The subject. + /// The attributed message body. + /// The sender address. + /// The primary recipient addresses. + /// The carbon-copy recipient addresses. + /// Creates an email draft with the specified contents and recipients. + [Export ("initWithSubject:body:from:to:cc:")] + NativeHandle Constructor (string subject, NSAttributedString body, string from, string [] to, string [] cc); + } + + interface IMFComposeAssistantViewControllerDelegate { } + + /// Methods for receiving email drafts from a compose assistant. + [NoTV, NoMac, iOS (27, 0), MacCatalyst (27, 0)] + [Protocol (BackwardsCompatibleCodeGeneration = false), Model] + [BaseType (typeof (NSObject))] + interface MFComposeAssistantViewControllerDelegate { + /// The compose assistant that created the draft. + /// The email draft. + /// Notifies the delegate that the compose assistant created an email draft. + [Abstract] + [Export ("composeAssistantViewController:didComposeDraft:")] + void DidComposeDraft (MFComposeAssistantViewController controller, MFMailDraft draft); + } + + /// Provides an interface for composing an email draft. + [NoTV, NoMac, iOS (27, 0), MacCatalyst (27, 0)] + [BaseType (typeof (UIViewController))] + [PrivateDefaultCtor] // init and initWithCoder: abort at runtime + interface MFComposeAssistantViewController { + /// The object that receives the composed draft. + /// Creates a compose assistant with the specified delegate. + [Export ("initWithDelegate:")] + [DesignatedInitializer] + NativeHandle Constructor (IMFComposeAssistantViewControllerDelegate @delegate); + } + /// Provides a user interface for composing and sending email messages. /// /// Apple documentation for MFMailComposeViewController diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore index 1811ac4c37e8..a9f7cb8248fc 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore @@ -1 +1,4 @@ !missing-selector! MFMessageComposeViewController::setMFMessageComposeViewControllerVerificationCodeSendCompletion: not bound + +## The inherited initializers abort at runtime, so initWithDelegate: is the designated initializer, but the header is not decorated +!extra-designated-initializer! MFComposeAssistantViewController::initWithDelegate: is incorrectly decorated with an [DesignatedInitializer] attribute diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.todo b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.todo deleted file mode 100644 index 11b02d1c8b13..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.todo +++ /dev/null @@ -1,10 +0,0 @@ -!missing-protocol! MFComposeAssistantViewControllerDelegate not bound -!missing-selector! MFComposeAssistantViewController::initWithDelegate: not bound -!missing-selector! MFMailDraft::body not bound -!missing-selector! MFMailDraft::cc not bound -!missing-selector! MFMailDraft::from not bound -!missing-selector! MFMailDraft::initWithSubject:body:from:to:cc: not bound -!missing-selector! MFMailDraft::subject not bound -!missing-selector! MFMailDraft::to not bound -!missing-type! MFComposeAssistantViewController not bound -!missing-type! MFMailDraft not bound diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore new file mode 100644 index 000000000000..d7d3a90f657f --- /dev/null +++ b/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore @@ -0,0 +1,2 @@ +## The inherited initializers abort at runtime, so initWithDelegate: is the designated initializer, but the header is not decorated +!extra-designated-initializer! MFComposeAssistantViewController::initWithDelegate: is incorrectly decorated with an [DesignatedInitializer] attribute diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.todo b/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.todo deleted file mode 100644 index 11b02d1c8b13..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.todo +++ /dev/null @@ -1,10 +0,0 @@ -!missing-protocol! MFComposeAssistantViewControllerDelegate not bound -!missing-selector! MFComposeAssistantViewController::initWithDelegate: not bound -!missing-selector! MFMailDraft::body not bound -!missing-selector! MFMailDraft::cc not bound -!missing-selector! MFMailDraft::from not bound -!missing-selector! MFMailDraft::initWithSubject:body:from:to:cc: not bound -!missing-selector! MFMailDraft::subject not bound -!missing-selector! MFMailDraft::to not bound -!missing-type! MFComposeAssistantViewController not bound -!missing-type! MFMailDraft not bound From 897e85a4b8e8e206c57ea59a7b0c3088abf18e15 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Mon, 20 Jul 2026 11:48:38 -0400 Subject: [PATCH 2/2] [MessageUI] Match initializer metadata to headers Remove the designated-initializer attribute from MFComposeAssistantViewController.initWithDelegate: because the Xcode header does not annotate it. Drop the corresponding xtro exceptions and add a narrow introspection match for the inherited UIViewController initializer that aborts at runtime. Keep the invalid generated initialization paths non-public. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 153b8939-99d0-4969-9178-e1f2fc5ce69a --- src/messageui.cs | 1 - tests/introspection/ApiCtorInitTest.cs | 5 +++++ .../api-annotations-dotnet/MacCatalyst-MessageUI.ignore | 3 --- .../xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore | 2 -- 4 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore diff --git a/src/messageui.cs b/src/messageui.cs index 7e1f5911a526..c365ba381619 100644 --- a/src/messageui.cs +++ b/src/messageui.cs @@ -80,7 +80,6 @@ interface MFComposeAssistantViewController { /// The object that receives the composed draft. /// Creates a compose assistant with the specified delegate. [Export ("initWithDelegate:")] - [DesignatedInitializer] NativeHandle Constructor (IMFComposeAssistantViewControllerDelegate @delegate); } diff --git a/tests/introspection/ApiCtorInitTest.cs b/tests/introspection/ApiCtorInitTest.cs index 0f6d380873e5..a0fab899b86c 100644 --- a/tests/introspection/ApiCtorInitTest.cs +++ b/tests/introspection/ApiCtorInitTest.cs @@ -498,6 +498,11 @@ protected virtual bool Match (ConstructorInfo ctor, Type type) if (ctor.ToString () == $"Void .ctor(Metal.IMTLDevice, MetalPerformanceShaders.MPSNDArrayDescriptor)") return true; break; + case "MFComposeAssistantViewController": + // The inherited UIViewController initializer aborts, and the header does not designate initWithDelegate:. + if (cstr == $"Void .ctor(System.String, Foundation.NSBundle)") + return true; + break; case "MFMailComposeViewController": // You are meant to use the system provided one case "MFMessageComposeViewController": // You are meant to use the system provided one case "GKFriendRequestComposeViewController": // You are meant to use the system provided one diff --git a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore index a9f7cb8248fc..1811ac4c37e8 100644 --- a/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore +++ b/tests/xtro-sharpie/api-annotations-dotnet/MacCatalyst-MessageUI.ignore @@ -1,4 +1 @@ !missing-selector! MFMessageComposeViewController::setMFMessageComposeViewControllerVerificationCodeSendCompletion: not bound - -## The inherited initializers abort at runtime, so initWithDelegate: is the designated initializer, but the header is not decorated -!extra-designated-initializer! MFComposeAssistantViewController::initWithDelegate: is incorrectly decorated with an [DesignatedInitializer] attribute diff --git a/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore b/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore deleted file mode 100644 index d7d3a90f657f..000000000000 --- a/tests/xtro-sharpie/api-annotations-dotnet/iOS-MessageUI.ignore +++ /dev/null @@ -1,2 +0,0 @@ -## The inherited initializers abort at runtime, so initWithDelegate: is the designated initializer, but the header is not decorated -!extra-designated-initializer! MFComposeAssistantViewController::initWithDelegate: is incorrectly decorated with an [DesignatedInitializer] attribute