-
Notifications
You must be signed in to change notification settings - Fork 3
LiveCommunicationKit
Package
SwiftBindings.Apple.LiveCommunicationKit· Version26.2.6Auto-published fromapple-frameworks/LiveCommunicationKit/LIVECOMMUNICATIONKIT-GUIDE.md.
SwiftBindings.Apple.LiveCommunicationKit exposes Apple's LiveCommunicationKit framework — the modern VoIP / Live Communication API (CallKit's successor for VoIP "conversations") — to C# through .NET 10's native Swift interop. These are direct Swift calls, not Objective-C proxy wrappers.
This is an orientation guide: it walks the few entry points you build a VoIP integration around (the conversation manager, conversations, and the action types) and is honest about what requires a real app capability and a delegate. Every type, method, and enum case below is verbatim from the generated C#.
- Requirements & install
- Naming conventions
- Quick start
- The conversation manager
- Conversations
- Actions
- Handles & capabilities
- Telephony & history
- Known limitations
- Memory & threading
- Reference links
- .NET 10.0+
- iOS 26.2+, macOS 26.2+, Mac Catalyst 26.2+
- macOS host for development
- The LiveCommunicationKit / VoIP capability enabled on the app, plus a configured
Info.plist
dotnet add package SwiftBindings.Apple.LiveCommunicationKit
using LiveCommunicationKit;The co-located test app only exercises type metadata and plain enum round-trips, and only under
#if IOS. Conversation lifecycle calls need a real app with the VoIP capability and a wired-up delegate. Treat live behavior as device-only.
| Swift | C# | Rule |
|---|---|---|
func perform(...) async throws |
PerformAsync(...) |
async methods gain an Async suffix and return Task/Task<T>
|
obj.localMember |
obj.LocalMember |
properties are PascalCase |
nested struct Configuration / enum State
|
ConversationManager.ConfigurationType, Conversation.StateType
|
nested types that collide with a member get a Type suffix |
static var sharedInstance |
…SharedInstance |
Swift type-level singletons become static C# properties |
protocol ConversationManagerDelegate |
interface IConversationManagerDelegate |
Swift protocols project to I-prefixed C# interfaces |
OptionSet (Conversation.Capabilities) |
static singletons + ==/!=, not a flags enum |
combine/compare with the provided members and operators |
Every async method also accepts a trailing CancellationToken (defaulted).
You build the manager from a configuration, set a delegate, then report incoming/outgoing conversations and perform actions.
using LiveCommunicationKit;
// 1. Describe your VoIP app's capabilities
using var config = new ConversationManager.ConfigurationType(
ringtoneName: null,
iconTemplateImageData: null,
maximumConversationGroups: 1,
maximumConversationsPerConversationGroup: 5,
includesConversationInRecents: true,
supportsVideo: true,
supportedHandleTypes: new HashSet<Handle.Kind> { Handle.Kind.PhoneNumber, Handle.Kind.Generic });
// 2. Create the manager
using var manager = new ConversationManager(config);
// 3. Report an incoming call so the system shows the call UI
using var remote = new Handle(Handle.Kind.PhoneNumber, "+15551234567", displayName: "Alex");
using var update = new Conversation.Update(localMember: null,
members: new HashSet<Handle> { remote });
await manager.ReportNewIncomingConversationAsync(Guid.NewGuid(), update);ConversationManager is the central object. It is constructed from a ConfigurationType:
public partial class ConversationManager
{
public ConversationManager(ConversationManager.ConfigurationType configuration);
public IReadOnlyList<Conversation> Conversations { get; }
public IReadOnlyList<ConversationAction> PendingActions { get; }
public ConversationManager.ConfigurationType Configuration { get; }
public IConversationManagerDelegate? Delegate { get; set; }
public Task PerformAsync(IEnumerable<ConversationAction> actions, CancellationToken ct = default);
public Task ReportNewIncomingConversationAsync(Guid uuid, Conversation.Update update, CancellationToken ct = default);
public void ReportConversationEvent(Conversation.Event @event, Conversation conversation);
public static Task ReportNewIncomingVoIPPushPayloadAsync(IDictionary<Swift.AnyHashable, object> payload, CancellationToken ct = default);
public void Invalidate();
}ConfigurationType has two constructors (the second adds supportsAudioTranslation):
new ConversationManager.ConfigurationType(
string? ringtoneName, byte[]? iconTemplateImageData,
nint maximumConversationGroups, nint maximumConversationsPerConversationGroup,
bool includesConversationInRecents, bool supportsVideo,
IReadOnlySet<Handle.Kind> supportedHandleTypes);
new ConversationManager.ConfigurationType(
/* …same… */, bool supportsAudioTranslation);Wire up an IConversationManagerDelegate to receive callbacks. Its members:
public interface IConversationManagerDelegate
{
void ConversationManager(ConversationManager manager, Conversation conversation);
void ConversationManagerDidBegin(ConversationManager manager);
void ConversationManagerDidReset(ConversationManager manager);
void ConversationManager(ConversationManager manager, ConversationAction action);
void ConversationManager(ConversationManager manager, AVFoundation.AVAudioSession audioSession);
}Conversation is the call object the system tracks:
public partial class Conversation
{
public Guid Uuid { get; }
public Conversation.StateType State { get; } // Idle, Joining, Joined, Paused, Leaving, Left
public Handle? LocalMember { get; }
public string DebugDescription { get; }
}Conversation.Update describes the participants/capabilities of a conversation you report:
new Conversation.Update(
Handle? localMember = null,
IReadOnlySet<Handle>? members = null,
IReadOnlySet<Handle>? activeRemoteMembers = null,
Conversation.Capabilities? capabilities = null);Conversation.Event is a projected Swift enum (discriminate with .Tag against Conversation.Event.CaseTag: ConversationUpdated, ConversationStartedConnecting, ConversationConnected, ConversationEnded, …). Conversation.EndedReason (Failed, RemoteEnded, Unanswered, JoinedElsewhere, DeclinedElsewhere) explains a finished call.
All conversation operations are modeled as action structs; submit them with manager.PerformAsync(...). Each is constructed with the target conversation's UUID plus operation-specific arguments:
| Action | Constructor |
|---|---|
StartConversationAction |
new(Guid conversationUUID, IEnumerable<Handle> handles, bool isVideo) |
JoinConversationAction |
new(Guid conversationUUID) |
EndConversationAction |
new(Guid conversationUUID) |
MergeConversationAction |
new(Guid conversationUUID, Guid conversationUUIDToMergeWith) |
UnmergeConversationAction |
new(Guid conversationUUID) |
MuteConversationAction |
new(Guid conversationUUID, bool isMuted) |
PauseConversationAction |
new(Guid conversationUUID, bool isPaused) |
PlayToneAction |
new(Guid conversationUUID, string digits, PlayToneAction.ToneType tone) |
SetTranslatingAction |
new(Guid conversationID, bool isTranslating, Swift.Foundation.Locale.Language localLanguage, Swift.Foundation.Locale.Language remoteLanguage) |
StartCellularConversationAction |
new(Handle handle, CellularService? cellularService = null) or new(ConversationHistoryManager.RecentConversation recentConversation)
|
using var end = new EndConversationAction(conversationUuid);
await manager.PerformAsync(new[] { end });The action types share a ConversationAction base exposing Uuid, ConversationUUID, State (a projected enum — Failed/Idle/Running/Complete), and TimeoutDate.
PlayToneAction.ToneType = Single / SoftPause / HardPause.
SetTranslatingAction.TranslationEngine = Default / Custom.
A Handle identifies a participant:
using var handle = new Handle(Handle.Kind.PhoneNumber, "+15551234567", displayName: "Alex");
// Handle.Kind: Generic, PhoneNumber, EmailAddress
string value = handle.Value;
string display = handle.DisplayName;Conversation.Capabilities is an OptionSet-style value type with static members (Pausing, Merging, Unmerging, Video, PlayingTones) and ==/!= operators — combine and compare with those, not with C# flag enums.
Two singleton managers are exposed via static SharedInstance accessors:
var telephony = TelephonyConversationManager.SharedInstance;
await telephony.StartCellularConversationAsync(
new StartCellularConversationAction(handle));
var history = ConversationHistoryManager.SharedInstance;
await history.MarkConversationAsReadAsync(recentConversation);
await history.MarkConversationsAsReadAsync(recentConversations);ConversationHistoryManager.RecentConversation carries StatusType and DirectionType enums and a DecodeFromJson(byte[]) helper; CellularService (with Id and Label) describes an available cellular line.
- Live behavior is device + capability gated. Reporting conversations and performing actions requires the VoIP/LiveCommunicationKit capability on the app and a running system call UI. The bindings construct fine, but the validated surface here is metadata + enum values only.
-
The delegate is fully wired.
IConversationManagerDelegateis backed by a generatedConversationManagerDelegateProxywith vtable dispatch for all five methods. Implement the interface in C# and assign it tomanager.Delegate; Swift will call back through the proxy. Test on a physical device with the VoIP capability to exercise the full round-trip. -
No constructor on the singleton managers.
TelephonyConversationManagerandConversationHistoryManagerare reached only throughSharedInstance. -
Three niche APIs are not bound. A second overload of
pendingConversationActions(returning an opaque placeholder type),ConversationHistoryManager.makeMessage(unsupported placeholder return type), and the predicate-basedConversationHistoryManager.recentConversationsoverload (requiresFoundation.Predicate<…>which references SwiftUI/Combine) are commented out in the generated bindings. The primaryPendingActions,MarkConversationAsReadAsync, andMarkConversationsAsReadAsyncAPIs are fully bound. -
Synthesized
Codablemembers pruned. Several value types implement Swift'sCodableprotocol; theencode(to:)andinit(from:)members are intentionally omitted becauseEncoder/Decoderare unresolvable existential protocols. UseConversationHistoryManager.RecentConversation.DecodeFromJson(byte[])for JSON round-tripping where the framework provides it.
Generated types implement ISwiftObject / IDisposable. The action and configuration types wrap Swift structs; Conversation, ConversationManager, and the singleton managers are class wrappers. using var is the recommended pattern for deterministic cleanup — Dispose is safe on every generated type and double-Dispose is a no-op. Do not dispose the SharedInstance singletons.
using var config = new ConversationManager.ConfigurationType(/* … */);
using var manager = new ConversationManager(config);Async PerformAsync / Report*Async calls continue on a thread-pool thread; marshal back to your UI thread before touching UI.
- Apple — LiveCommunicationKit — upstream documentation
-
ActivityKit —
SwiftBindings.Apple.ActivityKitv26.2.6 -
CryptoKit —
SwiftBindings.Apple.CryptoKitv26.2.6 -
FamilyControls —
SwiftBindings.Apple.FamilyControlsv26.2.6 -
LiveCommunicationKit —
SwiftBindings.Apple.LiveCommunicationKitv26.2.6 -
Matter —
SwiftBindings.Apple.Matterv26.2.6 -
MatterSupport —
SwiftBindings.Apple.MatterSupportv26.2.6 -
MusicKit —
SwiftBindings.Apple.MusicKitv26.2.6 -
ProximityReader —
SwiftBindings.Apple.ProximityReaderv26.2.6 -
RealityFoundation —
SwiftBindings.Apple.RealityFoundationv26.2.6 -
RealityKit —
SwiftBindings.Apple.RealityKitv26.2.6 -
RoomPlan —
SwiftBindings.Apple.RoomPlanv26.2.6 -
StoreKit2 —
SwiftBindings.Apple.StoreKit2v26.2.6 -
TipKit —
SwiftBindings.Apple.TipKitv26.2.6 -
Translation —
SwiftBindings.Apple.Translationv26.2.6 -
WeatherKit —
SwiftBindings.Apple.WeatherKitv26.2.6 -
WorkoutKit —
SwiftBindings.Apple.WorkoutKitv26.2.6