2026.3.x から 2026.4.x への移行

2026.4.0 では Swift 6 言語モードに対応し、あわせて公開 API の一部を変更しました。 このドキュメントでは 2026.3.x から 2026.4.x へ移行する際に必要な対応をまとめています。

Swift 6 言語モードへの対応

概要

2026.4.0 の Package.swift は swift-tools-version が 6.3 で、 swiftLanguageModes: [.v6] により Swift 6 言語モードを宣言しています。 そのため Swift Package Manager で取り込んだ場合も SDK は Swift 6 言語モードでコンパイルされます。利用側で言語モードを指定する必要はありません。

swift-tools-version 6.3 の manifest を読むために Swift Package Manager 6.3 以降が必要です。 Swift Package Manager 6.3 は Xcode 26.6 に同梱されているため、 2026.4.0 以降を利用するには Xcode 26.6 以降が必要です。

利用側で必要な対応

SDK 側で公開型に Sendable 準拠を追加したため、利用側で独自に Sendable 準拠を追加していた場合は削除してください。 重複適合は警告になり、 warnings-as-errors を有効にした build ではエラーになります。

Configuration / MediaChannel / MediaStream / MediaChannelHandlers / SoraHandlers / Statistics / VideoView などは Sendable ではありません。 これらの値を actor 境界や Task の @Sendable クロージャへそのまま渡すことはできません。詳細は nonisolated(unsafe) が必要なケース をご確認ください。

@MainActor のクラス ( UIViewController など) の中でコールバッククロージャを書くと、クロージャが MainActor 隔離を継承します。 SDK はシグナリングスレッドなどからコールバックを呼ぶため、そのままでは Swift 6 言語モードの実行時隔離チェックでクラッシュします。 クロージャに @Sendable を付けるか、 nonisolated な関数へ処理を分離して隔離を外してください。

config.mediaChannelHandlers.onAddStream = { @Sendable [weak self] stream in
  // MediaStream は非 Sendable のため nonisolated(unsafe) で Task へ渡す
  nonisolated(unsafe) let stream = stream
  Task { @MainActor in
    guard let self else { return }
    self.attach(stream: stream)
  }
}

コールバックの呼び出しスレッドは保証されないため、 UI の更新は main actor / main queue へ束ねてください。

MediaChannel.setVideoHardMute など一部の API は async / await に対応しています。 これらは MediaChannel を保持している側のコンテキストから Task で局所的に呼び出す想定です。

nonisolated(unsafe) が必要なケース

2026.4.0 の時点では、次の操作を行う場合にアプリ側で nonisolated(unsafe) が必要です。

  • SDK のコールバックで受け取った MediaChannel / MediaStream を Task や @Sendable クロージャへ渡す
    • 例: Sora.connect の handler で受け取った MediaChannel を Task { @MainActor in ... } へ渡す
  • @MainActor の文脈から MediaChannel の async メソッドを呼び出す
    • rpc
    • sendableRPC
    • getStatsSnapshot()
    • setVideoHardMute(_:)
    • startScreenCapture(settings:)
    • stopScreenCapture()
  • @MainActor の文脈から ScreenCaptureSettings を startScreenCapture(settings:) へ渡す

MediaChannel / MediaStream / ScreenCaptureSettings は Sendable ではないためです。 また MediaChannel の async メソッドは nonisolated な非同期メソッドで、呼び出し元の executor では実行されません (コンパイラの診断では @concurrent と表示されます) 。 そのため @MainActor の文脈から呼び出すと、 MediaChannel の参照と引数が actor 境界を越えます。

nonisolated(unsafe) を付けた let で受けると、この検査を外せます。

@MainActor
final class RoomViewController: UIViewController {
  private var mediaChannel: MediaChannel?

  func setHardMute(_ mute: Bool) {
    guard let mediaChannel else { return }
    // MediaChannel は非 Sendable で、 setVideoHardMute は呼び出し元の executor では実行されないため
    nonisolated(unsafe) let channel = mediaChannel
    Task {
      do {
        try await channel.setVideoHardMute(mute)
      } catch {
        print(error)
      }
    }
  }
}

MediaChannel / MediaStream の参照を actor 境界へ渡す必要がある箇所は、 2026.4.0 で追加した Sendable な API へ置き換えることで減らせます。 Sendable な API への移行 をご確認ください。

Sendable な API への移行

actor 境界や @Sendable クロージャへ値を渡す場合は、 2026.4.0 で追加した次の API を利用してください。

MediaChannel.rpc / MediaChannel.getStats(handler:) とコールバック API は引き続き利用できます。 コールバックの型は変更していませんが、一部のコールバックは配送 executor が変わっています。詳細は リリースノート をご確認ください。

MediaChannel.rpc は互換 API として残していますが、将来のバージョンで削除される予定です。 RPC を actor 境界や @Sendable クロージャへ渡す場合は MediaChannel.sendableRPC へ移行してください。

RPCErrorDetail.data の型変更

概要

RPCErrorDetail.data の型を Any? から JSONValue? に変更しました。 RPCErrorDetail を Sendable な型にするためです。

data を as? [String: Any] のようにキャストしていたコードでは always fails の警告が出て常に nil になるため、 JSONValue の case 分岐へ書き換える必要があります。

移行方法

// 移行前
if let errorData = detail.data as? [String: Any] {
  _ = errorData
}

// 移行後
if case .some(.object(let errorData)) = detail.data {
  _ = errorData
}

JSON-RPC 2.0 の error.data が省略された場合は nil 、 null の場合は .null になります。 数値は JSONSerialization を経由して decimal / double の case で復元されるため、小数の表記が変わることがあります (例: 0.1 は .decimal(0.10000000000000001) になります) 。

詳細は エラーを扱う をご確認ください。

WebRTC の enum 型への CustomStringConvertible 準拠の削除

概要

RTCSignalingState / RTCIceConnectionState / RTCIceGatheringState / RTCDataChannelState / RTCDegradationPreference / RTCPriority への CustomStringConvertible 準拠を削除しました。 別モジュールの型へプロトコル準拠を追加していた retroactive conformance の警告 (SE-0364) を解消するためです。

影響を受けるケース

description を呼び出していたコードはコンパイルエラーになります。 文字列補間と String(describing:) は RTCSignalingState(rawValue: 0) のような raw 表現に変わります。

RTCRtpParameters.description からは Optional(...) が消え、未知の値は "unknown(<rawValue>)" になります ( messagingError の reason と SDK のログにも現れます) 。

移行方法

enum の値を文字列化していた場合は rawValue を利用するか、利用側で文字列化する処理を用意してください。

// 移行前
print(state.description)

// 移行後 (raw value を利用する)
print(state.rawValue)

Utilities.Stopwatch の非推奨

概要

Utilities.Stopwatch を非推奨にしました。 1 秒ごとに経過時間を "時:分:秒" の文字列で handler へ通知するカウンタで、 Sora iOS SDK 固有の機能ではなく SDK 内でも利用していないため、 2027 年中に廃止予定です。

移行方法

1 秒ごとの定期実行や表示の更新には、 Timer を MainActor 上のタイマーとして管理する方法か、 ContinuousClock と Task.sleep(for:) を組み合わせる方法へ移行してください。

経過時間の計測だけが目的の場合は、 ContinuousClock / SuspendingClock の now の差分 ( Duration ) へ移行してください。

用途によって移行先が異なるため、 SDK 固有の代替タイマーは提供しません。

Utilities.randomString の非推奨

概要

Utilities.randomString を非推奨にしました。 紛らわしい文字 ( l / I / O) を除く 59 文字の英数字から length の長さの文字列を返す汎用ユーティリティで、 Sora iOS SDK 固有の機能ではなく SDK 内でも利用していないため、 2027 年中に廃止予定です。 シグネチャと挙動は変わりません。

移行方法

ランダムな文字列が必要な場合は、 UUID や標準の乱数 API ( randomElement() / UInt32.random(in:) など) へ移行してください。 Utilities.randomString とは出力の長さ指定と文字集合が異なるため、同じ出力が必要な場合は文字集合を自前で定義してください。

用途によって移行先が異なるため、 SDK 固有の代替ユーティリティは提供しません。

その他の変更

移行時に確認が必要な 2026.4.0 の変更です。

  • CameraVideoCapturer.stream は capturer が MediaStream を強参照しなくなり、利用者が capturer 以外に MediaStream の強参照を保たない場合は nil になります
  • MediaStream.send(videoFrame:) は、映像フレームの加工と配送を非同期で行うようになりました (以前は呼び出し元の executor で同期的に実行していました) 。 send を呼び出した後にフレームとそれが保持する画素データを参照・変更していないか確認してください
  • VideoFilter の filter(videoFrame:) はストリームごとの直列 executor で実行されるようになりました (以前は呼び出し元の executor で実行されていました) 。呼び出し元のスレッドで実行されることを前提にしていないか確認してください
  • MediaStream.terminate() は冪等になり、以降に到着したフレームと renderer のコールバックを配送しなくなりました (以前は終了後も配送される場合がありました)
  • VideoRenderer のコールバックは main queue で配送されるようになりました (以前はコールバックによって呼ばれるスレッドが異なる場合がありました) 。ストリームをまたぐコールバックの順序は保証しません
  • MediaChannel.setVideoHardMute(true) の経路では onSwitchVideo が VideoHardMuteActor の executor で発火するようになりました (以前と異なるスレッドから呼ばれる場合があります)
  • Sora から "type": "redirect" を受信すると、 SDK は接続を一度切断して指定された location に再接続します。このとき旧接続の DataChannel が無効化され、無効化が完了した後に開始した MediaChannel.sendMessage は SoraError.messagingError を返すようになりました (以前は旧 DataChannel へ送信されることがありました)
  • Configuration の metadata と dataChannels の encode に失敗した場合は、接続開始前に SoraError.configurationError を返すようになりました (以前は接続がタイムアウトするか、接続時にプロセスが異常終了していました)
  • connect message に載る数値の表記が変わることがあります ( Float / Double の指数表記の展開、 -0.0 の符号など) 。 dataChannels を設定している場合は 17 桁表記が解消され JSONEncoder の表記に揃います
  • JSON オブジェクトのキー順は不定になります ( JSON として等価です)

変更の全体は リリースノート をご確認ください。