This is the shortest onboarding path for iOS integrators: from initialization, to getting the picture on screen, to sending control instructions, to ending the experience. For the complete method signatures, fields, and error codes, refer to the iOS SDK API Reference.
0. What You Will Build
A minimal end-to-end loop of "enter a world → real-time video experience → interact → end". The runtime entry points are the global HappyOysterEngine.shared and the single-use session handle OysterTravel it creates.
1. Requirements
Item | Requirement |
|---|---|
Minimum OS | iOS 15.0+ |
Language | Swift ( |
Threading | Public APIs are |
Import |
|
1.1 Add the SDK via CocoaPods
The SDK is distributed as a precompiled binary (xcframework) via CocoaPods subspecs, published to the public CocoaPods Trunk — reference it directly by version, no local podspec file needed.
pod install and open the generated .xcworkspace (not the .xcodeproj).
AliVCSDK_ARTC is required whenever you pull in HappyOysterSDK/StreamAliRTC: if it's missing, the SDK silently falls back to Loopback — it still connects and reaches running, but shows a black screen with no error.2. Two Kinds of Credentials (Understand These First to Avoid Pitfalls)
The SDK does not obtain or refresh any credentials on its own; you inject all of them:
Credential | Source | Purpose | How to Inject |
|---|---|---|---|
HTTP auth token | Your app fetches it from your own backend | General authentication for SDK calls to the gateway (long-lived, needs renewal) |
|
One-time ticket | Issued by your server after exchanging via the Travel credential API | Used for a single experience, invalidated immediately after use | Passed as the |
updateToken is for general auth, while ticket is a one-time join credential. AK / signing keys exist only on your server and are never exposed to the client.3. Integration Steps
Lifecycle: register the stream engine → initialize → inject token → create the session → attach video + subscribe to events → start → interact → end.
Step 1: Register the Stream Engine
The single entry point for rendering video. Call it once at app launch; repeated calls are safe.
Step 2: Initialize the SDK
You must initialize once before calling any other API. To switch gateway or model, just call it again — while idle the latest config wins and the injected token is kept; the call is ignored only while a travel is in flight, so end() it first.
Step 3: Inject the HTTP Auth Token (push)
Fetch a temporary QwenCloud API Key from your own backend and inject it. Re-inject after it expires.
Step 4: Create the Session Handle
Create an OysterTravel from a single-use ticket. Nothing is connected yet, but the video view is already available.
Step 5: Attach the Video View and Subscribe to Events
The SDK provides the view, the host places it. Subscribe before start() so you do not miss early status changes.
Step 6: Start the Experience
Connect and start playing. The SDK then automatically maintains the real-time connection and status polling, surfacing status through events.
start(maxExperienceTimeSec:) only applies to adventure; directing and acting ignore the parameter.model you passed to initialize in Step 2. With per-mode models (happyoyster-1.0-adventure / -directing / -acting), each model is its own gateway application route, so a single initialize serves worlds of one mode only; the ticket was issued by your server under the route of that world's mode, and start() sends it to the route of the currently configured model — a mismatch fails at this step.
Before entering a world of a different mode, call initialize() again with the matching model — no cleanup() and no re-updateToken():
mode only arrives in this step's response (data.mode); before the call the SDK holds nothing but an opaque ticket and a model name. Apps offering a single mode are unaffected and initialize once.
initialize() call is ignored with a warning — end() it first.Step 7: Real-Time Interaction (Pick One Based on Mode)
sendCommand throttles internally on a 42ms (24FPS) latest-wins cycle, so the host can call it at high frequency:
- One-shot actions such as jump, attack, crouch, and sprint are sent once.
- Movement and view rotation are sent continuously while held, and you simply stop calling on release.
- You do not need to send
noneor callflushCommands()on release; the SDK never generates a stop command on its own, and the server ends the action once the real-time channel goes quiet.
Step 8: Pause / Resume / Rewind (Mode-Dependent)
adventure supports none of these; acting supports pause/resume but not rewind — hide the rewind entry point in those modes. Mismatched calls are rejected locally by the SDK (103003 / 103002).Step 9: End the Experience
Disconnects, stops polling, and releases all session resources; the ticket is consumed. Idempotent — every exit path must funnel into it.
await engine.cleanup() when tearing down the SDK or switching gateways.4. Full Example (SwiftUI)
5. Best Practices
- Lifecycle: Call
OysterStream.register()+initialize()as early as possible at app launch, once each globally; always callend()when leaving the experience page to ensure the real-time connection and resources are released.OysterTravelis single-use — create a new one viacreateTravelafter it reaches a terminal state. - Token renewal: Make sure the HTTP token is fresh before starting an experience; when you receive an auth-related error callback, fetch a new token and call
updateToken(non-fatal, does not terminate the experience). - Error severity: For fatal errors, the SDK automatically terminates the current experience, surfaces them via the
.errorofevents, and settles into thefailedterminal state; you should return to the screen shown before "start experience". Non-fatal errors are only surfaced and can be retried. See the full error code table in the API Reference. - Mode adaptation: Directing and acting modes show a text input (
sendInstruct); adventure mode shows control widgets (sendCommand). Only directing shows a rewind entry point. For acting worlds, pick the player orientation fromaspectRatio(portrait9:16by default).
6. Next Steps
- Full API (
pause()/resume()/rewind(toSec:), data models, error codes) → iOS SDK API Reference