跳轉到

Initialization and configuration

Revue.shared is the entry point of the SDK. Before you can add friends, invite them or publish tracks, start the SDK with initialize(_:). When you are done, shut it down with destroy(). Call both on the main thread.

Initialize

initialize(_:) takes a Revue.Configuration. Two fields are required:

  • licenseData: the bytes of your license file. Without it, initialize(_:) throws RevueInitError.
  • bootstrapNodes: the nodes the SDK uses to join the network. The SDK has no built-in list; see Connection for nodes you can use.

initialize(_:) throws a RevueInitError when the license is missing, malformed, invalid or expired, or when the configuration is invalid. Once it returns, Room.localParticipant on Room.shared is ready.

Right after initialize(_:) returns, add your delegates to Revue.delegates and Room.delegates, on Revue.shared and Room.shared:

import RevueSDK
import Foundation

/// Start the SDK, then register your delegates. `destroy()` removes every delegate,
/// so register them again after every `initialize(_:)`.
@MainActor
func startRevue(licenseData: Data, bootstrapNodes: [Revue.BootstrapNode],
                delegate: RevueDelegate & RoomDelegate) throws {
    let config = Revue.Configuration(bootstrapNodes: bootstrapNodes, licenseData: licenseData)
    try Revue.shared.initialize(config)

    Revue.shared.delegates.add(delegate: delegate)
    Room.shared.delegates.add(delegate: delegate)
}

Configuration

Field Default Meaning
licenseData nil License file bytes. Required.
bootstrapNodes none Nodes used to join the network. Required.
savedataFileName nil (revue.bin) File name of the identity save file, without a path. It must not contain / or ...
savedataPassword nil Password that encrypts the save file.
networkOptions Revue.NetworkOptions.default Transport switches and port range. Read only at initialize.
mqttOptions nil Presence service settings. nil uses the built-in service. .deferred starts presence later; see Start presence after sign-in.

Every field is read once, by initialize(_:). To change one, destroy the SDK and initialize it again.

Start presence after sign-in

An App that has no MQTT account at launch can initialize first and start presence later. Set mqttOptions to Revue.MqttOptions.deferred: initialize(_:) then does not contact the broker and sends no presence events. Calls and friend connections work as usual. Call startPresence(_:) once you have the account:

import RevueSDK
import Foundation

/// Start the SDK without presence, because there is no MQTT account yet.
@MainActor
func startRevueWithoutPresence(licenseData: Data, bootstrapNodes: [Revue.BootstrapNode],
                               delegate: RevueDelegate & RoomDelegate) throws {
    let config = Revue.Configuration(bootstrapNodes: bootstrapNodes, licenseData: licenseData,
                                     mqttOptions: .deferred)
    try Revue.shared.initialize(config)

    Revue.shared.delegates.add(delegate: delegate)
    Room.shared.delegates.add(delegate: delegate)
}

/// After sign-in, start presence with the account. Call it again to switch accounts.
@MainActor
func startPresenceAfterSignIn(username: String, password: String) async throws {
    let options = Revue.MqttOptions(brokerUrl: "wss://broker.example.com/mqtt",
                                    username: username, password: password)
    try await Revue.shared.startPresence(options)
}

/// After sign-out, stop presence. Calls and friend connections keep working.
@MainActor
func stopPresenceAfterSignOut() async {
    await Revue.shared.stopPresence()
}
  • When startPresence(_:) returns without an error, the request has been sent. It does not mean presence is connected: wait for .connected in revue(_:didUpdatePresenceConnectionState:).
  • To switch accounts, call startPresence(_:) again with the new settings. The old connection closes first, so you get .notInitialized, then .connected. Calls run in the order you made them.
  • To sign out, call stopPresence(). You get .notInitialized once, and calls and friend connections are not affected.
  • deferred applies to one initialize(_:). After destroy(), presence stays off until you call startPresence(_:) again.
  • Passing nil uses the built-in service. deferStart is ignored here.

已知問題

呼叫 stopPresence() 後,只要雙方的好友連線還在,好友可能看到這位使用者先變 .offline,又變回 .online 並一直維持。修好前,如果一定要讓好友看到離線,請呼叫 destroy()。

startPresence(_:) throws a RevuePresenceError:

Error Meaning
.notInitialized The SDK is not initialized, or destroy() is running.
.invalidConfiguration presenceQos is outside 0–2, or the core rejected the settings. The running connection is not affected.
.startFailed(code:) The connection request failed and presence is stopped.

Destroy

destroy() hangs up every call, stops the SDK and releases its network instance. It is async: wait for it to return before you initialize again.

By default destroy() keeps everything on disk. Pass a Revue.DestroyOptions to delete data after the SDK has stopped:

  • deleteSavedata: the identity save file of this session and the files that belong to it.
  • deleteRecordings: every recording.
  • Revue.DestroyOptions.deleteAllData sets both.
import RevueSDK

/// Shut the SDK down and delete the identity save file and every recording.
@MainActor
func signOutAndDeleteData() async {
    await Revue.shared.destroy(.deleteAllData)
}

Initialize again

Three rules apply every time you restart the SDK, for example after the user changes network settings:

  • destroy() removes every delegate from Revue.delegates and Room.delegates. Register your delegates again after every initialize(_:).
  • You cannot call initialize(_:) while the SDK is running; call destroy() first. Calling it too early throws RevueInitError, and the running instance is left as it is.
  • localParticipant is nil before initialize(_:) and after destroy(). Do not read it outside that window.
import RevueSDK

/// Apply a new configuration: destroy the running SDK, initialize it again, and register the delegates again.
@MainActor
func restartRevue(with config: Revue.Configuration, delegate: RevueDelegate & RoomDelegate) async throws {
    await Revue.shared.destroy()
    try Revue.shared.initialize(config)

    Revue.shared.delegates.add(delegate: delegate)
    Room.shared.delegates.add(delegate: delegate)
}