Skip to main content

macios-binding-creator

Create C# bindings for Apple frameworks in dotnet/macios. USE FOR: binding new APIs, implementing .todo file entries, creating Xcode SDK bindings, binding AVFoundation/UIKit/AppKit or any Apple framework, "bind this framework", "implement these APIs". DO NOT USE FOR: Xcode beta version bumps (use macios-xcode-beta-update skill), CI failure investigation (use macios-ci-failure-inspector skill).

来源信息

仓库
dotnet/macios
最近来源活动
2026年7月13日 14:10
检测到的 SKILL.md 语言
英语
星标
2,912
分支
579

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
3 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
macios-binding-creator
description
Create C# bindings for Apple frameworks in dotnet/macios. USE FOR: binding new APIs, implementing .todo file entries, creating Xcode SDK bindings, binding AVFoundation/UIKit/AppKit or any Apple framework, "bind this framework", "implement these APIs". DO NOT USE FOR: Xcode beta version bumps (use macios-xcode-beta-update skill), CI failure investigation (use macios-ci-failure-inspector skill).
# macios Binding Creator Create C# bindings for Apple platform APIs in the dotnet/macios repository. This skill encodes the end-to-end workflow: from reading `.todo` files through implementation, building, and validating with xtro, cecil, and introspection tests on all platforms. ## When to Use This Skill Use this skill when: - Asked to bind a new Apple framework or add missing API bindings - Implementing entries from `.todo` files in `tests/xtro-sharpie/api-annotations-dotnet/` - Creating bindings for a new Xcode SDK release - Adding new types, properties, methods, or enum values to existing framework bindings - Asked to "bind", "implement", or "add bindings for" any Apple framework ## Prerequisites - Repository checked out and configured (`./configure` already run) - Xcode installed at the expected `XCODE_DEVELOPER_ROOT` path - A successful `make world` or `make all && make install` already completed ## Process ### Step 1: Understand What to Bind Check the `.todo` files to see what APIs are missing: ```bash ls tests/xtro-sharpie/api-annotations-dotnet/*-{FrameworkName}.todo cat tests/xtro-sharpie/api-annotations-dotnet/iOS-{FrameworkName}.todo ``` Each `.todo` file lists missing APIs per platform (iOS, tvOS, macOS, MacCatalyst). The format is: ``` !missing-selector! ClassName::methodName: not bound !missing-type! ClassName not bound !missing-field! ClassName FieldName not bound !missing-enum-value! EnumName::ValueName not bound ``` > ❌ **NEVER** bind APIs that aren't in the `.todo` files unless explicitly asked. The `.todo` files are the source of truth for what's missing. ### Step 2: Generate Reference Bindings Run the xtro generator to produce reference C# bindings from the SDK headers: ```bash make -C tests/xtro-sharpie gen-all ``` This creates generated `.cs` files you can search to find the correct C# signatures, attributes, and patterns for the APIs you need to bind. Use these as reference — don't copy them verbatim. ### Step 3: Research the Native API Before implementing, understand the native API: - Search the generated reference bindings for the correct Objective-C selectors - Read Apple header files when available (under `$XCODE_DEVELOPER_ROOT`) - Check existing bindings in `src/frameworkname.cs` for patterns used in the same framework ### Step 4: Implement Bindings #### Determine the Correct Availability Version Before writing any bindings, determine the correct availability version for each API. The version represents **when Apple introduced the API**, not the current SDK version. **Primary source of truth: the generated reference bindings** from Step 2. After running `make -C tests/xtro-sharpie gen-all`, search the generated `.cs` files for the API you're binding — they include `[Introduced]` attributes extracted from Apple's SDK headers with the correct per-platform introduction versions. Always use these versions. ```bash # Find the generated reference binding for a specific API. # gen-all (Step 2) writes these to api/<Platform>/ApiDefinition.cs (gitignored), # so run Step 2 first. Widen to api/*/ if a symbol isn't in ApiDefinition.cs. grep -rn "SomeClassName\|SomeMethodName" tests/xtro-sharpie/api/*/ApiDefinition.cs ``` If the generated reference bindings don't include version information, fall back to these sources: 1. **Apple SDK headers** — search under `$XCODE_DEVELOPER_ROOT` for `API_AVAILABLE` macros 2. **Current SDK version from `SdkVersions.cs`** — use this only for **brand-new APIs** introduced in the current Xcode release: ```bash grep -E 'public const string (iOS|TVOS|OSX|MacCatalyst) ' tools/common/SdkVersions.cs ``` > ❌ **NEVER assume the current SDK version is the introduction version for all APIs.** The SDK version (e.g., `26.5`) is only correct for APIs that are genuinely new in this Xcode release. When adding an existing framework to a new platform (e.g., MediaSetup to MacCatalyst), or adding enum members that were introduced in an earlier release, the introduction version will be different — check the generated reference bindings or Apple headers. If the user specifies a version, use that instead. **Ask the user if you're unsure which version to use.** #### File Locations Bindings go in these locations: - **`src/frameworkname.cs`** — API definitions (interfaces with `[Export]` attributes) - **`src/FrameworkName/`** — Manual code (partial classes, enums, P/Invokes, extensions) - **`src/frameworks.sources`** — Maps frameworks to source files (update if adding new files) > ⚠️ **Binding an entirely new framework** (no `src/<fw>.cs` yet) needs extra build/test wiring — `frameworks.sources`, `tools/common/Frameworks.cs`, `ProjectTest.cs` link lists, the xtro ignore lists, plus two generated-file build gotchas. See [references/binding-patterns.md](references/binding-patterns.md) § "Registering a Brand-New Framework". Key binding patterns: ```csharp // New property on existing class [Export ("allowsCaptureOfClearKeyVideo")] bool AllowsCaptureOfClearKeyVideo { get; set; } // New method on existing class [Export ("setCaptionPreviewProfileId:")] void SetCaptionPreviewProfileId ([NullAllowed] string profileId); // New notification field [Field ("AVPlayerInterstitialEventMonitorScheduleRequestedNotification")] [Notification] NSString ScheduleRequestedNotification { get; } ``` > ❌ **NEVER** forget platform availability attributes. Every new API must have `[iOS]`, `[Mac]`, `[TV]`, `[MacCatalyst]`, and/or `[No*]` attributes matching the `.todo` file platforms where the API appears. This includes **all** binding types: > - API definition interfaces and members in `src/frameworkname.cs` — use `[iOS (X, Y)]`, `[Mac (X, Y)]`, etc. > - P/Invoke wrappers and manual properties in `src/FrameworkName/*.cs` — use `[SupportedOSPlatform ("iosX.Y")]`, `[SupportedOSPlatform ("macos")]`, etc. > - Fields, constants, and enum values > - **Individual enum members** added to an existing enum — match the native header **per member**: add `[iOS (X, Y)]`/`[No*]`/etc. **only** for what the header annotates on that member (its own `API_AVAILABLE` version newer than the enum, or `API_UNAVAILABLE`/absence on a platform). A member the header doesn't annotate inherits the enum's availability — add **no** attribute, matching its siblings. On a **multi-platform** enum, if you do add a per-member introduced version, add it for **every** applicable platform (bgen otherwise back-fills the enum's older version). **Error enums are an exception — see the next rule.** See [references/binding-patterns.md](references/binding-patterns.md) § "Adding New Members to Existing Enums". > ❌ **NEVER put availability *or* unavailability attributes on members of an *error enum*** — not even brand-new ones. An error enum is any enum whose name ends in `Error` or `ErrorCode`, **or** that carries `[ErrorDomain]`. The cecil test `EnumTest.NoAvailabilityOnError` (issue #9724) fails — with **no** known-failures allowlist — if **any** field carries an availability/unavailability attribute (`[iOS]`/`[Mac]`/`[TV]`/`[No*]`/`[Introduced]`/`[Unavailable]`/`[Supported/UnsupportedOSPlatform]`); only `[Obsolete]`/`[Obsoleted…]` deprecation attributes are exempt. Bind new error-code members bare — just the value (plus `[Field]` if smart) — matching their siblings (e.g. `VNErrorCode.ResourceUnavailable`, `UNErrorCode.AttachmentUnsupportedType`). > ❌ **NEVER** use `string.Empty` — use `""`. Never use `Array.Empty<T>()` — use `[]`. > ❌ **NEVER** add placeholder XML documentation text like `"To be added."` anywhere — not in `<remarks>`, `<summary>`, `<returns>`, `[Async (XmlDocs = ...)]`, or any other XML doc element. Either write meaningful documentation or omit the element entirely. > ❌ **NEVER** forget `[NullAllowed]` on `out NSError error` parameters. Every method that takes `NSError**` (bound as `out NSError error`) must use `[NullAllowed] out NSError error`. This applies to all error-returning methods — the error output is null on success. > ❌ **NEVER** forget `#nullable enable` at the top of every new C# file you create. > ⚠️ **PREFER a named delegate type** (`delegate void SomeFrameworkSomeCallback (…)`) over `Action<T>`/`Func<T>` for completion-handler / callback parameters **when the meaning of a parameter isn't obvious from its type** — only a named delegate can carry parameter names and XML docs. (`Action<T>`/`Func<T>` now support nullable type arguments, so `[NullAllowed]`/nullability is no longer a reason to avoid them.) See [references/binding-patterns.md](references/binding-patterns.md) § "Blocks and Completion Handlers". > ❌ **NEVER** use non-blittable types (`bool`, `char`) as backing fields in structs. Use `byte` (for `bool`) and `ushort`/`short` (for `char`) with property accessors. See [references/binding-patterns.md](references/binding-patterns.md) for the correct pattern. > ❌ **NEVER** use `XAMCORE_5_0` for new code. `XAMCORE_5_0` is only for fixing breaking API changes on existing types that shipped in prior releases. However, when xtro reports a mismatch on an **existing** type (e.g., wrong enum backing type, missing `[Native]`), and fixing it directly would be a breaking change, you **must** use `#if XAMCORE_5_0` guards to preserve binary compatibility while queuing the fix for the future. Add a `.ignore` entry for the xtro mismatch. See [references/binding-patterns.md](references/binding-patterns.md) § "XAMCORE_5_0 Pattern for Existing Types". > ❌ **NEVER** use `#pragma warning disable 0169` for struct fields. Instead, wrap public methods and properties inside `#if !COREBUILD` (but NOT fields — bgen needs to know the struct size). > ⚠️ **Protocol methods returning opaque types**: If a protocol method returns an opaque C type (e.g., `PMPrintSession`) that has a managed `NativeObject` wrapper in `src/FrameworkName/`, do NOT use `IntPtr`. Register the type as a bgen marshal type so bgen can generate proper `Runtime.GetINativeObject<T>()` marshaling. See [references/binding-patterns.md](references/binding-patterns.md) § "NativeObject Return Types in Protocol Methods". > ⚠️ Place a space before parentheses and brackets: `Foo ()`, `Bar (1, 2)`, `myarray [0]`. > ⚠️ Method names should follow .NET naming conventions — use verb-based names, not direct Objective-C selector translations (e.g., `BuildMenu` not `MenuWithContents`). > ❌ **NEVER** change the casing of the Objective-C class name **prefix** in C# type names. `ARSession` stays `ARSession` (not `ArSession`), `AVPlayer` stays `AVPlayer` (not `AvPlayer`). But an acronym *inside* the name (after the prefix) DOES follow .NET rules — `NSURLSession` → `NSUrlSession`, `NSURLSessionHandler` → `NSUrlSessionHandler` (the `NS` prefix is kept, but `URL` becomes `Url`). When creating new manual types, match the framework's established prefix (e.g., all ARKit types use `AR*`, all CoreGraphics types use `CG*`). The .NET acronym rules (SIMD → Simd, URL → Url) apply within property/method names **and** to acronyms inside type names, NOT to the leading class prefix. (A few frameworks instead preserve an inner acronym across their whole family — e.g. CoreGraphics `CGPDF*` — so match the existing sibling types when a framework is consistent.) > ⚠️ For in depth binding patterns and conventions See [references/binding-patterns.md](references/binding-patterns.md) > ⚠️ **Struct array parameters**: When an API takes a C struct pointer + count (e.g., `MyStruct*` + `NSUInteger`), bind the raw pointer as `[Internal]` with `IntPtr`, then create a manual public wrapper using the **factory pattern** with `fixed`. See [references/binding-patterns.md](references/binding-patterns.md) § "Struct Array Parameter Binding". ### Step 4b: Platform Exclusion Patterns for Manual Types When a manually coded type (struct, extension, etc.) is not available on a specific platform (e.g., tvOS), you must handle compilation on that platform: 1. In the manual code file (`src/FrameworkName/MyStruct.cs`), wrap the struct body with `#if !__TVOS__` 2. Add `[UnsupportedOSPlatform ("tvos")]` on the struct 3. In the API definition file (`src/frameworkname.cs`), add a type alias at the top so compilation succeeds: ```csharp #if __TVOS__ using MyStruct = Foundation.NSObject; #endif ``` The `[NoTV]` attribute on the API definition interface ensures the type won't appear in the final tvOS assembly, while the alias prevents compilation errors from method signatures that reference the struct. > ❌ **NEVER** use platform-specific source file lists (e.g., appending a per-framework list to `MACOS_DOTNET_SOURCES`) for platform-conditional code. Instead, use preprocessor directives (`#if __MACOS__`, `#if !__TVOS__`, `#if __IOS__`) within shared source files. Platform-specific source file lists are for the build system, not for conditional compilation of individual types or members. Available preprocessor symbols for platform checks: - `__MACOS__` (preferred) / `MONOMAC` — macOS - `__IOS__` — iOS - `__TVOS__` (preferred) / `TVOS` — tvOS - `__MACCATALYST__` — Mac Catalyst > ⚠️ Mac Catalyst defines **both** `__MACCATALYST__` **and** `__IOS__` (`msbuild/Xamarin.Shared/Xamarin.Shared.props`). In `#if` chains, test `__MACCATALYST__` **before** `__IOS__`, or the Catalyst case falls into the iOS branch. > ⚠️ **Foundation/TextKit types shared by AppKit and UIKit** (e.g. `NSTextList`, `NSParagraphStyle`) are bound once in `src/xkit.cs`, not duplicated in `appkit.cs`/`uikit.cs`. If a type in `appkit.cs` (or `uikit.cs`) becomes exposed to the other side, consolidate it there (share identical enums, split only divergent ones, handle platform-only members with `[No*]` attributes — reserving `#if` for divergences attributes can't express — keep back-dated availability). See [references/binding-patterns.md](references/binding-patterns.md) → "Shared AppKit/UIKit Types". ### Step 5: Build Rebuild **and install** so the test suites — which read the installed NuGet packs, not `src/build/` — pick up your changes: ```bash make all && make install ``` > ❌ **NEVER** use `make -C src build`. There is no `build` *target* in `src/Makefile`, so the command is unreliable: on a fresh checkout it fails with `make: *** No rule to make target 'build'`, and once the `src/build/` output directory exists the word `build` matches that directory and the command silently no-ops (`Nothing to be done for 'build'`). Either way it compiles nothing and you validate against **stale** (or missing) assemblies. Use `make all && make install` (or `make world` for a full rebuild). Fix any compilation errors before proceeding. Builds can take up to 60 minutes — do not timeout early. ### Step 5b: Write Monotouch Tests for Manual Bindings For any manually bound APIs (P/Invokes, manual properties on partial classes, struct accessors), add tests in `tests/monotouch-test/{FrameworkName}/`. > ⚠️ **Only run monotouch-tests (Step 6d) if you added or modified test files in this step.** If no manual bindings were added (i.e., all APIs were bound via `[Export]` in the API definition file), skip both this step and Step 6d. ```csharp using CoreText; // framework being tested using NUnit.Framework; namespace MonoTouchFixtures.CoreText { // MonoTouchFixtures.{FrameworkName} [TestFixture] [Preserve (AllMembers = true)] public class FontTest { [Test] public void UIFontType_SystemFont () { TestRuntime.AssertXcodeVersion (26, 4); // match the availability version using (var font = new CTFont ("Helvetica", 12)) { var fontType = font.UIFontType; Assert.AreEqual (CTUIFontType.System, fontType); } } } } ``` Key patterns: - **Namespace**: `MonoTouchFixtures.{FrameworkName}` (e.g., `MonoTouchFixtures.CoreText`) - **Version guards**: Use `TestRuntime.AssertXcodeVersion (major, minor)` matching the API's availability version. This skips the test on older runtimes instead of failing.
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看