Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
英会話サービスのために開発したビデオチャットアプリの技術
Search
taminif
September 16, 2017
Programming
1
1.1k
英会話サービスのために開発したビデオチャットアプリの技術
iOSDC 2017 TrackC 13:30〜のトークです
taminif
September 16, 2017
Tweet
Share
More Decks by taminif
See All by taminif
PuppeteerとPlaywrightの15日間の演劇 / relation of Puppeteer and Playwright
taminif
3
2.1k
Redashの開発はじめました / How to get started Redash development
taminif
0
720
私の生活を変えたHeadless Chrome / Headless Chrome who changed my life
taminif
3
440
WebSocketをiOSに持ち込んで辛い思いをした経験がありますか!? / have you painful experience in web socket?
taminif
3
5.4k
LINEで馬券を購入する / Purchase a betting ticket at LINE
taminif
1
1.5k
SkyWayで一年間運用してきたけどWebRTCってつらいんじゃないの
taminif
2
960
オンライン英会話とSkyWay
taminif
0
470
オンライン英会話アプリとSkyWay
taminif
0
420
Mac1台でアプリを作る時代再び
taminif
0
410
Other Decks in Programming
See All in Programming
ISUCON14感想戦で85万点まで頑張ってみた
ponyo877
1
590
[JAWS-UG横浜 #80] うわっ…今年のServerless アップデート、少なすぎ…?
maroon1st
0
100
歴史と現在から考えるスケーラブルなソフトウェア開発のプラクティス
i10416
0
300
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
1.9k
QA環境で誰でも自由自在に現在時刻を操って検証できるようにした話
kalibora
1
140
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
240
週次リリースを実現するための グローバルアプリ開発
tera_ny
1
1.2k
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
6
1.4k
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
770
為你自己學 Python
eddie
0
520
非ブラウザランタイムとWeb標準 / Non-Browser Runtimes and Web Standards
petamoriken
0
430
Асинхронность неизбежна: как мы проектировали сервис уведомлений
lamodatech
0
1.3k
Featured
See All Featured
Designing for Performance
lara
604
68k
Building Your Own Lightsaber
phodgson
104
6.2k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
For a Future-Friendly Web
brad_frost
176
9.5k
A designer walks into a library…
pauljervisheath
205
24k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
3
180
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Into the Great Unknown - MozCon
thekraken
34
1.6k
Git: the NoSQL Database
bkeepers
PRO
427
64k
The Pragmatic Product Professional
lauravandoore
32
6.4k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.2k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
Transcript
ӳձαʔϏεͷͨΊʹ ࡞ͨ͠ϏσΦνϟοτΞϓϦ ͷٕज़ iOSDC JAPAN 2017 day 1 2017/09/16 େౡ
ޫو@sbntaminif
ຊͷλʔήοτ • SkyWay, Firebaseʹ͍ͭͯΓ͍ͨํ • ্هͷӡ༻ͷݟʹ͍ͭͯڵຯͷ͋Δํ • ӳձαʔϏεʹڵຯͷ͋Δํ • ७ਮʹڵຯͷ͋Δํ
ࣗݾհ • ΣϒϦΦגࣜձࣾWEBΤϯδχΞ + ϓϩμΫτ Ϛωʔδϟʔ • ΞϓϦΤϯδχΞ ʢࣗশʣ •
ීஈژͰಇ͍͍ͯ·͢
http://ejje.weblio.jp/content/ios
Weblio ΦϯϥΠϯࣙॻΛఏڙ͢Δ WebαʔϏεΛ ӡӦ͓ͯ͠Γ·͢
࣮ࣙॻҎ֎ʹ ͜ΜͳWebαʔϏεΛͬ ͍ͯ·͢
None
WebRTCͱʢςϯϓϨʣ • W3C͕ఏএ͢ΔP2PϦΞϧλΠϜίϛϡχέʔ γϣϯΛ࣮ݱ͢Δٕज़ • ϓϥάΠϯͳ͠ͰϒϥβؒͷΓͱΓ͕Մೳ • ຊΈΛ؆୯ʹ͚ͩઆ໌͠·͢ɻ
؆୯ʹΈ͚ͩ ᶅ௨৴ʂ 456/563/ ʢதܧʣαʔό γάφϦϯά αʔό ᶃ ᶄ ᶄ ᶃ
WebRTCͱʢςϯϓϨʣ • W3C͕ఏএ͢ΔP2PϦΞϧλΠϜίϛϡχέʔ γϣϯΛ࣮ݱ͢Δٕज़ • ϓϥάΠϯͳ͠ͰϒϥβؒͷΓͱΓ͕Մೳ • ຊΈΛ؆୯ʹ͚ͩઆ໌͠·͢ɻ
ΞϓϦͷ ͡Όͳ͍ͷʁ ϒϥβͷʁ
ΞϓϦΛ࡞ΔܦҢ
iOSͷSafari WebRTCʹରԠ͍ͯ͠·ͤΜ ʢۙରԠ༧ఆʂʣ
iPhoneiPadͰ Weblioӳձ͕͑ͳ͍
มΘͬͯɺ Weblioӳձֶߍ اۀʹఏڙ͍ͯ͠·͢
·ͨɺֶߍͷதʹ iPadΛतۀʹ༻͢Δॴ ૿͖͑ͯ·ͨ͠
ʮWeblioӳձΛiPadͰ ༻Ͱ͖ͳ͍ʁʯ
None
iOS SafariͰແཧ͚ͩͲ ΞϓϦͰ࣮͢ΕͰ͖Δ
ͦ͏ɺΞϓϦΛ࡞Δඞཁ͕ ͋ͬͨͷͰ͢
https://itunes.apple.com/jp/app/weblio๏ਓӳձ/id1215209006?mt=8
ΞϓϦͷհΛ͠·͢ʂ
ͱͯγϯϓϧͳΞϓϦ ᶃϩάΠϯ
ͱͯγϯϓϧͳΞϓϦ ᶄ࣍ճͷϏσΦϨοεϯ࣌֬ೝ
ͱͯγϯϓϧͳΞϓϦ ᶅϨοεϯ
͜ΜͳΞϓϦͰ͢ʂ • ߹ܭSwiftϑΝΠϧ16ϑΝΠϧʂ Controller4ͭʂ • Storyboard1ϑΝΠϧʹऩ·Δ • ͓ͦΒ͘iOSDCͷதͰͬͱখ͍͞Ξ ϓϦͩͱࢥ͍·͢ʂ
ຊ͜ͷΞϓϦΛ ֤ίϯϙʔωϯτʹ͚ͯ հ͢Δ͜ͱͰ
ͦΕͧΕͷ෦ʹ༻͞Εͯ ͍Δٕज़ӡ༻ʹ͍ͭͯͷ ݟΛڞ༗͠·͢
͜ͷࡾͭ ϏσΦ෦ ڭࡐ෦ νϟοτ෦
1. ϏσΦ෦
ઌ΄Ͳհͨ͠௨Γɺ WeblioӳձWebRTCΛ ༻͍ͯ͠·͢
ͪΖΜɺΞϓϦʹ WebRTCͰ࣮͢Δඞཁ͕ ͋Γ·͢
SkyWay: WebRTCΛ؆୯ʹ ࣮ݱ͢ΔαʔϏε https://webrtc.ecl.ntt.com
let options:SKWPeerOption = SKWPeerOption.init() options.key = `APIΩʔ` options.domain = `υϝΠϯ`
peer = SKWPeer.init(options: options) peer?.on(SKWPeerEventEnum.PEER_EVENT_OPEN, callback: {(obj) -> Void in // my peer ID if let ownId = obj as? String { self.videoLessonRtdb.writeSkyWayId(id: ownId) } }) peer?.on(SKWPeerEventEnum.PEER_EVENT_CALL, callback: {(obj) -> Void in let mediaConnection:SKWMediaConnection = obj as! SKWMediaConnection self.videoConnection = mediaConnection mediaConnection.answer(self.localMediaStream) }) ਃ͠༁ఔͷαϯϓϧίʔυ #import <SkyWay/SKWPeer.h> $PDPB1PETͰΠϯετʔϧ ͨ͠ϥΠϒϥϦΛΠϯϙʔτ 1FFSΦϒδΣΫτΛੜ ʢγάφϦϯάαʔόʔʹ ใॻ͖ࠐΈʣ ௨৴։࢝ ͜͜Ͱө૾ͱԻΛૹ৴ ใΛॻ͖ࠐΜͩΒɺ 1FFS*%͕ൃߦ͞Ε·͢
2. νϟοτ෦
Firebase
Firebase • FirebaseGoogle͕ఏڙ͢ΔαʔϏε (Baas?) • iOS, Android, ΣϒͰ༻Մೳ • ։ൃΛॿ͚Δଟ͘ͷػೳ͕͋Γ·͢ɻ
༻͍ͯ͠Δػೳ • AuthͱRealtime Database • AuthೝূػೳΛఏڙͯ͘͠ΕΔαʔϏε • Realtime DatabaseαʔόʔͱΫϥΠΞ ϯτؒͰσʔλΛಉظͯ͠อଘͯ͘͠ΕΔ
αʔϏε
νϟοτͷ࣮ݱ ,FZ7BMVFͰΛอଘ औಘ͢Δࡍ+40/ܗ ࣜͰऔಘͰ͖Δ ҰͭͷϊʔυͰҰͭͷνϟοτΛ ࣮ݱ͍ͯ͠Δ ࣌ܥྻॱʹฒΔ͜ͱͰνϟοτͬΆ͘ දࣔ
Auth let rtdbLoginCompletionHandler: FIRAuthResultCallback = {_,_ in self.setChatObserve() self.setTmObserve() }
let rtdbLoginErrorHandler = { print(‘error’) } FIRAuth.auth()?.signIn(withEmail: `ID`, password: `ύεϫʔυ`, completion: { (user, error) in guard error == nil else { rtdbLoginCompletionHandler() return } rtdbLoginCompletionHandler(user, error) }) ೝূޙͷॲཧΛఆٛ ೝূΤϥʔ࣌ͷॲཧΛఆٛ ೝূॲཧ ͜͜ͰύεϫʔυํࣜͰ ϩάΠϯ
Realtime Database let withBlock = { (snapshot: FIRDataSnapshot) in //
received chat data if let dictionary = snapshot.value as? [String : AnyObject] { guard let isRoleProf = dictionary["is_role_prof"] as? Bool, let timeMsec = dictionary["time_msec"] as? UInt64, let senderIdString = dictionary["sender_id"] as? String, let senderId = Int(senderIdString), let text = dictionary["text"] as? String else { return } let time:Double = Double(timeMsec) / 1000 } var data:ChatDataStruct if isRoleProf { // prof data = ChatDataStruct(messageSender: .YOU, message: text, displayTime: self.displayTimeFormatter.string(from: Date(timeIntervalSince1970: time))) } else { // member data = ChatDataStruct(messageSender: .ME, message: text, displayTime: self.displayTimeFormatter.string(from: Date(timeIntervalSince1970: time))) } self.chatTableReload(data: data) } firebaseChatObserveHandle = firebaseUserReference.child(`Firebaseͷύε `).observe(.childAdded, with: withBlock) 'JSFCBTF͔Βϊʔ υΛड͚औͬͨ࣌ ͷॲཧΛఆٛ ՃࣜͰ0CTFSWFS ηοτ
3. ڭࡐ෦
ڭࡐ෦ • ڭࡐʹը૾Λ༻ʢWebͷ༷ʣ • αʔόʔʹஔ͍ͯ͋ΔڭࡐΛɺ WKWebViewΛ༻ͯ͠ಡΈࠐΈ • ڭࡐͷURLͷΓͱΓʹRealtime DatabaseΛ༻
࣮͜Μͳͱ͜ʹ ͍ͬͯΔFirebase • ڭࡐURLͷૹ৴ • PeerIDͷަ • ϨοεϯதͷϏσΦঢ়گͷࢹ • ڭࡐ্ʹදࣔ͢ΔϚεಉظ
ӡ༻͖ͯͨ͠ݟ
1. SkyWay
ແྉͰ αʔϏεӡ༻Ͱ͖ͦ͏ʁ
͋Γ·ͤΜ • ֶߍͷतۀͰ༻͢ΔͷͰɺ20ਓʙ40ਓ ͘Β͍ͷੜె͕ಉ࣌ʹडߨ • ௨৴ཱ͕֬͢Εϥά1ඵ͔͔Γ·ͤ Μ • ͨͩ͠ωοτϫʔΫ͕උ͞Ε͍ͯΔલఏ
ωοτϫʔΫͲΕ͚ͩ ඞཁͳͷʁ
ඞཁͳଳҬ • 1ΫϥΠΞϯτ͋ͨΓ͜Ε͘Β͍ඞཁ Իɿ500Kbps ө૾ɿ2Mbps • ֶߍͩͱશһ͕ಉ࣌ʹतۀΛ͢ΔͨΊɺ 1ΫϥεͰडߨ͢Δͱଓෆྑ͕ଟ͘ൃੜͨ͠
༻ଳҬΛݮΒͤͳ͍͔ʁ
ϦϦʔε࣌Ͱ͖ͳ͔ͬ ͨͷͰ͕͢ɺਖ਼ࣜ൛ͰͰ ͖ΔΑ͏ʹͳ͍ͬͯ·͢
2. Firebase
ຖ݄ͷྉۚͲ͏ͳͷʁ
ྉۚϓϥϯࡾछྨ͋Γ·͢
4QBSLϓϥϯ ʢແྉʣ 'MBNFϓϥϯ ʢఆֹ՝ۚʣ #MB[Fϓϥϯ ʢैྔ՝ۚʣ ಉ࣌ଓ ্ݶ͋Γ ্ݶͳ͠ ্ݶͳ͠
μϯϩʔυ (#·Ͱ (#·Ͱ (# ετϨʔδ ݄(#·Ͱ ݄(#·Ͱ (# ࣗಈόοΫΞοϓ ͳ͠ ͳ͠ ͋Γ ※2017/09/11ݱࡏ https://firebase.google.com/pricing/
ྫɿ8݄ͷ༻ྔ • ࠷େಉ࣌ଓ250 • μϯϩʔυྔ1.4GB • ετϨʔδ༻ྔ16GBʢαʔϏε։࢝࣌ ͔Βͷ߹ܭʣ ͯ͞ɺ͜ΕͰ͍͘Βʁ
Realtime Databaseͷ ϊʔυཧ
ཧը໘ͰΒ͔͢ தུ
ϊʔυ͕1000Λ͑Δͱ ཧը໘ػೳ͠ͳ͘ͳΔ
͋Δఔੵ͞ΕΔલʹ ׂ͢ΔΑ͏ͳઃܭʹ͠·͠ΐ͏ ʢྫɿʁʣ
Firebaseͷোใ
ظ͚ؒͩͲ ͪΐ͍ͪΐ͍ଓෆྑʹͳΓ·͢
ேํ͕ଟ͍ͷͰ ʹͳΓʹ͍͘Ͱ͕͢ ͜Ε͔Β҆ఆ͢Δ͜ͱΛ ظ͓ͯ͠Γ·͢
·ͱΊ
·ͱΊ • SkyWay, FirebaseڞʹɺॳಈແྉͰ༻Մೳ • ؆୯ͳͷΛ࡞Γ͍ͨͱ͖ɺؾܰʹͬͯΈΔ ͷҰͭ • ಛʹFirebaseΞϓϦ։ൃΛ͢Δ্Ͱඇৗʹศར •
μϯϩʔυεΫϦʔϯϏϡʔͷղੳͰ ͖ΔͷͰɺͱΓ͋͑ͣೖΕΔͱ͍͏ͷҰߟͷ ༨͋Γ
͋Γ͕ͱ͏͍͟͝·ͨ͠