macOS

The iOS package is a macOS package too — one Swift Package, one AppEngine, the same delegate. This page covers only what is different on the desktop: windows instead of view controllers, and sandbox entitlements on top of the Info.plist prompts.

Requirements#

Minimum
macOS11 Big Sur
Xcode15
Swift5.9
ArchitecturesApple silicon and Intel (universal xcframework)

Installation#

Add the package to your Mac target exactly as on iOS. The manifest declares both platforms.

Package.swift
dependencies: [
.package(url: "https://github.com/AppLooma-RTC/iOS-SDK", from: "0.6.1")
],
targets: [
.target(name: "MyMacApp", dependencies: [
.product(name: "AppLoomaRTC", package: "iOS-SDK")
])
]

In Xcode: File → Add Package Dependencies…, paste the URL, and addAppLoomaRTC to your macOS target.

Sandbox and entitlements

A sandboxed Mac app must ask for the network and the hardware explicitly, or the call connects and no audio ever leaves the machine.

MyMacApp.entitlements
<key>com.apple.security.network.client</key> <true/>
<key>com.apple.security.device.audio-input</key> <true/>
<key>com.apple.security.device.camera</key> <true/>
Info.plist
<key>NSCameraUsageDescription</key>
<string>Shows you to the people you are calling.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Lets the people you are calling hear you.</string>

Screen share on the Mac

Screen share from the Swift SDK is on the roadmap. If your product needs it today, the Electron path ships with window and display picking built in.

A minimal call window#

CallWindowController.swift
import AppKit
import AppLoomaRTC
final class CallWindowController: NSWindowController, AppEngineDelegate {
private lazy var engine = AppEngine.create(appId: "YOUR_APP_ID", delegate: self)
private let remoteView = AppVideoView()
private let localView = AppVideoView()
func start(token: String, wsUrl: String) {
let content = NSView(frame: NSRect(x: 0, y: 0, width: 960, height: 600))
remoteView.frame = content.bounds
remoteView.autoresizingMask = [.width, .height]
localView.frame = NSRect(x: 780, y: 420, width: 160, height: 160)
content.addSubview(remoteView)
content.addSubview(localView)
window?.contentView = content
Task {
try await engine.joinChannel(token: token, wsUrl: wsUrl,
options: AppJoinOptions(role: .host, camera: true))
localView.attachLocal(engine: engine)
}
}
func appEngine(_ engine: AppEngine, trackSubscribedFor user: AppRemoteUser) {
remoteView.attach(user: user)
}
func windowWillClose(_ notification: Notification) {
Task { await engine.leaveChannel() }
}
}

SwiftUI

AppVideoView is an NSView on macOS. Wrap it once withNSViewRepresentable and use it like any other view.

RemoteVideo.swift
struct RemoteVideo: NSViewRepresentable {
let user: AppRemoteUser
func makeNSView(context: Context) -> AppVideoView { AppVideoView() }
func updateNSView(_ view: AppVideoView, context: Context) { view.attach(user: user) }
}

Cameras and microphones#

  • The SDK follows the system default camera and microphone; when the user changes it in System Settings, the call follows. A per-call device picker is on the roadmap.
  • Nothing to do for Bluetooth or USB audio: macOS routes to whatever the user has selected in the menu bar.
  • Video publishes at 1080p with simulcast by default, the same as every other platform.

Differences from iOS#

iOSmacOS
Rendering viewUIViewNSView
Background audioNeeds the audio background modeRuns while the window is hidden; nothing to declare
Permission promptOn first use, per appOn first use, plus the sandbox entitlements above
Screen shareRoadmapRoadmap (use Electron today)
CameraFront and backBuilt-in or the system default external camera