ハイライト
iOS 17 で追加された
GroupSessionJournalAPI により、SharePlay App は最大 100MB の添付ファイル(画像、PDF、音声など)を転送できます。Apple のクラウド基盤を使ってエンドツーエンド暗号化された高速転送を実現し、遅れて参加した人の状態同期も自動処理します。
主要内容
GroupSessionMessenger の限界
SharePlay App はこれまで GroupSessionMessenger で状態を同期していましたが、これは小さなメッセージデータの転送に向いています。共同描画 App を想像してください。筆跡は Messenger で送れますが、ユーザーがキャンバスに写真をドラッグした場合、この経路では対応できません。
(00:58)GroupSessionJournal はこの空白を埋めます。FaceTime と同じ Apple のクラウド基盤を使い、複数の技術を組み合わせて転送データ量と待ち時間を減らし、全工程でエンドツーエンド暗号化されます。
Journal の仕組み
(02:14)GroupSessionJournal は 1 つの GroupSession に紐づき、すべての参加者が同じ Journal インスタンスを共有します。誰かがローカルで add を呼ぶと、全員の attachments AsyncSequence が新しい添付ファイルイベントを受け取り、remove を呼ぶと全員の環境で同期して削除されます。
添付ファイルの型は Transferable プロトコルに準拠するだけでよく、残りの転送ロジックはシステムが処理します。
2 つの重要な設計制約
(03:37)添付ファイルのサイズ上限は 100MB です。これにより、開発者はコンテンツタイプを切り分ける必要があります。ユーザーが生成した写真、PDF、ボイスメモは Journal に適していますが、映画のような大きなファイルは App 独自のサーバーを使うべきです。
(04:18)ライフサイクルは GroupSession に紐づきます。誰かがオンラインでいる限り添付ファイルは保持され、全員が離れると自動的に削除されます。つまり重要なデータは Session 終了前にローカルへ永続化する必要があります。
遅れて参加した人の問題を自動解決
(04:47)以前は新しく参加した人のために、他の参加者が状態データを再送信する必要がありました。状態に大きな添付ファイルが含まれている場合、全員がもう一度アップロードする必要がありました。Journal は既存の添付ファイルを新しい参加者へ自動同期するため、他の人が再アップロードする必要はありません。
詳細
DrawTogether に Journal を統合する
Session では DrawTogether App を例に、4 ステップの統合を示しました。
ステップ 1: データモデルを定義する
Journal 内の画像を追跡する CanvasImage 構造体を作成します。
struct CanvasImage: Identifiable {
let id: UUID
let image: UIImage
var position: CGPoint
}
ステップ 2: Canvas モデル内で Journal を作成する
class Canvas: ObservableObject {
@Published var images: [CanvasImage] = []
@Published var selectedImageData: Data?
private var journal: GroupSessionJournal?
func configureGroupSession(_ session: GroupSession<DrawTogether>) {
// Journal を作成
journal = GroupSessionJournal(session: session)
// 添付ファイルの変更を監視
Task {
for await attachment in journal!.attachments {
await handleAttachment(attachment)
}
}
}
func addImageToJournal(_ imageData: Data) {
guard let journal = journal else { return }
// Transferable 添付ファイルを作成してアップロード
let attachment = TransferableAttachment(data: imageData, type: .image)
journal.add(attachment)
}
}
キーポイント:
GroupSessionJournal(session:)は GroupSession で初期化するattachmentsは AsyncSequence で、for awaitを使って新しい添付ファイルを監視するadd()で添付ファイルをアップロードすると、すべての参加者が受信する
ステップ 3: 画像選択ボタンを追加する
import PhotosUI
struct ControlBar: View {
@ObservedObject var canvas: Canvas
var body: some View {
HStack {
// その他のボタン...
PhotosPicker(selection: $canvas.selectedImageData,
matching: .images) {
Image(systemName: "photo")
}
}
}
}
ステップ 4: キャンバスに画像を表示する
struct CanvasView: View {
@ObservedObject var canvas: Canvas
var body: some View {
ZStack {
// ストロークを描画...
// すべての画像を表示
ForEach(canvas.images) { canvasImage in
Image(uiImage: canvasImage.image)
.position(canvasImage.position)
.gesture(
DragGesture()
.onChanged { value in
canvasImage.position = value.location
}
)
}
}
}
}
キーポイント:
PhotosPickerは SwiftUI の組み込みコンポーネントで、iOS 16 以降で利用できる- 画像位置のドラッグは
DragGestureで実装する - すべての画像状態は Journal を通じて全参加者へ同期される
添付ファイル処理フロー
func handleAttachment(_ attachment: GroupSessionJournal.Attachment) async {
do {
let data = try await attachment.load(Data.self)
if let image = UIImage(data: data) {
let canvasImage = CanvasImage(
id: attachment.id,
image: image,
position: .center
)
await MainActor.run {
images.append(canvasImage)
}
}
} catch {
print("Failed to load attachment: \(error)")
}
}
キーポイント:
attachment.load(Data.self)は添付ファイルデータを非同期で読み込む- 読み込み完了後、メインスレッドに戻って UI を更新する
- 添付ファイル ID は後続の削除操作に利用できる
重要ポイント
-
画像付き共同作業ホワイトボード App
- 何を作るか: 複数人が同じキャンバスに画像を貼り、注釈を付け、議論できる
- なぜ価値があるか: Journal が画像転送と同期を自動処理するため、開発者はキャンバスのインタラクションロジックに集中できる
- 始め方:
GroupSessionJournalで画像添付ファイルを転送し、GroupSessionMessengerで筆跡を同期する
-
共有アルバム付きイベント App
- 何を作るか: イベントや旅行中にグループで写真をリアルタイム共有し、全員が互いの撮ったばかりの写真を見られる
- なぜ価値があるか: Journal のエンドツーエンド暗号化と自動同期により、写真共有を安全かつ即時にできる
- 始め方: 写真選択後に
journal.add()でアップロードし、attachmentsシーケンスを監視して他の人の写真を受け取る
-
共同注釈付きドキュメントレビュー ツール
- 何を作るか: チームメンバーが PDF ドキュメントを一緒にレビューし、それぞれ注釈やハイライトを追加する
- なぜ価値があるか: PDF ファイルは通常 100MB 未満で Journal に適しており、注釈データは Messenger で送ることで完全な体験を実現できる
- 始め方: PDF ファイルを Journal 添付ファイルとして転送し、注釈の座標とテキストを Messenger でリアルタイム同期する
-
共有プレイリスト付き音楽 App
- 何を作るか: グループで 1 つのプレイリストを共同編集し、誰でも曲を追加できる
- なぜ価値があるか: 音声ファイル本体は Journal に載せないが、アルバムアートやユーザーメモなどのメタデータは Journal で高速同期できる
- 始め方: Journal でカバー画像とプレイリスト変更を同期し、Messenger で再生状態を同期する
関連セッション
- Add SharePlay to your app — SharePlay の入門と GroupActivities フレームワークの基礎
- Build custom experiences with GroupActivities — GroupSessionMessenger を使ってカスタム共有体験を構築する方法
- Make a great SharePlay experience — SharePlay 体験設計のベストプラクティス
コメント
GitHub Issues · utterances