-
Notifications
You must be signed in to change notification settings - Fork 3
Packages (5) · Upstream
18.1.0—SwiftBindings.Facebook.AEM,SwiftBindings.Facebook.Core,SwiftBindings.Facebook.CoreBasics,SwiftBindings.Facebook.Login,SwiftBindings.Facebook.ShareAuto-published fromlibraries/Facebook/FACEBOOK-GUIDE.md.
The SwiftBindings.Facebook.* packages expose Meta's Facebook SDK for iOS (upstream v18.1.0) to C# — SDK initialization, App Events, Facebook Login, Graph API requests, and Sharing. The Facebook SDK is a mixed codebase: some modules are pure Objective-C, some are pure Swift, and FBSDKCoreKit is both. That mix is the single most important thing to understand before you translate a snippet from Meta's docs, because it decides what a type is called in C#. This guide teaches that translation and walks the flows most apps need.
- Package map
- Requirements & install
- The two binding shapes (and how to name things)
- Setup: Info.plist + app delegate wiring
- App Events
- Facebook Login
- Access token and profile
- Graph API requests
- Sharing
- FBSDKCoreKit_Basics utilities
- FBAEMKit (Aggregated Event Measurement)
- Object lifetime
- Known limitations
- Reference links
Five packages, mirroring the five upstream component SDKs. Install what you use — dependencies pull the rest in.
| Package | Upstream module | Install it when… |
|---|---|---|
SwiftBindings.Facebook.Core |
FBSDKCoreKit | Always. SDK init, App Events, AccessToken, Settings, Profile, FBSDKGraphRequest. |
SwiftBindings.Facebook.Login |
FBSDKLoginKit | You need Facebook Login (LoginManager, FBLoginButton). Pulls in Core. |
SwiftBindings.Facebook.Share |
FBSDKShareKit | You need share dialogs (ShareDialog, ShareLinkContent). Pulls in Core. |
SwiftBindings.Facebook.AEM |
FBAEMKit | Rarely direct — Aggregated Event Measurement. Pulled in by Core. |
SwiftBindings.Facebook.CoreBasics |
FBSDKCoreKit_Basics | Rarely direct — the pure-ObjC kernel (Base64, JSON/type coercion, crash handler). Pulled in by everything. |
Dependency direction is Login/Share → Core → AEM → CoreBasics. A typical app installs Login and/or Share and gets Core transitively:
dotnet add package SwiftBindings.Facebook.Login
dotnet add package SwiftBindings.Facebook.Share
All five ship at the same version as the upstream SDK (18.1.0) and must be kept in lockstep — mixing versions across the five packages is not supported.
- .NET 10.0+
-
Target framework:
net10.0-ios. iOS only — there is no macOS, Mac Catalyst, or tvOS binding, because the upstream xcframeworks the packages are built from target iOS (and Mac Catalyst, which is not bound here). -
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>or higher (the upstream minimum). - macOS host for development.
- A Facebook app ID and client token from the Meta App Dashboard.
using FBSDKCoreKit; // ApplicationDelegate, Settings, Profile, AccessToken, FBSDKAppEvents, FBSDKGraphRequest
using FBSDKLoginKit; // LoginManager, LoginConfiguration, FBLoginButton
using FBSDKShareKit; // ShareDialog, ShareLinkContent, SharePhoto, HashtagNamespaces are the native module names, not Swift.<Module> — FBSDKCoreKit, FBSDKLoginKit, FBSDKShareKit, FBAEMKit, FBSDKCoreKit_Basics. You also need using Foundation; (for NSDictionary, NSUrl, NSString) and, for anything that takes a Swift geometry value, using Swift; (Swift.CGRect).
The generator produced two different kinds of C# inside these packages, and which one a type came from determines its name:
| Origin | Binding shape | C# name | Examples |
|---|---|---|---|
| Objective-C class/protocol that Swift imports under a shorter name | ObjC (bgen) binding | takes the Swift-import name |
AccessToken, AuthenticationToken, Location, UserAgeRange, BridgeAPIResponse
|
| Objective-C class/protocol with no such rename | ObjC (bgen) binding | keeps the full FBSDK… ObjC name |
FBSDKAppEvents, FBSDKGraphRequest, FBSDKGraphRequestConnection, FBSDKUtility, FBSDKAppLinkUtility, FBSDKSettings-family protocols |
| Swift class/struct/enum | Swift interop binding | keeps the short Swift name |
ApplicationDelegate, Settings, Profile, Permission, LoginManager, LoginConfiguration, FBLoginButton, ShareDialog, ShareLinkContent, Hashtag, AEMReporter
|
This is the rule that costs the most time if you don't know it, and it changed in SDK 0.19.0. Meta's Swift docs write AccessToken.current and AppEvents.shared. AccessToken is an ObjC class (FBSDKAccessToken) that Swift imports as AccessToken, and the binding now follows that import — so it is AccessToken.CurrentAccessToken in C#, where earlier packages spelled it FBSDKAccessToken.CurrentAccessToken. FBSDKAppEvents carries no such Swift rename, so it keeps its ObjC name and stays FBSDKAppEvents.Shared. And Settings.shared really is a Swift class, so it has always been Settings.Shared.
Only the managed name moves — the raw ObjC name is preserved in the binding's [BaseType(…, Name = "FBSDKAccessToken")], so native registration, superclass resolution and anything that reaches these objects through the ObjC runtime are unaffected. The FBSDKCoreKit renames a consumer actually touches are:
| Old C# name | New C# name |
|---|---|
FBSDKAccessToken |
AccessToken |
FBSDKAuthenticationToken |
AuthenticationToken |
FBSDKLocation |
Location |
FBSDKUserAgeRange |
UserAgeRange |
FBSDKBridgeAPIResponse |
BridgeAPIResponse |
FBSDKPaymentProductRequestor |
PaymentProductRequestor |
FBSDKAdvertisingTrackingStatus (enum) |
AdvertisingTrackingStatus |
FBSDKAppLinkNavigationType (enum) |
AppLinkNavigationType |
FBSDKFeature (enum) |
SDKFeature |
FBSDKWebDialogView |
FBWebDialogView |
FBSDKShareBridgeOptions (enum, FBSDKShareKit) |
ShareBridgeOptions |
Four more — FBSDKAppEventsState, FBSDKContainerViewController, FBSDKDialogConfiguration, FBSDKLogger — moved to _-prefixed names (_AppEventsState, …) because Swift imports them as internal; they are not API (see Known limitations). FBSDKCoreKit_Basics, FBSDKLoginKit and FBAEMKit have zero type renames: CoreBasics' ObjC names carry no Swift rename, and LoginKit/AEMKit emit no ObjC lane at all (their @objc classes are Swift declarations the Swift lane already binds). Two FBSDKWebDialogViewDelegate methods also renamed — WebDialogViewDidCancel → DidCancel, WebDialogViewDidFinishLoad → DidFinishLoad — but that protocol is internal surface.
Per-module: FBSDKCoreKit_Basics is entirely ObjC-shaped; FBSDKLoginKit and FBAEMKit are entirely Swift-shaped; FBSDKCoreKit is mixed; FBSDKShareKit is Swift-shaped in its callable surface.
Other conventions worth internalizing:
| Swift / ObjC | C# | Rule |
|---|---|---|
AccessToken.current |
AccessToken.CurrentAccessToken |
ObjC selector name wins for the member (currentAccessToken), even where the type takes its Swift-import name |
AppEvents.shared.logEvent(_:) |
FBSDKAppEvents.Shared.LogEvent(…) |
selectors PascalCase; the label-free first argument disappears |
LoginManager.logIn(permissions:from:handler:) |
LoginManager.LogIn(permissions, viewController, handler) |
Swift argument labels are dropped; order preserved |
init?(permissions:tracking:) (failable) |
LoginConfiguration.TryCreate(…, out var config) |
failable Swift initializers become TryCreate + out
|
enum LoginResult { case success(…), cancelled, failed(Error) } |
class with .Tag (LoginResult.CaseTag) + TryGetSuccess(out …)
|
Swift enums with payloads project to a class + CaseTag + TryGet…
|
enum LoginTracking { case enabled, limited } |
enum LoginTracking : ulong |
payload-free Swift enums become ordinary C# enums |
enum ShareDialog.Mode |
ShareDialog.ModeKind |
nested Swift type names that clash with a member get a Kind suffix |
FBSDKProductAvailabilityInStock (ObjC enum case) |
FBSDKProductAvailability.InStock |
ObjC enum cases drop the prefix only when it is exactly the native enum name |
FBSDKErrorInvalidArgument (ObjC enum case) |
FBSDKCoreError.FBSDKErrorInvalidArgument |
…and keep the full case name when it isn't — here the cases are FBSDKError… but the enum is FBSDKCoreError
|
[String: Any] parameters (ObjC surface) |
Foundation.NSDictionary |
ObjC bindings take NSDictionary; build with NSDictionary.FromObjectsAndKeys
|
Set<String> (Swift surface) |
IReadOnlySet<string> |
Swift collections project to the matching .NET read-only interface |
completion: (Result?, Error?) -> Void |
Action<T?, Swift.Foundation.AnyError?> |
Swift closures become Action<…>; Swift Error is Swift.Foundation.AnyError
|
ObjC completion (id, NSError *)
|
Action<…, NSObject, NSError> |
ObjC blocks keep NSError
|
Three FBSDKCoreKit enums land on the second of those two rows, so their members read redundantly: FBSDKCoreError (cases FBSDKError…), FBSDKGraphRequestFlags (cases FBSDKGraphRequestFlag… — singular, against a plural type name) and the internal AdvertisingTrackingStatus (cases FBSDKAdvertisingTracking…). Every other enum in the package strips cleanly. Let IntelliSense complete these rather than guessing the short form; this is longstanding bgen behavior driven by Meta's own header naming, not something 0.19.0 changed.
This is where .NET consumers need the most translation help. There is no Xcode project to edit — you edit your app's Info.plist and your UIApplicationDelegate subclass directly.
Add these to your app's Info.plist (the same keys Meta documents in Getting Started; substitute your app ID, client token, and display name):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb1234567890</string> <!-- literally "fb" + your app ID -->
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>1234567890</string>
<key>FacebookClientToken</key>
<string>your-client-token</string>
<key>FacebookDisplayName</key>
<string>Your App Name</string>
<!-- Needed for native Login / Share app-switching dialogs -->
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
</array>If you would rather not hardcode the IDs in the plist, Settings.Shared exposes the same values as writable properties — set them before initializing the SDK:
Settings.Shared.AppID = "1234567890";
Settings.Shared.ClientToken = "your-client-token";
Settings.Shared.DisplayName = "Your App Name";FacebookAutoLogAppEventsEnabled and FacebookAdvertiserIDCollectionEnabled are honoured from the plist as usual; the C# equivalents are Settings.Shared.IsAutoLogAppEventsEnabled and Settings.Shared.IsAdvertiserIDCollectionEnabled.
using System;
using System.Collections.Generic;
using System.Linq;
using FBSDKCoreKit;
using Foundation;
using UIKit;
[Register("AppDelegate")]
public sealed class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// Swift: ApplicationDelegate.shared.application(app, didFinishLaunchingWithOptions: launchOptions)
ApplicationDelegate.Shared.Application(application, AsOptions(launchOptions));
// … your own window setup …
return true;
}
// Swift: application(_:open:options:) — required for login / share redirects back into the app
public override bool OpenUrl(UIApplication app, NSUrl url, UIApplicationOpenUrlOptions options)
=> ApplicationDelegate.Shared.Application(app, url, options.SourceApplication, options.Annotation);
// Swift: application(_:continue:restorationHandler:) — App Links / deferred deep links
public override bool ContinueUserActivity(
UIApplication application,
NSUserActivity userActivity,
UIApplicationRestorationHandler completionHandler)
=> ApplicationDelegate.Shared.Application(application, userActivity);
// The Swift dictionaries project as IReadOnlyDictionary<NSString, object>;
// .NET-for-iOS hands you an NSDictionary, so cross the two here once.
private static Dictionary<NSString, object>? AsOptions(NSDictionary? d)
=> d?.Keys.ToDictionary(k => (NSString)k, k => (object)d[k]);
}Three things to note:
-
The
launchOptionsandopenURL:options:overloads are bound. Both take the Swift dictionary projected asIReadOnlyDictionary<NSString, object>(IDictionary<…>for the open-URL one) — not asNSDictionary. The two are unrelated .NET types, so the smallAsOptionsbridge above is what crosses them; there is no implicit conversion. -
launchOptionsis optional.Application(application)also compiles — the parameter defaults tonull— and the SDK does not require launch options for normal initialization. Pass them if you have them. -
Prefer the
sourceApplication/annotationOpenUrlshape as shown above.UIApplicationOpenUrlOptionsis a strongly-typed wrapper rather than a plain dictionary, so forwarding its two properties is less work than projecting it. It is the same native method the Swiftoptions:variant funnels into. If you already hold a raw optionsNSDictionary,ApplicationDelegate.Shared.Application(app, url, AsOptions(dict)!)is the equivalent call.
If your app uses a UIWindowSceneDelegate, forward scene(_:openURLContexts:) to the same ApplicationDelegate.Shared.Application(UIApplication.SharedApplication, url, sourceApplication: null, annotation: null) call, as Meta's docs describe for SceneDelegate.swift.
AppEvents in Meta's docs is the ObjC class FBSDKAppEvents — a singleton reached through .Shared.
using FBSDKCoreKit;
using Foundation;
// Session tracking. Auto-logged unless you set FacebookAutoLogAppEventsEnabled=false,
// in which case call it from applicationDidBecomeActive.
FBSDKAppEvents.Shared.ActivateApp();
// Simple event, and one with a value to sum. The standard event names are bound
// constants — NSString converts to string implicitly, so they drop straight in.
FBSDKAppEvents.Shared.LogEvent(FBSDKCoreKitConstants.FBSDKAppEventNameAddedToCart);
FBSDKAppEvents.Shared.LogEvent(FBSDKCoreKitConstants.FBSDKAppEventNameAddedToCart, 29.99);
// Event with parameters — ObjC surface, so parameters are an NSDictionary
var parameters = NSDictionary.FromObjectsAndKeys(
objects: new NSObject[] { new NSString("product"), new NSNumber(2) },
keys: new NSObject[]
{
FBSDKCoreKitConstants.FBSDKAppEventParameterNameContentType,
FBSDKCoreKitConstants.FBSDKAppEventParameterNameNumItems,
});
FBSDKAppEvents.Shared.LogEvent(FBSDKCoreKitConstants.FBSDKAppEventNameAddedToCart, 29.99, parameters);
// Purchases
FBSDKAppEvents.Shared.LogPurchase(29.99, "USD", parameters);
// Flush control
FBSDKAppEvents.Shared.FlushBehavior = FBSDKAppEventsFlushBehavior.ExplicitOnly;
FBSDKAppEvents.Shared.Flush();
// User identity for advanced matching
FBSDKAppEvents.Shared.UserID = "internal-user-42";
FBSDKAppEvents.Shared.SetUserEmail("a@example.com", "Ada", "Lovelace",
phone: null, dateOfBirth: null, gender: null, city: null, state: null, zip: null, country: null);
FBSDKAppEvents.Shared.ClearUserData();Where the event-name constants live. Swift's
AppEvents.Name.addedToCart/AppEvents.ParameterName.contentTypeareextern NSStringconstants on the ObjC side. They are bound as static properties onFBSDKCoreKitConstants, a generated[Static]container in theFBSDKCoreKitnamespace holding all 171 of the module's extern constants — everyFBSDKAppEventName…,FBSDKAppEventParameterName…,FBSDKAppEventParameterValue…, plus theFBSDKLoggingBehavior…and error-domain/key strings. The property names keep the fullFBSDK…C name; unlike some other modules the generator does not peel a common prefix here, because one constant (DefaultKeychainServicePrefix) does not carry it and the de-prefixing rule is all-or-nothing per module.The type is
NSString, which converts tostringimplicitly, so the constants pass straight intoLogEvent(string, …). Raw strings from Meta's standard-events reference still work identically — the strings are the wire format — but the constants give you compile-time checking.
Read this before you copy a snippet from Meta's docs. The overload everyone reaches for first —
LoginManager.logIn(permissions:from:handler:), i.e.LogIn(IEnumerable<string>, UIViewController, Action<LoginManagerLoginResult, AnyError>)— is emitted as anSB0001non-callable stub (no@_cdeclwrapper or native thunk could be generated for it). It is present in the API surface and compiles with a warning, but do not call it. The supported path is alwaysLoginConfiguration+LogIn(viewController, configuration, completion), shown below. That path covers everything the permissions overload did, including classic (non-Limited) login.
using FBSDKCoreKit;
using FBSDKLoginKit;
using UIKit;
var manager = new LoginManager();
// Swift's failable init?(permissions:tracking:) → TryCreate + out
if (!LoginConfiguration.TryCreate(
new[] { "public_profile", "email" },
LoginTracking.Enabled, // or LoginTracking.Limited for Limited Login
out var configuration))
{
return; // invalid permission set
}
manager.LogIn(presentingViewController, configuration, result =>
{
using (result)
{
switch (result.Tag)
{
case LoginResult.CaseTag.Success:
result.TryGetSuccess(out var granted, out var declined, out var token);
Console.WriteLine($"{granted.Count} granted, {declined.Count} declined");
Console.WriteLine($"userID={token?.UserID}");
break;
case LoginResult.CaseTag.Cancelled:
Console.WriteLine("cancelled");
break;
case LoginResult.CaseTag.Failed:
result.TryGetFailed(out var failure);
Console.WriteLine($"failed: {failure}");
break;
}
}
});
manager.LogOut();The same call has a generated Task form:
using var result = await manager.LogInAsync(presentingViewController, configuration);granted/declined are IReadOnlySet<FBSDKCoreKit.Permission> — the Swift Permission enum, which exposes the well-known permissions as statics (Permission.PublicProfile, Permission.Email, Permission.UserFriends, …) plus Permission.Custom("some_scope") for anything else.
TryCreate has a large family of overloads mirroring Swift's initializers — add nonce, messengerPageId, authType, AppSwitch, or a CodeVerifier as needed, or drop permissions entirely (TryCreate(LoginTracking.Limited, out var config)).
Other members you are likely to want: LoginTracking.Enabled / .Limited, DefaultAudience.Friends / .OnlyMe / .Everyone (new LoginManager(DefaultAudience.OnlyMe) or manager.DefaultAudience), and manager.ReauthorizeDataAccess(viewController, handler).
using Swift; // Swift.CGRect
var button = new FBLoginButton(new CGRect(0, 0, 240, 44))
{
Permissions = new[] { "public_profile", "email" },
LoginTracking = LoginTracking.Enabled,
};
View.AddSubview(button); // FBLoginButton derives from UIButtonusing FBSDKCoreKit;
// Swift docs say AccessToken.current — in C# the type name matches, the member does not.
AccessToken? token = AccessToken.CurrentAccessToken;
if (AccessToken.CurrentAccessTokenIsActive)
{
// Also: AppID, ExpirationDate, RefreshDate, DataAccessExpirationDate,
// Expired, DeclinedPermissions, ExpiredPermissions
Console.WriteLine($"{token!.UserID}: {token.TokenString}");
Console.WriteLine(token.HasGranted("email"));
foreach (var p in token.Permissions) // NSSet<NSString>
Console.WriteLine(p);
}
AccessToken.RefreshCurrentAccessTokenWithCompletion(
(connection, result, error) => { /* … */ });Profile is a Swift class and always had its short name; AccessToken is Objective-C (FBSDKAccessToken) and reaches the same name through the Swift-import rename described in The two binding shapes. Both read the same in C# now:
Profile.EnableUpdatesOnAccessTokenChange(true);
Console.WriteLine(Profile.Current?.Name);
Profile.LoadCurrentProfile((profile, error) =>
{
Console.WriteLine(profile?.FirstName);
Console.WriteLine(profile?.Location?.Name); // Location — an ObjC type (FBSDKLocation)
Console.WriteLine(profile?.AgeRange?.Min); // UserAgeRange — an ObjC type (FBSDKUserAgeRange)
});Profile.Location / .Hometown / .AgeRange returning Location / UserAgeRange is the mixed-module bridge working: a Swift class handing back Objective-C values. Those two are FBSDKLocation / FBSDKUserAgeRange natively — the raw names survive on [BaseType(…, Name = "…")] for the registrar, so nothing about the runtime changes.
GraphRequest is Objective-C, so it is FBSDKGraphRequest and takes NSDictionary parameters.
using FBSDKCoreKit;
using Foundation;
var parameters = NSDictionary.FromObjectsAndKeys(
objects: new NSObject[] { new NSString("id,name,email") },
keys: new NSObject[] { new NSString("fields") });
new FBSDKGraphRequest("me", parameters).StartWithCompletion((connection, result, error) =>
{
if (error is not null) { Console.WriteLine(error.LocalizedDescription); return; }
if (result is NSDictionary dict)
Console.WriteLine(dict[(NSString)"name"]);
});The request uses AccessToken.CurrentAccessToken unless you pass a token string. Other constructors take an explicit HTTP method (new FBSDKGraphRequest("me/feed", parameters, "POST")) or a token string + Graph API version. For batching, build an FBSDKGraphRequestConnection, AddRequest(request, completion) each call, then Start().
using FBSDKShareKit;
using Foundation;
using UIKit;
var content = new ShareLinkContent
{
ContentURL = new NSUrl("https://developers.facebook.com"),
Quote = "Check this out",
Hashtag = new Hashtag("#dotnet"),
};
// Keep a field-level reference: the dialog and its content must outlive Show().
_dialog = new ShareDialog(presentingViewController, content, @delegate: null)
{
Mode = ShareDialog.ModeKind.Automatic,
};
if (_dialog.CanShow)
_dialog.Show();Photos and video use the same dialog with a different content object:
var photo = new SharePhoto(someUIImage, isUserGenerated: true) { Caption = "hello" };
var photoContent = new SharePhotoContent { Photos = new[] { photo } };
_dialog = new ShareDialog(presentingViewController, photoContent, null);
_dialog.Show();
var video = new ShareVideo(videoUrl, previewPhoto: photo);
var videoContent = new ShareVideoContent { Video = video };To receive the result, implement ISharingDelegate — three members: Sharer(ISharing, IDictionary<string, object> results), Sharer(ISharing, Swift.Foundation.AnyError error), and SharerDidCancel(ISharing) — and pass it as the dialog's third constructor argument (or assign dialog.Delegate). A C#-authored delegate does get called back: the binding builds a SharingDelegateProxy for any conformer that is not already a Swift object.
MessageDialog (Messenger) mirrors ShareDialog minus the view controller: new MessageDialog(content, delegate).
Two sharp edges here — see Known limitations:
-
The
ShareDialog.ShareContentgetter throws. Set it, or pass content through the constructor; never read it back. -
Errors raised by this package use the
FBSDKShareErrorDomaindomain, bound asFBSDKShareKitConstants.ShareErrorDomain(anNSString, so it compares againstNSError.Domaindirectly). Note the name: FBSDKShareKit's constants do get the module tag peeled, because that one constant is the module's whole extern-constant surface — unlike FBSDKCoreKit, where the tag stays. -
The constructor and the
Dialog(...)/Show(...)statics all carry anSB0008warning. It is about theISharingContentparameter, not the delegate:ISharingContentis an@objcprotocol existential, so a C#-authored content type cannot be marshalled to Swift (it throwsNotSupportedExceptionat the call). The Swift-vended content types —ShareLinkContent,SharePhotoContent,ShareVideoContent,ShareMediaContent,ShareCameraEffectContent— areISwiftObjectand round-trip normally, so the warning is benign for every supported usage and you can suppressSB0008at the call site. The same applies toMessageDialog.
You rarely reference this package directly, but its surface is fully bound and is the one place in the Facebook graph that is purely ObjC-shaped. Everything is static:
using FBSDKCoreKit_Basics;
using Foundation;
string? b64 = FBSDKBase64.EncodeString("hello .NET");
string? back = FBSDKBase64.DecodeAsString(b64);
NSData? raw = FBSDKBase64.DecodeAsData(b64);
string enc = FBSDKBasicUtility.URLEncode("a b&c=d");
string? sha = FBSDKBasicUtility.SHA256Hash(new NSString("abc"));
NSData? gz = FBSDKBasicUtility.Gzip(NSData.FromString("…"));
// Defensive coercion helpers (wrong-typed input yields the documented zero/nil, never a throw)
string? s = FBSDKTypeUtility.StringValueOrNil(new NSString("s"));
NSUrl? u = FBSDKTypeUtility.CoercedToURLValue(new NSString("https://example.com"));
string version = FBSDKCrashHandler.GetFBSDKVersion(); // "18.1.0"Also here: FBSDKBasicUtility.URLDecode, .JSONStringForObject/.ObjectForJSONString, .QueryStringWithDictionary/.DictionaryWithQueryString, .AnonymousID, and the rest of FBSDKTypeUtility (IntegerValue, BoolValue, NumberValue, DictionaryValue, ArrayValue, …).
If a name here collides with something in your own code, import it aliased — using Basics = global::FBSDKCoreKit_Basics; — as the binding test app does.
AEM is infrastructure the Core SDK drives for you; the useful direct surface is small.
using FBAEMKit;
string? appId = AEMSettings.GetAppID(); // reads Info.plist's FacebookAppID
AEMReporter.SetConversionFilteringEnabled(true);
AEMReporter.SetCatalogMatchingEnabled(true);
AEMReporter.SetAdvertiserRuleMatchInServerEnabled(false);
// Enum raw values match upstream
var op = AEMAdvertiserRuleOperator.RegexMatch;AEMReporter.Configure(networker, appId, reporter), AEMReporter.Enable(), and AEMReporter.HandleMethod(url) are bound too, but Core drives them for you — Configure wants implementations of the Swift protocols IAEMNetworking / ISKAdNetworkReporting, so calling it by hand means supplying the whole networking stack.
IAEMNetworking additionally carries an SB0010 marker: none of its requirements is reverse-dispatchable, so a C# type implementing it is never called back from Swift. Consuming a Swift-vended IAEMNetworking value is unaffected — the marker is only about authoring one. In practice this closes the door on hand-driving Configure, which was already the discouraged path.
Five AEMReporter members — IsContentOptimized, RuleMatchRequestParameters, LoadRuleMatch, LoadMinAggregationRequestTimestamp, and AddConfigurations — reach module-internal Swift types and are emitted as [Obsolete(DiagnosticId = "SB0009")] tombstones that throw NotSupportedException rather than making an unsound native call.
Swift-shaped types implement ISwiftObject. The recommended pattern is standard C# deterministic cleanup — using var — for short-lived values you fully own. Dispose is safe on every generated type and double-Dispose is a no-op.
Two things not to dispose: singletons reached through a static (Settings.Shared, FBSDKAppEvents.Shared, ApplicationDelegate.Shared, Profile.Current) are owned by the SDK; and any object that outlives the statement that created it — a ShareDialog and its content stay alive for the whole presentation, and a FBLoginButton for the lifetime of its view, so hold those in fields rather than wrapping them in using.
Swift enum values with payloads — LoginResult is the one you will actually handle — are IDisposable structs; dispose them when you own them, as in the login example above.
-
LoginManager.LogIn(permissions, viewController, handler)is anSB0001non-callable stub — no native thunk exists for it (its closure parameter shape cannot be marshalled by the C wrapper bridge). UseLoginConfiguration+LogIn(viewController, configuration, completion)(see Facebook Login). This is the single most likely way to translate a Meta doc snippet into a crash. -
Three App Links entry points are
SB0001stubs too —AppLinkNavigation.ResolveAppLink(destination, resolver, handler),AppLinkNavigation.Navigate(destination, resolver, handler)andAppLinkResolver.AppLinks(urls, handler). All three take anany AppLinkResolvingexistential alongside a closure, which is the shape the bridge cannot carry. Deferred deep links viaApplicationDelegate.Shared.Application(application, userActivity)are unaffected — only the manual resolver API is out of reach. (There is a fifthSB0001on the internal_ErrorFactory, which is not API.) -
The
ShareContentgetter is unavailable on four types —ShareDialog,MessageDialog,FBSendButtonandFBShareButton, each[Obsolete(DiagnosticId = "SB0006")], and reading one throwsNotSupportedException(its Swift protocol reverse-dispatch proxy could not be generated). The setter works, and so does passing content through the constructor. Keep your own reference to the content object if you need to read it back. -
The
ShareDialog/MessageDialogconstructors and theirDialog(...)/Show(...)statics carry anSB0008warning — a C#-authoredISharingContentimplementation cannot be marshalled to Swift (it throwsNotSupportedException), becauseISharingContentis an@objcprotocol existential. The Swift-vended content types (ShareLinkContent,SharePhotoContent,ShareVideoContent,ShareMediaContent,ShareCameraEffectContent) round-trip fine, so the warning is benign for every supported usage. It does not apply to the delegate: a C#-authoredISharingDelegateis proxied and is called back normally. -
IAEMNetworkingcarries anSB0010marker — no requirement of the SwiftAEMNetworkingprotocol is reverse-dispatchable, so a C# type implementing it is never invoked from Swift. Consuming a Swift-vended value through the interface is unaffected. Practical effect:AEMReporter.Configurecannot be hand-driven from C#, which was already the discouraged path. -
SB0009tombstones throwNotSupportedException— members whose signature reaches a type that isinternalto its Swift module, so no@_cdeclwrapper can be generated. They are declared for source and conformance compatibility only. There are ~75 across the five packages, but essentially all are on Meta's own plumbing types (MACARuleMatchingManager,LoginURLCompleter,GraphRequestPiggybackManager,_ShareUtility,DPoPKeyManager,DeviceRequestsHelper, …) that no app calls. The ones on types this guide covers are the fiveAEMReportermembers (see FBAEMKit) andLoginManager.GetRecentlyGrantedPermissions/GetRecentlyDeclinedPermissions, which take the module-internalFBPermissionrather than the publicPermission— readgranted/declinedoff theLoginResultinstead. -
FBSendButton.ImpressionTrackingEventName/FBShareButton.ImpressionTrackingEventNameare not bound — their type isFBSDKCoreKit'sAppEvents.Name(anNS_TYPED_EXTENSIBLE_ENUM), which does not resolve across the module boundary into FBSDKShareKit, so both properties are dropped. The buttons themselves work; only this analytics-labelling knob is missing. Known upstream. -
Fourteen FBSDKCoreKit members typed by
FBSDKCoreKit_Basicsprotocols fail closed — elevenconfigureWith…/init…dependency-injection seams plus theDataStore,FileManagerandNotificationCenterproperties. Cross-assembly ObjC type resolution is not implemented, so rather than binding to the sibling assembly's real type they are omitted. Every one of them is a FacebookINTERNAL - DO NOT USEsurface, so no public API is lost. This is the residual of theMT4118fix described below. -
Deprecated upstream members carry
[Obsolete]—Settings.AutoLogAppEventsEnabled(useIsAutoLogAppEventsEnabled),Settings.AdvertiserTrackingEnabled(useIsAdvertiserTrackingEnabled),ShareDialog.ModeKind.Web/.FeedBrowser/.FeedWeb. Follow the message. -
Internal
_-prefixed types are bound but are not API —_BridgeAPI,_WebDialog,_ErrorFactory,_LoginCompletionParametersand friends are marked "INTERNAL — DO NOT USE" upstream and can change without notice. Likewise, mostI…interfaces exist so Swift-vended values can be handed back to you, not so you can implement them;ISharingDelegateis the notable exception. -
Older SDK note: under SDK 0.18.0,
FBSDKCoreKit's binding re-declared seven native names also owned byFBSDKCoreKit_Basics(FBSDKCrashHandler,FBSDKCrashObserving,FBSDKDataPersisting,FBSDKFileDataExtracting,FBSDKFileManaging,FBSDKInfoDictionaryProviding,FBSDKNotificationDelivering), breaking the registrar (MT4118) and therefore every device and App Store build. That duplication was fixed in SDK 0.18.1 and remains fixed in 0.19.0, which these packages are built with — a plainusing FBSDKCoreKit_Basics;alongsideusing FBSDKCoreKit;is no longer ambiguous. The only leftover is the fourteen internal DI seams noted above.
The binding is a faithful projection of Meta's SDK, not a re-design. For full API semantics — permission names, event names, dialog behaviour, review requirements — consult Meta's own documentation and translate the names using the table above.
- Facebook SDK for iOS — documentation home — component SDKs, getting started, advanced topics
-
Getting Started with the iOS SDK — the canonical
Info.plist+ app-delegate setup this guide translates - Facebook Login for iOS — permissions, Limited Login, access tokens, review
- Sharing on iOS — content types, dialog modes, App Links
- App Events for iOS and the standard events reference — the event- and parameter-name strings
- Graph API reference — endpoints, fields, versions
- Aggregated Event Measurement — what FBAEMKit implements
- facebook/facebook-ios-sdk — upstream source, changelog, and release notes (these packages track v18.1.0)
- Meta App Dashboard — where your app ID and client token live
-
ActivityKit —
SwiftBindings.Apple.ActivityKitv26.2.9 -
CryptoKit —
SwiftBindings.Apple.CryptoKitv26.2.9 -
FamilyControls —
SwiftBindings.Apple.FamilyControlsv26.2.9 -
LiveCommunicationKit —
SwiftBindings.Apple.LiveCommunicationKitv26.2.9 -
Matter —
SwiftBindings.Apple.Matterv26.2.9 -
MatterSupport —
SwiftBindings.Apple.MatterSupportv26.2.9 -
MusicKit —
SwiftBindings.Apple.MusicKitv26.2.9 -
ProximityReader —
SwiftBindings.Apple.ProximityReaderv26.2.9 -
RealityFoundation —
SwiftBindings.Apple.RealityFoundationv26.2.9 -
RealityKit —
SwiftBindings.Apple.RealityKitv26.2.9 -
RoomPlan —
SwiftBindings.Apple.RoomPlanv26.2.9 -
StoreKit2 —
SwiftBindings.Apple.StoreKit2v26.2.9 -
TipKit —
SwiftBindings.Apple.TipKitv26.2.9 -
Translation —
SwiftBindings.Apple.Translationv26.2.9 -
WeatherKit —
SwiftBindings.Apple.WeatherKitv26.2.9 -
WorkoutKit —
SwiftBindings.Apple.WorkoutKitv26.2.9
-
BlinkID —
SwiftBindings.BlinkIDupstream 7.8.0 -
BlinkIDUX —
SwiftBindings.BlinkIDUXupstream 7.8.0 -
Facebook —
SwiftBindings.Facebook.*upstream 18.1.0 -
Kingfisher —
SwiftBindings.Kingfisherupstream 8.11.0 -
Lottie —
SwiftBindings.Lottieupstream 4.6.1 -
MapLibre —
SwiftBindings.MapLibreupstream 6.28.0 -
Mappedin —
SwiftBindings.Mappedinupstream 6.7.0 -
Nuke —
SwiftBindings.Nukeupstream 13.0.6 -
Stripe —
SwiftBindings.Stripe.*upstream 26.4.1