Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
サーバーと同期してリアルタイムに更新する画面を実装する
Search
izumi
September 12, 2022
Programming
4.8k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
サーバーと同期してリアルタイムに更新する画面を実装する
izumi
September 12, 2022
More Decks by izumi
See All by izumi
新規機能開発からモジュール分割を始めてみる
rizumi
7
6.3k
5分でわかるMint
rizumi
1
900
Introducing SourceKit-LSP
rizumi
2
2.4k
レイアウト実装方法の比較ポイント
rizumi
0
2.4k
アプリ内の絵文字をカスタム絵文字化した話
rizumi
1
320
Other Decks in Programming
See All in Programming
setup-vp GitLab対応の裏側
naokihaba
0
110
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
220
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
130
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
210
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
160
Building an Out-of-Order CPU
latte72
1
790
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
120
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
330
FreeBSDでZabbixを動かす
kenkino
0
310
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
310
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
2.1k
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
150
Featured
See All Featured
The browser strikes back
jonoalderson
0
1.7k
The Cult of Friendly URLs
andyhume
79
7k
Being A Developer After 40
akosma
91
590k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
[SF Ruby Conf 2025] Rails X
palkan
3
1.4k
First, design no harm
axbom
PRO
2
1.3k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
240
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Building Adaptive Systems
keathley
44
3.2k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
440
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Transcript
サーバーと同期してリアルタイム に更新する画面を実装する iOSDC2022 @rizumi
Cluster, Inc. All Rights Reserved. 2 自己紹介 Ryo Izumi @rizumi_jp
クラスター株式会社 Software Engineer
Cluster, Inc. All Rights Reserved. 3 clusterの紹介
Cluster, Inc. All Rights Reserved. 4 outroom inroom
5 アプリの画面更新
Cluster, Inc. All Rights Reserved. 6 アプリの画面更新 DB API Server
Client • Serverからデータを取得して表示する画面
Cluster, Inc. All Rights Reserved. 7 アプリの画面更新 DB API Server
Client • Serverからデータを取得して表示する画面 fetch
Cluster, Inc. All Rights Reserved. 8 アプリの画面更新 DB API Server
Client response • Serverからデータを取得して表示する画面 fetch
Cluster, Inc. All Rights Reserved. 9 アプリの画面更新 DB API Server
Client response Update • Serverからデータを取得して表示する画面 fetch
Cluster, Inc. All Rights Reserved. 10 アプリの画面更新 DB API Server
Client 反映したい response Update • Serverからデータを取得して表示する画面 fetch
Cluster, Inc. All Rights Reserved. 11 画面更新のパターン • ユーザーの明示的なアクション ◦
PullToRefreshや更新ボタン • 自動的な更新 ◦ serverの更新を検知してリアルタイムな更新処理
Cluster, Inc. All Rights Reserved. 12 画面更新のパターン • ユーザーの明示的なアクション ◦
PullToRefreshや更新ボタン • 自動的な更新 ◦ serverの更新を検知してリアルタイムな更新処理
Cluster, Inc. All Rights Reserved. 13 ※リアルタイムの定義 • 本セッションでの ”リアルタイム”は
基本的に soft real-timeの事を意味します ※ soft real-time: 時間内に処理できなくても品質は下がるが価値は0にならない
Cluster, Inc. All Rights Reserved. 14 リアルタイム更新が必要な場合 • ユーザーに情報の更新をいち早く伝えたい場合 ◦
ex. チャット, ユーザーのオンライン状態 • 逆にリアルタイム更新すべきでないケースもある ◦ ex. 商品詳細の説明文など
15 リアルタイム更新の実装例
Cluster, Inc. All Rights Reserved. 16 更新通知の受信方法 1. polling 2.
Push通知 3. Firebase Realtime Database / Cloud Firestore 4. WebSocket
Cluster, Inc. All Rights Reserved. 17 更新通知の受信方法 1. polling 2.
Push通知 3. Firebase Realtime Database / Cloud Firestore 4. WebSocket
Cluster, Inc. All Rights Reserved. 18 更新方法1. polling let timer
= Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in Task { // 差分があれば画面更新 let data = await self.apiClient.fetch() refreshIfNeeded(data) } }
Cluster, Inc. All Rights Reserved. 19 更新方法1. polling • メリット
◦ 実装がシンプルでAPIも使いまわせる • デメリット ◦ 無駄なAPI通信が発生するのでパフォーマンスが悪い
Cluster, Inc. All Rights Reserved. 20 更新通知の受信方法 1. polling 2.
Push通知 3. Firebase Realtime Database / Cloud Firestore 4. WebSocket
Cluster, Inc. All Rights Reserved. 21 更新方法2. サイレントPush通知 https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_serv er/pushing_background_updates_to_your_app
Cluster, Inc. All Rights Reserved. 22 更新方法2. サイレントPush通知 • Push通知のpayloadにcontent-available:
1を指定 { "aps": { "content-available": 1 }, "data": { "example":"sync-notify" } }
Cluster, Inc. All Rights Reserved. 23 更新方法2. サイレントPush通知 { "aps":
{ "content-available": 1 }, "data": { "example":"sync-notify" } } • Push通知のpayloadにcontent-available: 1を指定 任意の値を入れれる
Cluster, Inc. All Rights Reserved. 24 更新方法2. サイレントPush通知 func application(_
application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // サイレントpush受信 // ここで画面に受信通知をする (e.g. NotificationCenter) } • Appdelegateで受信時の処理をハンドリング
Cluster, Inc. All Rights Reserved. 25 更新方法2. サイレントPush通知 • メリット
◦ 既存のPushの仕組みを使いまわせる • デメリット ◦ 他Platformへの流用が難しい ◦ ユーザー設定でOFFにできてしまう ◦ Push通知を対応していない場合は対応が必要
Cluster, Inc. All Rights Reserved. 26 更新通知の受信方法 1. polling 2.
Push通知 3. Firebase Realtime Database / Cloud Firestore 4. WebSocket
Cluster, Inc. All Rights Reserved. 27 更新方法3. Firebase Realtime Database
/ Cloud Firestore
Cluster, Inc. All Rights Reserved. 28 import FirebaseDatabase ... //
Realtime Database let ref = Database.database().reference() ref.child(“users”).observe(.value, with: { snapshot in let value = snapshot.value // 画面更新 refresh(value) }) 更新方法3. Firebase Realtime Database / Cloud Firestore
Cluster, Inc. All Rights Reserved. 29 • メリット ◦ client実装がシンプル
◦ インフラのメンテナンスコスト低い ▪ スケールなどをFirebaseに頼れる • デメリット ◦ FirebaseにDBが依存 更新方法3. Firebase Realtime Database / Cloud Firestore
Cluster, Inc. All Rights Reserved. 30 更新通知の受信方法 1. polling 2.
Push通知 3. Firebase Realtime Database / Cloud Firestore 4. WebSocket
Cluster, Inc. All Rights Reserved. 31 更新方法4. WebSocket Client Server
Update通知 Connection Close
Cluster, Inc. All Rights Reserved. 32 更新方法4. WebSocket class WebSocketEngine:
NSObject, URLSessionWebSocketDelegate { private var task: URLSessionWebSocketTask? func connect() { let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil) task = session.webSocketTask(with: .init(string: "ws://example")!) doReceive() task?.resume() } func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) { // connected } }
Cluster, Inc. All Rights Reserved. 33 更新方法4. WebSocket private func
doReceive() { task?.receive { [weak self] (result) in switch result { case .success(let message): switch message { case .string(let string): // Receive string case .data(let data): // Receive data @unknown default: // error } self?.doReceive() case .failure(let error): // error } } }
Cluster, Inc. All Rights Reserved. 34 更新方法4. WebSocket func disconnect()
{ task?.cancel(with: .normalClosure, reason: nil) } func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) { // disconnected }
Cluster, Inc. All Rights Reserved. 35 更新方法4. WebSocket SwiftのWebSocket library
• Starscream ◦ https://github.com/daltoniam/Starscream • socket.io-client-swift ◦ https://github.com/socketio/socket.io-client-swift • SwiftWebSocket ◦ https://github.com/tidwall/SwiftWebSocket
Cluster, Inc. All Rights Reserved. 36 更新方法4. WebSocket • メリット
◦ 拡張性/自由度が高い ▪ 他Platformでも同様の仕組みが使いまわせる • デメリット ◦ client/server共に実装が大変になりがち
Cluster, Inc. All Rights Reserved. 37 各手法のpros / cons比較 メリット
デメリット polling シンプルな実装 パフォーマンスが良くない silent push Pushの実装を使いまわせる 拡張性が低い Firebase SDKを使った実装がシンプル mBaasの基盤で安定 Firebaseが使えない環境だと利用で きない WebSocket 自由度 / 拡張性が高い 実装やメンテナンスコストが高い • 要件 / 仕様と併せて最適なものを選ぶと良い
38 clusterでの実例
Cluster, Inc. All Rights Reserved. 39 clusterでの実例 • メッセージや フレンドリクエストに利用
Cluster, Inc. All Rights Reserved. 40 clusterでの実例 • メッセージや フレンドリクエストに利用
Cluster, Inc. All Rights Reserved. 41 更新通知はWebSocketを採用 • 多くのPlatformをカバーできる ◦
iOS / Android / Windows / Mac / Quest2 • inroom(Unity)内の通知にもWebSocketを利用 • FirebaseのDBを利用していない
Cluster, Inc. All Rights Reserved. 42 接続 / 切断の管理 RealtimeSync
Manager Auth API WebSocket token
Cluster, Inc. All Rights Reserved. 43 接続 / 切断の管理 RealtimeSync
Manager Auth API WebSocket token connect(token)
Cluster, Inc. All Rights Reserved. 44 接続 / 切断の管理 RealtimeSync
Manager Auth API WebSocket token connect(token) 以下の状態をRealtimeSyncManagerが管理 状態に変化がある度に接続(or 切断)処理を行う ・Login状態 ・inroom / outroom ・Foreground / Background ・エラーなどでの切断
Cluster, Inc. All Rights Reserved. 45 更新通知の受信 RealtimeSync Manager WebSocket
Protocol Buffers Revisions
Cluster, Inc. All Rights Reserved. 46 更新通知の受信 RealtimeSync Manager WebSocket
Protocol Buffers Revisions 初回接続時 or データ更 新時に送られてくる struct Revisions { var messageRevision: UInt64 var friendRevision: UInt64 var fooRevision: UInt64 var barRevision: UInt64 }
Cluster, Inc. All Rights Reserved. 47 更新通知の受信 RealtimeSync Manager WebSocket
Protocol Buffers Revisions final class RealtimeSyncManager { var revisions: Observable<Revisions> { revisionsRelay.asObservable() } private var revisionsRelay = PublishRelay<Revisions>() // WebSocketからデータ受信毎に呼ぶ private func doReceive(_ data: Data) { // protobufをdecode guard let revisions = try? Revisions(contiguousBytes: data) else { return } revisionsRelay.accept(revisions) } }
Cluster, Inc. All Rights Reserved. 48 更新通知の受信 RealtimeSync Manager WebSocket
FriendSync subscribe Protocol Buffers Revisions final class FriendSync { private var currentRevision: UInt64 private let bag = DisposeBag() init(realtimeSyncManager: RealtimeSyncManager, repository: FriendRepository) { realtimeSyncManager.revisions .subscribe(onNext: { [weak self] revisions in guard let self = self else { return } if self.currentRevision != revisions.friendRevision { self.currentRevision = revisions.friendRevision repository.fetchRequest() } }) .disposed(by: bag) } } Revisionの 更新チェック
Cluster, Inc. All Rights Reserved. 49 更新通知の受信 RealtimeSync Manager WebSocket
FriendSync subscribe Revisionの 更新チェック Protocol Buffers Revisions FriendAPI Friend Repository fetch Friend ViewModel FriendView subscribe data bind 更新をrequest
Cluster, Inc. All Rights Reserved. 50 更新通知の受信 RealtimeSync Manager WebSocket
FriendSync subscribe Revisionの 更新チェック Protocol Buffers Revisions FriendAPI Friend Repository fetch Friend ViewModel FriendView subscribe data bind 更新をrequest 各画面共通の設計
Cluster, Inc. All Rights Reserved. 51 更新通知の受信 RealtimeSync Manager WebSocket
Sync subscribe Revisionの 更新チェック Protocol Buffers Revisions API Repository fetch ViewModel View subscribe data bind 更新をrequest 各画面共通の設計 新規でリアルタイム更新を追 加する場合この部分を新設す るだけでOK
52 UI更新時に考慮するポイント
Cluster, Inc. All Rights Reserved. 53 UIをリアルタイム更新するときに大事な事 • ユーザーの邪魔しない ◦
ユーザーが何かを見ている途中でのインジケーター ◦ エラー表示 ◦ スクロールしていた画面が勝手に戻る
Cluster, Inc. All Rights Reserved. 54 差分更新を使う • DiffableDataSources var
snapshot = NSDiffableDataSourceSnapshot<Section, Item>() snapshot.appendSections([.section]) snapshot.appendItems(items) dataSource.apply(snapshot)
Cluster, Inc. All Rights Reserved. 55 差分更新を使う https://developer.apple.com/videos/play/wwdc2020/10045/
56 まとめ
Cluster, Inc. All Rights Reserved. 57 まとめ • 情報をいち早く伝える必要がある場合にリアルタイム更新処理は必要 ◦
ex. チャットなど • 更新通知の受信方法 ◦ polling, push通知, Firebase, WebSocket • 対応画面を柔軟に増やせる更新通知の設計 • UI更新時にはユーザーの操作を邪魔しない
58 最後に
Cluster, Inc. All Rights Reserved. 59 絶賛採用強化中! • iOS Engineerはじめ各職種採用強化中です!
https://recruit.cluster.mu/engineer/