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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
taminif
September 16, 2017
Programming
1.2k
1
Share
英会話サービスのために開発したビデオチャットアプリの技術
iOSDC 2017 TrackC 13:30〜のトークです
taminif
September 16, 2017
More Decks by taminif
See All by taminif
React Native New Architecture 移行実践報告
taminif
1
230
「とりあえずAI」が招く悲劇〜私がAIで生産性を下げるまでの話〜 / The tragedy caused by "AI for now" - The story of how I used AI to reduce my productivity
taminif
1
310
PuppeteerとPlaywrightの15日間の演劇 / relation of Puppeteer and Playwright
taminif
3
2.3k
Redashの開発はじめました / How to get started Redash development
taminif
0
810
私の生活を変えたHeadless Chrome / Headless Chrome who changed my life
taminif
3
540
WebSocketをiOSに持ち込んで辛い思いをした経験がありますか!? / have you painful experience in web socket?
taminif
3
6.2k
LINEで馬券を購入する / Purchase a betting ticket at LINE
taminif
1
1.7k
SkyWayで一年間運用してきたけどWebRTCってつらいんじゃないの
taminif
2
1k
オンライン英会話とSkyWay
taminif
0
550
Other Decks in Programming
See All in Programming
運用エージェントは "作る" から "育てる" へ - 記憶と自己進化の3層設計パターン / self-evolving-agents-three-layer-agent-design
gawa
12
3.3k
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
2.4k
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
110
LLM Plugin for Node-REDの利用方法と開発について
404background
0
150
net-httpのHTTP/2対応について
naruse
0
390
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
110
色即是空、空即是色、データサイエンス
kamoneggi
1
250
OCRを使ってゲームのアイテムをデータ化する
kishikawakatsumi
0
120
次世代リンターで探る、tsgo 時代における型認識カスタムルールの現実解
ytakahashii
3
1.3k
Inspired By RubyKaigi (EN)
atzzcokek
0
460
Lessons from Spec-Driven Development
simas
PRO
0
110
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
110
Featured
See All Featured
Measuring & Analyzing Core Web Vitals
bluesmoon
9
850
sira's awesome portfolio website redesign presentation
elsirapls
0
270
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
380
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
210
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
How to train your dragon (web standard)
notwaldorf
97
6.6k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
130
BBQ
matthewcrist
89
10k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.2k
KATA
mclloyd
PRO
35
15k
Why Our Code Smells
bkeepers
PRO
340
58k
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ΞϓϦ։ൃΛ͢Δ্Ͱඇৗʹศར •
μϯϩʔυεΫϦʔϯϏϡʔͷղੳͰ ͖ΔͷͰɺͱΓ͋͑ͣೖΕΔͱ͍͏ͷҰߟͷ ༨͋Γ
͋Γ͕ͱ͏͍͟͝·ͨ͠