HappyOyster iOS SDK 入口為處理程序級單例 HappyOysterEngine.shared,業務方法均為 async throws,失敗時拋出 OysterSDKError。一次體驗由 OysterTravel 控制代碼承載,支援 UIKit 與 SwiftUI。
核心概念
先確立幾個名詞,以便閱讀後文。
概念 | 說明 |
|---|---|
token | HTTP 驗證 token(百煉臨時 API Key)。由您的伺服器呼叫百煉介面換取後下發,經 |
ticket | 一次性體驗憑證。由您的伺服器呼叫開放平台 |
World | AI 世界,含角色、場景。由您的伺服器建立與管理,SDK 不涉及。 |
Travel | 一次即時體驗對應一個 |
工作階段狀態 |
|
模式 |
|
概覽
整合本 SDK 後,您的 App 可進入由 AI 即時生成的「世界」,以世界探索模式(adventure)、即時導演模式(directing)或角色演繹模式(acting)進行即時互動視訊體驗:開始體驗 → 即時播放 → 即時互動 → 過程控制(暫停/恢復/回溯/結束)→ 狀態與錯誤回調。
各模式可用的能力不同,請按 start() 傳回的 mode 決定 UI:
能力 | adventure | directing | acting |
|---|---|---|---|
| 支援 | 不支援 | 不支援 |
| 不支援 | 支援 | 支援 |
| 不支援 | 支援 | 支援 |
| 不支援 | 支援 | 不支援,請隱藏入口 |
| 支援 | 支援 | 支援 |
| 生效 | 忽略 | 忽略 |
acting 世界以直向螢幕優先:start() 返回的 aspectRatio 提供本次體驗的畫幅比例(9:16 / 16:9),建議在拉流前據此決定播放器方向與容器尺寸(詳見「資料模型」章節)。import HappyOysterSDK,核心入口是兩個類型。
HappyOysterEngine —— 編排入口,處理程序級單例 HappyOysterEngine.shared。
方法 / 屬性 | 說明 |
|---|---|
| 初始化執行階段並自動註冊即時引擎( |
| 注入 / 更新 HTTP 驗證 token |
| 使用一次性憑證建立工作階段控制代碼 |
| 釋放資源(可再 |
| 目前 SDK 版本號 |
OysterTravel —— 單次體驗的工作階段控制代碼,由 createTravel(ticket:) 建立。
方法 / 屬性 | 說明 |
|---|---|
| 播放檢視(UIKit / SwiftUI) |
| 狀態變更 + 錯誤推送串流 / 可觀察的目前狀態 |
| 建立連線播放(可選請求世界探索模式體驗的最大時長) |
| 即時導演模式文字指令 |
| 世界探索模式操控 |
| 暫停 / 恢復( |
| 回溯(僅限 paused) |
| 結束(冪等,務必呼叫) |
| 暫時釋放 / 恢復麥克風 |
OysterLog 用於接管 SDK 內部日誌;HappyOysterEngine.version 讀取版本號;OysterVideoView 是 SwiftUI 播放檢視(與 videoView 等效)。用法詳見後文。
生命週期:初始化 → 注入 token → 建立工作階段 → 掛載視訊與訂閱事件 → start 播放 → 互動 → end。SDK 不負責世界的建立與管理(由您的伺服器完成),也不公開底層即時通訊細節。
快速上手
一段從初始化到結束的完整流程,逐步註解。各 API 的細節見「API 參考」章節。
環境需求
項目 | 要求 |
|---|---|
最低系統版本 | iOS 15.0+(公開類型均標記 |
語言 | Swift( |
並行處理 | 主執行緒存取(入口類型標記 |
網路 | 需可存取公網 |
權限 |
|
Info.plist 必須提供 NSMicrophoneUsageDescription,否則啟動即時採集時會崩潰。當您需要獨佔麥克風(如語音辨識)時,請使用 pauseLocalAudioCapture() / resumeLocalAudioCapture() 暫時釋放與恢復(詳見「OysterTravel」章節)。
引入與驗證
引入與相依性
程式碼層面 import HappyOysterSDK 即可。SDK 以預編譯二進位檔(xcframework)按 CocoaPods subspec 分發,已發佈至 CocoaPods 公開 Trunk——請在 Podfile 中宣告相依性:
HappyOysterSDK/StreamAliRTC 時 AliVCSDK_ARTC 為必要項目:若缺失,SDK 會靜默回落 Loopback——能連上且狀態走到 running,但會黑屏且不報錯。驗證模型
SDK 不獲取、不重新整理 token,保持輕量。驗證分為兩層,整合方負責生命週期管理:
- HTTP 驗證 token(百煉臨時 API Key):由您的伺服器呼叫百煉介面換取後下發,經
updateToken(_:)注入。SDK 內部部分服務直接呼叫百煉閘道,並攜帶該 token 進行驗證——因此它必須是百煉端簽發的臨時 API Key,而非您自有業務服務的 token。SDK 僅保存最新一個,不持久化、不重新整理;過期後由您重新換取並再次注入。 - 一次性體驗憑證
ticket:由您的伺服器呼叫開放平台get-travel-credential換取(前綴tk_,有效期 30 分鐘,一次性),作為createTravel(ticket:)的輸入參數;體驗結束(正常或異常)或過期後即失效,不可重複使用。
start / pause / resume / rewind / sendInstruct / sendCommand)會被拒絕並透出 108001,進行中的體驗會被 SDK 主動終止(詳見「錯誤碼」章節);OysterSDKError.raw 中帶有可讀的停用原因,版本過低時請引導使用者升級。updateToken(_:) 注入。有兩處需判斷 token 是否過期:
- 呼叫
engine.createTravel、travel.start等 API 時,處理 error,判斷 token 過期或無效的 error 類型(101001/101002),注入新 token 後重新呼叫對應 API。 - 監聽
OysterTravelEvent的.error事件時,判斷 token 過期或無效的 error 類型,重新請求 token 並注入。
API 參考
入口為兩個類型,均標註 @MainActor、@available(iOS 15.0, *)。業務方法為 async throws,失敗時拋出 OysterSDKError;有返回值的方法均標註 @discardableResult。
HappyOysterEngine
處理程序級單例,編排入口。init 非 public——請統一使用 HappyOysterEngine.shared,切勿自行實體化(底層即時引擎亦為處理程序單例)。
initialize(config:)
初始化執行階段並自動註冊即時引擎(無需宿主手動註冊)。
使用時機:createTravel 前呼叫一次,App 啟動後盡早呼叫。
注意:空閒時再次呼叫即以新 config 重新裝配(更換 apiHost / model 都不必先 cleanup(),已注入的 token 會保留);僅當有進行中的 Travel 時為 no-op 並發出警告,需先 end()。config 無效時維持現狀,已生效的運行環境不受影響。
簽章
傳回值
Bool —— 本次傳入的 config 是否已生效。false 有兩種情況:config 無效(apiHost / model 為空或無法組合出合法閘道 URL),或有進行中的 Travel 導致本次呼叫被忽略;這兩種情況下運行環境皆維持原狀。
isReady 判斷成敗:若重新 initialize 被拒,先前的 config 仍在生效,isReady 依舊為 true。isReady 回答的是「引擎現在可用嗎」,而本返回值回答的是「我剛傳的這份 config 生效了嗎」。參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 是 |
|
mode 一一對應:按模式拆分後,每個模型是一條獨立的閘道路由,一次 initialize 僅服務一種 mode 的世界。若您的 App 同時提供多種模式的世界,在進入不同模式的世界前使用對應模型再 initialize() 一次即可——空閒時以最新 config 為準,不需要 cleanup(),已注入的 token 也會保留;若有進行中的 Travel,該呼叫會被忽略,需先 end()。當模型與世界 mode 不匹配時,閘道會以 AccessDenied 拒絕並歸一為 106003。OysterLog
設定並接管 SDK 內部的日誌,輸出至您自己的日誌模組。提供 setMinimumLevel(_:) 設定等級、setHandler(_:) 自訂列印(詳見「快速入門」範例)。
updateToken(_:)
注入 / 更新 HTTP 驗證 token(百煉臨時 API Key,見「驗證模型」章節)。
使用時機:initialize 之後可隨時呼叫;token 過期或收到驗證類錯誤(101001 / 101002)後重新換取並再次呼叫。
注意:未 initialize 時為 no-op 並發出警告。
簽章
參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 是 | HTTP 驗證 token(百煉臨時 API Key,見「驗證模型」章節)。 |
createTravel(ticket:)
使用一次性 ticket 建立一次工作階段控制代碼。
使用時機:每次開始新體驗前呼叫;返回的控制代碼尚未建立連線,需再呼叫 travel.start()。視訊畫面從返回的控制代碼取得(詳見「OysterTravel」章節)。
注意(同步 throws):未 initialize 時拋出 100001;上一個 Travel 未 end() 前再次呼叫則拋出 103004(每個 engine 同時僅允許一個 active Travel)。
簽章
參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 是 | 一次性憑證,建立後即視為本次體驗佔用。 |
傳回值
返回OysterTravel 工作階段控制代碼;尚未建立連線,需再呼叫 start()。
錯誤
code | 說明 |
|---|---|
| 未 |
| 上一個 Travel 未 |
cleanup()
釋放 SDK 資源(結束 active travel、執行階段設定、token)。
使用時機:徹底退出 SDK 或需要更換 config 時。
注意:async——內部會先確定性地 end() 目前的 active travel,再拆解運行環境,不留 fire-and-forget。釋放後可再次 initialize。
簽章
OysterTravel
由 createTravel 建立的工作階段控制代碼;僅限單次使用,到達終止狀態(end / 伺服器端結束 / 失敗)後即失效,需透過 engine 重新 createTravel。同時也是 ObservableObject(@Published status,可直接驅動 SwiftUI)。
videoView / OysterVideoView(travel:)
遠端畫面渲染入口,「SDK 提供檢視、宿主負責擺放」。UIKit 取 travel.videoView;SwiftUI 使用 OysterVideoView(travel:)。
使用時機:建立控制代碼後即可取得(多次存取返回同一檢視),掛載至任意層級,引擎就緒後自動渲染,start() 前後掛載均可,不會黑屏。
注意:工作階段結束時 SDK 會自動釋放渲染繫結,您可按需將檢視移出層級。
簽章
events / status / isEnded
events 是狀態變更與錯誤的推送串流;status 是可觀察的目前對外狀態;isEnded 可同步讀取是否為終止狀態。
使用時機:建議在 start() 之前就開始消費 events,避免遺漏早期狀態。
注意:每次存取 events 會返回一條獨立串流,支援多重訂閱;取消訂閱等同於結束 for await 迭代(或銷毀持有的 Task)。SwiftUI 可直接使用 @StateObject/@ObservedObject 觀察 status(錯誤仍走 events)。詳見「事件與狀態」章節。
簽章
start() / start(maxExperienceTimeSec:)
使用 create 時捕獲的 ticket 換取 travel 與 RTC 入會設定並建立連線播放。成功後 SDK 會自動建立即時連線並開始內部狀態輪詢,狀態經 events 透出。
注意(無推流自動結束):伺服器下發「無推流逾時」(預設約 30s)。若建立連線後在該時長內仍未收到推流(遲遲未進入 running),SDK 會自動結束本次體驗,狀態轉為 failed、經 events 的 .error 透出 105006(致命,請按回到開始前介面處理,無需自行計時)。
簽章
參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 否 | (選用)——請求本次世界探索(adventure)體驗的最大持續時長(秒)。參數會原樣傳送給伺服器,允許值、實際生效時長與到期自動結束時機均由伺服器決定,SDK 不做本機驗證;傳 |
傳回值
OysterStartTravelData(mode / version / encryptedTravelId 等,詳見「資料模型」章節),據此決定互動 UI。
ticket 的世界 mode 必須與 initialize 傳入的 model 匹配(由呼叫方保證):模型按 mode 拆分後,每個模型是一條獨立的閘道路由,start() 是將 ticket 傳往目前模型那條路由。SDK 不會也無法在呼叫前替您驗證這一點——mode 由本次 start() 的回應下發(即 OysterStartTravelData.mode),呼叫前 SDK 手中只有不透明的 ticket 和模型名稱,沒有可比對的 mode;而從模型名稱反推 mode 屬於對伺服器命名的猜測,SDK 不會執行此操作。因此:切換至另一種 mode 的世界之前,請使用對應模型再 initialize() 一次(空閒時以最新 config 為準,無需 cleanup(),token 會保留;若有進行中的 Travel,該呼叫會被忽略,需先 end())。若不匹配,本次 start() 會在閘道端失敗,排查時請優先核對「目前 model 與本次 ticket 所屬世界的 mode 是否成套」,再查看下表的憑證類錯誤碼。錯誤
code | 說明 |
|---|---|
| 憑證無效(亦包括:憑證有效,但所屬世界的 |
| 憑證已使用 |
| 世界未就緒 |
| 目前規格未開通(如角色演繹(acting)規格) |
| 併發已滿 / 可用容量不足 |
| 資源/服務端失敗 |
| 並行啟動 |
pause() / resume()
暫停 / 恢復體驗(冪等)。
使用時機:directing(即時導演)與 acting(角色演繹)世界支援,adventure 不支援。可使用 start() 返回的 mode 提前決定是否顯示暫停按鈕。pause 要求目前為 running;resume 要求為 paused。
簽章
返回值
返回OysterTravelStateData(欄位見「数据模型」章節)。
錯誤
code | 說明 |
|---|---|
| 無活躍體驗 |
| 狀態/版本不允許 |
| 模式不匹配 |
rewind(toSec:)
回溯至指定秒數。成功後 SDK 會自動使用原始 rtcConfig 重新加入會議並回到播放。
使用時機:僅 paused 狀態可發起,且只有 directing(即時導演)世界支援——acting 與 adventure 均不支援回溯,請在這兩種模式下隱藏回溯入口,切勿呼叫。
簽章
參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 是 | 回溯到的目標秒數。 |
返回值
返回OysterRewindTravelData(欄位見「数据模型」章節)。
錯誤
code | 說明 |
|---|---|
| 無活躍體驗 |
| 狀態不允許 |
end()
結束體驗(具冪等性,可重複呼叫)。呼叫成功或異常退出後,SDK 會自動斷開即時連線、停止輪詢並釋放所有工作階段資源,ticket 同時失效,控制代碼進入終止狀態。
使用時機與注意事項:無論使用者主動退出或被動結束(計時到期、收到 .ended/.failed、頁面銷毀),都必須確保執行一次 end(),否則遠端資源釋放可能不及時。建議將所有退出路徑收斂至同一個冪等清理方法。
簽章
返回值
返回OysterEndTravelData(欄位見「数据模型」章節)。
sendInstruct(content:)(即時導演模式)
傳送文字指令驅動劇情。
使用時機:即時導演模式;running 時直接傳送,paused 時暫存、待 resume 重新連入 running 後隨首幀補傳。
簽章
參數
欄位 | 類型 | 是否必填 | 描述 |
|---|---|---|---|
|
| 是 | 要傳送的文字指令內容。 |
返回值
返回OysterSendInstructData(欄位見「数据模型」章節)。
錯誤
code | 說明 |
|---|---|
| 無活躍體驗 |
| 狀態不允許 |
| 在世界探索模式下呼叫 |
| 輸入內容違規(內容安全審查) |
| Travel 不存在 |
sendCommand(_:) / flushCommands()(世界探索模式)
sendCommand:傳送方向/視角/動作控制指令(詳見「資料模型」章節OysterAdventureCommand,fire-and-forget,無返回值、不 throws)。僅於世界探索模式且為running時有效。外部可每幀高頻持續輸入,SDK 內部會進行節流(latest-wins 取樣、按 RTC 線速合幀),宿主無需自行節流。請注意伺服器對指令的回應本身有延遲,實際生效時間並不固定。flushCommands:於「放開按鍵 / 輸入釋放」瞬間呼叫,立即補傳佇列中已等待的最後一條指令;若無待傳指令則為純 no-op,不會產生新指令。
簽章
錯誤
code | 說明 |
|---|---|
| 無活躍體驗 |
| 在即時導演模式下呼叫 |
| 即時通道未就緒/傳送失敗 |
events 的 .error 透出,非 throws。)
pauseLocalAudioCapture() / resumeLocalAudioCapture()
暫時釋放 / 恢復 SDK 對本機麥克風採集的佔用。
使用時機:語音辨識等需要獨佔麥克風時先 pause,結束後 resume。
簽章
事件與狀態
事件掛在 OysterTravel.events 上,是 SDK 對您的主動推送通道,用於透出非您主動呼叫所觸發的情況(例如內部自動維護的即時連線或狀態輪詢出現問題)。
- SwiftUI:
OysterTravel是ObservableObject,可直接透過@StateObject/@ObservedObject觀察status驅動 UI;錯誤仍從events取得。 - 命令式 / UIKit:在
Task中使用for await event in travel.events { ... },並以switch處理.statusChanged/.error;結束時取消持有的Task。
OysterTravelStatus(5 個過程態 + 2 個終態):
狀態 | 說明 | 典型處理 |
|---|---|---|
| create 後、start 前 | — |
| 建立連線 / 重新連線中(內部 connecting / reconnecting) | 顯示連線 / 重新連線提示 |
| 串流已就緒、可互動(內部 playing) | 顯示畫面與操控 |
| 暫停已受理、等待伺服器確認 | 顯示「暫停中…」 |
| 已暫停(確認) | 顯示暫停狀態(僅 |
| 已結束(主動 end 或伺服器端結束)。終態 | 收尾並关闭頁面 |
| 失敗。終態 | 顯示錯誤並收尾 |
ended / failed 後工作階段即終止,所有工作階段操作(pause/resume/sendCommand…)均不再生效。回調可能在主執行緒觸發,可直接用於更新 UI。資料模型
@available(iOS 15.0, *)。下列返回值與參數為 SDK 輸出參數,由內部就地建構並使用 Swift 原生類型(Date / TimeInterval / OysterTravelStatus),並非 Codable、也不公開 wire(snake_case)細節——wire 解碼發生在 SDK 內部。- 操控指令 rawValue 為小寫駝峰命名(如
front/mouseLeft/jump),以上述列舉值為準。 mode對外取值為adventure(世界探索)/directing(即時導演)/acting(角色演繹),以OysterModeValue定義為準。aspectRatio為開放字串(目前為9:16/16:9,後續可能擴充)。判斷橫向或直向螢幕時請按宽:高解析比例,請勿窮舉已知值。
錯誤碼
SDK 統一以 OysterSDKError 回報錯誤,類型一律透過 code 區分,請勿依據「從哪條路徑取得的錯誤」來判斷類型——同一個 code 既可能從業務方法(async throws)拋出,也可能經 events 的 .error 透出。需要型別化匹配時請使用 error.kind(詳見「資料模型」章節 OysterErrorKind)。
錯誤碼:伺服器端4xxxxx/5xxxxx,用戶端本機1xxxxx。
伺服器錯誤碼(常見)
code | 含義 | 建議處理方式 |
|---|---|---|
| 參數非法(列舉非法等) | 檢查請求參數或 SDK 版本 |
| 體驗憑證( | 讓伺服器端重新下發憑證 |
| 體驗憑證( | 憑證一次性,重新下發 |
| World 不存在、已刪除或不屬於目前開發者(含憑證內世界已刪除) | 重新選擇有效 World |
| 世界狀態非就緒 | 等世界就緒後再開始 |
| 當前介面僅允許主 API Key | 臨時 Key 不可用於此介面 |
| 輸入內容違規(內容安全審查);適用於 | 修改輸入內容後重試 |
| 目前規格未開通 | 不可依容量已滿重試;請更換已開通的規格或聯絡開通(典型情況:帳號未開通角色演繹(acting)規格) |
| 容量配置暫不可用 | 稍後重試 |
| 資源不存在(世界 / Travel 歸屬或無產物) | 核對 ID / 狀態 |
| 請求與目前資源狀態衝突 | 檢查體驗狀態 |
| 目前規格併發已滿 | 待現有工作階段結束後重試(請勿與 |
| 目前可用容量不足 | 稍後重試 |
| 系統內部錯誤 | 稍後重試 / 回饋 |
| 推理資源分配/服務內部失敗 | 稍後重試 |
用戶端本機錯誤碼
code | 含義 | SDK 是否自動終止工作階段 | 建議處理方式 |
|---|---|---|---|
| SDK 未初始化即呼叫;亦包括 | 否(同步擲回,拒絕此次呼叫) | 先 |
| 未注入 HTTP 驗證 token | 否 |
|
| HTTP 驗證 token 無效 / 被拒 | 否 | 重新換取 token 後 |
| 目前無活躍體驗 | 否(拒絕該次呼叫) | 先 |
| 目前狀態/版本不允許此操作 | 否(拒絕該次呼叫) | 檢查體驗狀態 / |
| 模式不匹配(例如非 | 否(拒絕該次呼叫) | 按 |
| 並行建立/開始體驗 | 否(同步擲回) | 序列化呼叫,先 |
| 即時連線失敗 | 是 | 結束並重新開始 |
| 即時入會逾時 | 是 | 結束並重新開始 |
| 等待視訊首幀逾時 | 是 | 結束並重新開始 |
| 即時通道未就緒/傳送失敗 | 依場景而定(主動傳送失敗;心跳僅上報) | 待 |
| 回呼逾時(預設 30s) | 否 | 重試,必要時調大 |
| 加入會議後無推流,SDK 自動結束體驗 | 是 | 結束並重新開始 |
| 本機網路錯誤 | 否 | 可重試 |
| 回應解析失敗 | 依場景 | 升級 SDK / 回饋 |
| 未攜帶可識別錯誤碼 / 代理字串錯誤碼 | 否 | 可重試 |
| 被伺服器功能開關遠端停用(整體關閉或版本過低;原因見 | 是 | 按 |
OysterSDKError 沒有 isFatal)。語義上「致命」專指 SDK 是否主動終止工作階段(斷開 RTC、釋放整次工作階段)——
- 會自動終止工作階段的錯誤(如
105001/105002/105003/105006/108001):宿主從狀態機終止狀態感知(status → failed,經events的.statusChanged透出),據此回到「開始體驗」前的介面即可,無需自行判定致命性。 - 呼叫拒絕類錯誤(
100001/103001/103002/103003/103004):在您主動呼叫時同步拋出或拒絕該次呼叫,不會終止工作階段。 - 其餘非致命錯誤(如
101001/101002/105005/106001/106003):不會終止工作階段,請依建議重試或重新注入 token 後繼續。
106001 可能有兩種原因:本機網路錯誤,或 apiHost 設定錯誤。若重試無法恢復,請檢查 apiHost 是否設定正確。106003 若在填寫 model 後出現,請優先檢查模型名稱及版本是否正確、是否已為目前帳號開通,並確認 apiHost、token 與模型屬於同一帳號和區域——不匹配時閘道會以 AccessDenied 拒絕並歸一至此錯誤碼。