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
740
私の生活を変えたHeadless Chrome / Headless Chrome who changed my life
taminif
3
460
WebSocketをiOSに持ち込んで辛い思いをした経験がありますか!? / have you painful experience in web socket?
taminif
3
5.6k
LINEで馬券を購入する / Purchase a betting ticket at LINE
taminif
1
1.5k
SkyWayで一年間運用してきたけどWebRTCってつらいんじゃないの
taminif
2
980
オンライン英会話とSkyWay
taminif
0
490
オンライン英会話アプリとSkyWay
taminif
0
430
Mac1台でアプリを作る時代再び
taminif
0
410
Other Decks in Programming
See All in Programming
複数ドメインに散らばってしまった画像…! 運用中のPHPアプリに後からCDNを導入する…!
suguruooki
0
470
Preact、HooksとSignalsの両立 / Preact: Harmonizing Hooks and Signals
ssssota
1
1.3k
Ruby's Line Breaks
yui_knk
2
470
PHPのガベージコレクションを深掘りしよう
rinchoku
0
260
5年間継続して開発した自作OSSの記録
bebeji_nappa
0
170
ミリしらMCP勉強会
watany
4
740
DomainException と Result 型で作る型安全なエラーハンドリング
karszawa
0
890
マルチアカウント環境での、そこまでがんばらない RI/SP 運用設計
wa6sn
0
710
Being an ethical software engineer
xgouchet
PRO
0
200
自分のために作ったアプリが、グローバルに使われるまで / Indie App Development Lunch LT
pixyzehn
1
150
Agentic Applications with Symfony
el_stoffel
2
270
サービスレベルを管理してアジャイルを加速しよう!! / slm-accelerate-agility
tomoyakitaura
1
160
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
23
1.5k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
640
GitHub's CSS Performance
jonrohan
1030
460k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
KATA
mclloyd
29
14k
Product Roadmaps are Hard
iamctodd
PRO
52
11k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Navigating Team Friction
lara
184
15k
Testing 201, or: Great Expectations
jmmastey
42
7.4k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.2k
Statistics for Hackers
jakevdp
798
220k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
13
1.4k
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ΞϓϦ։ൃΛ͢Δ্Ͱඇৗʹศར •
μϯϩʔυεΫϦʔϯϏϡʔͷղੳͰ ͖ΔͷͰɺͱΓ͋͑ͣೖΕΔͱ͍͏ͷҰߟͷ ༨͋Γ
͋Γ͕ͱ͏͍͟͝·ͨ͠