Slide 1

Slide 1 text

8FCͰͰ͖ΔମݧΛߟ͑Δձ 折原 レオナルド賢

Slide 2

Slide 2 text

ڈ೥ͷ͍·͝Ζ

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

࿩͢͜ͱ ͍ΖΜͳ 8FC"1*Λ৮ͬͯΈΔ ࢖ͬͨ͜ͱͳ͍ਓͰ΋Θ͔Γ΍͘͢ Ͱ΋ʮߟ͑ΔձʯͳͷͰൃలܕ΋ఴ͑ͯ

Slide 7

Slide 7 text

࿩͢τϐοΫ  ໐Δ΋ͷɾಈ͘΋ͷͷ"1*  8FC"TTFNCMZͱ 8FC8PSLFS  1VTI"1*

Slide 8

Slide 8 text

8FC"VEJP"1*8FC(- 8FC#MVFUPPUI8FC.*%*"1*  ໐Δ΋ͷɾಈ͘΋ͷͷ"1*

Slide 9

Slide 9 text

໐Δ΋ͷ

Slide 10

Slide 10 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); AudioContext Λ࡞੒͢Δͱ͜Ζ͔Β͸͡·Δ

Slide 11

Slide 11 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); const sourceNode: AudioBufferSourceNode = context.createBufferSource(); const gainNode: GainNode = context.createGain(); const biquadFilterNode: BiquadFilterNode = context.createBiquadFilter(); const analyserNode: AnalyserNode = context.createAnalyser(); biquad Filter Node source Node gain Node analyser Node

Slide 12

Slide 12 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); const sourceNode: AudioBufferSourceNode = context.createBufferSource(); const gainNode: GainNode = context.createGain(); const biquadFilterNode: BiquadFilterNode = context.createBiquadFilter(); const analyserNode: AnalyserNode = context.createAnalyser(); biquad Filter Node source Node gain Node analyser Node "VEJP#VGGFS4PVSDF/PEF TUBSU XIFO PGGTFU EVSBUJPO  TUPQ XIFO  CVGGFSԻָσʔλ BT"VEJP#VGGFS MPPQUSVF ԻݯΛઃఆɾૢ࡞

Slide 13

Slide 13 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); const sourceNode: AudioBufferSourceNode = context.createBufferSource(); const gainNode: GainNode = context.createGain(); const biquadFilterNode: BiquadFilterNode = context.createBiquadFilter(); const analyserNode: AnalyserNode = context.createAnalyser(); biquad Filter Node source Node gain Node analyser Node (BJO/PEF HBJOWBMVF ʙ  ԻྔΛίϯτϩʔϧ

Slide 14

Slide 14 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); const sourceNode: AudioBufferSourceNode = context.createBufferSource(); const gainNode: GainNode = context.createGain(); const biquadFilterNode: BiquadFilterNode = context.createBiquadFilter(); const analyserNode: AnalyserNode = context.createAnalyser(); biquad Filter Node source Node gain Node analyser Node #JRVBE'JMUFS/PEF UZQF ༻ҙ͞ΕͨΤϑΣΫλʔΛֻ͚Δ GSFRVFODZWBMVF  ʙ  2WBMVF ʿ ʙ ʿ ʞMPXQBTTʟ ʞIJHIQBTTʟ ʞCBOEQBTTʟ ʞMPXTIFMGʟ ʞIJHITIFMGʟ FUD

Slide 15

Slide 15 text

8FC"VEJP"1*͜ͱ͸͡Ί const context: AudioContext = new (window.AudioContext || window.webkitAudioContext)(); const sourceNode: AudioBufferSourceNode = context.createBufferSource(); const gainNode: GainNode = context.createGain(); const biquadFilterNode: BiquadFilterNode = context.createBiquadFilter(); const analyserNode: AnalyserNode = context.createAnalyser(); biquad Filter Node source Node gain Node analyser Node "OBMZTFS/PEF ԻͷσʔλΛऔಘ͢Δ const analyzerParams = { times: new Uint8Array(analyserNode.frequencyBinCount), freqs: new Uint8Array(48), }; analyserNode.getByteTimeDomainData(analyzerParams.times); analyserNode.getByteFrequencyData(analyzerParams.freqs);

Slide 16

Slide 16 text

getByteTimeDomainData ͰऔಘͰ͖Δσʔλ getByteFrequencyData ͰऔಘͰ͖Δσʔλ

Slide 17

Slide 17 text

֤ /PEFͷ഑ઢ biquad Filter Node source Node gain Node analyser Node sourceNode.buffer = SOUND_BUFFER; sourceNode.connect(gainNode); gainNode.connect(biquadFilterNode); biquadFilterNode.connect(analyserNode); analyserNode.connect(context.destination); connect connect connect context.destination connect SOUND_BUFFER

Slide 18

Slide 18 text

4PVOE8BMLFSͷ഑ઢ

Slide 19

Slide 19 text

4PVOE8BMLFSͷ഑ઢ IUUQTZPVUVCF&:X089CCOL

Slide 20

Slide 20 text

4PVOE8BMLFSͷ഑ઢ IUUQTZPVUVCF9I%1D53VT

Slide 21

Slide 21 text

4PVOE8BMLFSͷ഑ઢ IUUQTZPVUVCF(1%OT$FG7I&

Slide 22

Slide 22 text

ಈ͘΋ͷ

Slide 23

Slide 23 text

8FC(-͜ͱ͸͡Ί ͞ΘͬͯΈΔͳΒϥΠϒϥϦ͕γϯϓϧ

Slide 24

Slide 24 text

8FC(-͜ͱ͸͡Ί IUUQTEFNPTMJUUMFXPSLTIPQGSUSBDL IUUQTJNNFSTJWFHDPNXJTIFT

Slide 25

Slide 25 text

8FC(-͜ͱ͸͡Ί import * as THREE from 'three'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); document.getElementById('screen').appendChild(renderer.domElement); scene camera γʔϯͱΧϝϥ͕Ͱ͖Δ ͜ΕΛ DBOWBTͱͯ͠ %0.΁௥Ճ

Slide 26

Slide 26 text

ΦϒδΣΫτΛੜ੒͢Δ const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0x000000 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); ཱํମ͕ઃஔ͞Εͨ scene cube

Slide 27

Slide 27 text

ϏδϡΞϥΠβʔͷத਎ ٖࣅίʔυ const rectShape = new THREE.Shape(); const OFFSET = 円の中心から付け根の距離; rectShape.moveTo( OFFSET * cos(角度) + (幅 / 2) * cos(角度 + π / 2), // X座標 OFFSET * sin(角度) + (幅 / 2) * sin(角度 + π / 2) // Y座標 ); rectShape.lineTo( OFFSET * cos(角度) + (幅 / 2) * cos(角度 - π / 2), OFFSET * sin(角度) + (幅 / 2) * sin(角度 - π / 2) ); rectShape.lineTo( 振幅 * cos(角度) + (幅 / 2) * cos(角度 + π / 2), 振幅 * sin(角度) + (幅 / 2) * sin(角度 + π / 2) ); rectShape.lineTo( 振幅 * cos(角度) + (幅 / 2) * cos(角度 - π / 2), 振幅 * sin(角度) + (幅 / 2) * sin(角度 - π / 2) ); ← OFFSET→

Slide 28

Slide 28 text

ϏδϡΞϥΠβʔͷத਎ ٖࣅίʔυ const rectShape = new THREE.Shape(); const OFFSET = 円の中心から付け根の距離; rectShape.moveTo( OFFSET * cos(角度) + (幅 / 2) * cos(角度 + π / 2), // X座標 OFFSET * sin(角度) + (幅 / 2) * sin(角度 + π / 2) // Y座標 ); rectShape.lineTo( OFFSET * cos(角度) + (幅 / 2) * cos(角度 - π / 2), OFFSET * sin(角度) + (幅 / 2) * sin(角度 - π / 2) ); rectShape.lineTo( 振幅 * cos(角度) + (幅 / 2) * cos(角度 + π / 2), 振幅 * sin(角度) + (幅 / 2) * sin(角度 + π / 2) ); rectShape.lineTo( 振幅 * cos(角度) + (幅 / 2) * cos(角度 - π / 2), 振幅 * sin(角度) + (幅 / 2) * sin(角度 - π / 2) ); ← OFFSET→ ͜͜ͷৼ෯̍ຊ

Slide 29

Slide 29 text

ը໘ͷస׵ IUUQTZPVUVCF)QOVR/&:

Slide 30

Slide 30 text

ը໘ͷస׵ 5ISFFKT DBOWBT 3FBDUKT $PNQPOFOUT 5ISFFKT DBOWBT ͕͜͜ τϥϯδγϣϯ ͍ͯ͠Δ

Slide 31

Slide 31 text

ը໘ͷస׵ const material = new THREE.ShaderMaterial({ ... }); const curtain = new THREE.Mesh(geometry, material); ShaderMaterial Λ࢖͏ͱɺ(-4-͕ॻ͚Δ

Slide 32

Slide 32 text

ը໘ͷస׵ uniform float mixRatio; uniform sampler2D tDiffuse1; uniform sampler2D tDiffuse2; varying vec2 vUv; void main() { vec4 tex1 = texture2D(tDiffuse1, vUv); vec4 tex2 = texture2D(tDiffuse2, vUv); gl_FragColor = mix(tex2, tex1, mixRatio); } const material = new THREE.ShaderMaterial({ }); material.uniforms.mixRatio.value = transition; mixRatio ΛมԽͤ͞Δ͜ͱͰ ̎ͭͷγʔϯΛ੾Γସ͑Δ

Slide 33

Slide 33 text

QPTUQSPDFTTJOH TDFOFʹඳը͞ΕͯΔϞϊͨͪશͯʹӨڹΛ༩͑ΔΤϑΣΫτ IUUQTZPVUVCF%N:[6BHPT

Slide 34

Slide 34 text

QPTUQSPDFTTJOH 5ISFFKT import { EffectComposer, RenderPass, EffectPass, GlitchEffect } from 'postprocessing'; const composer = new EffectComposer(renderer); composer.addPass(new RenderPass(scene, camera)); const glitchEffect = new GlitchEffect(); const glitchPass = new EffectPass(camera, glitchEffect); glitchPass.renderToScreen = false; composer.addPass(glitchPass); ͜ΕͰɺ͹Γ͹Γ͢Δԋग़͕ SFOEFSFSશମʹ͔͔Δ

Slide 35

Slide 35 text

ΞϯνΤΠϦΞεॲཧ import { EffectPass, SMAAEffect } from 'postprocessing'; const smaaEffect = new SMAAEffect(); smaaEffect.setEdgeDetectionThreshold(0.08); const smaaPass = new EffectPass(camera, smaaEffect); smaaPass.renderToScreen = false; composer.addPass(smaaPass); SMAAEffect Λ࢖͏͜ͱͰ SFOEFSFSશମʹΞϯνΤΠϦΞε͕͔͔Δ

Slide 36

Slide 36 text

දݱʗମݧΛߟ͑Δ

Slide 37

Slide 37 text

ԕ͘ͳ͍ະདྷͰ͸ 8FCͷήʔϜ 18" ͰΞϓϦฒΈʹ༡΂Δ͸ͣ

Slide 38

Slide 38 text

ΞϓϦͱൺ΂ͯͷϝϦοτ ɾ63-Λ౿Ί͹༡΂Δ ɾ8FC͍ͬͯ͏Πϯελϯτੑ ɾγΣΞͷ͠΍͢͞ ͜ΕΛ׆͔ͯ͠ɺ༡ͼํ΋ 1SPHSFTTJWFʹͪ͠Ό͑͹

Slide 39

Slide 39 text

ήʔϜηϯλʔͬͯͲ͏͍͏࣌ʹߦ͘ʁ Ո͡ΌͰ͖ͳ͍༡ͼํΛ͍ͨ࣌͠ ͨͱ͑͹ ݸਓͷ੠

Slide 40

Slide 40 text

ࣗ෼Ͱଗ͑ΒΕͳ͍ػࡐ͕͋Δͱ͜ΖͰ༡Ϳ

Slide 41

Slide 41 text

ྟ৔ײͨͬ΀ΓͳεϐʔΧʔ ͕͋ͬͨΓ େഭྗͷϏδϡΞϥΠβʔ͕͋ͬͨΓ ը૾Ҿ༻ɿ %+."9 NPTFT

Slide 42

Slide 42 text

໘ന͔ͬͨήʔϜΛ 18"Ͱ࣋ͪؼΔ

Slide 43

Slide 43 text

%&.0 %+ϛΩαʔͷ .*%*௨৴Λ #MVFUPPUIʹͷͤͯ 8FCͰड͚औͬͯΤϑΣΫλʔΛ͔͚ͯΈΑ͏ IUUQTZPVUVCFWR/T/P':

Slide 44

Slide 44 text

8FC#MVFUPPUI const device = await navigator.bluetooth.requestDevice({ filters: [{ services: [UUID.SERVICE] }], }); const server = await device.gatt.connect(); const service = await server.getPrimaryService(UUID.SERVICE); const characteristic = await service.getCharacteristic(UUID.CHARACTERISTIC); await characteristic.startNotifications(); const UUID = { SERVICE: '03b80e5a-ede8-4b33-a751-6ce34ec4c700‘, CHARACTERISTIC: '7772e5db-3868-4112-a1a9-f2669d106bf3', }; .*%*σόΠεͷ 66*%

Slide 45

Slide 45 text

.*%*#MVFUPPUI navigator.requestMIDIAccess({ sysex: true }) .then(onMIDISuccess, onMIDIFailure); ͦͷͨΊ .*%*ͷΞΫηε΋΋Β͓ͬͯ͘ ը૾Ҿ༻ɿ"NB[PODPN #MVFUPPUIΛ௨ͯ͠ .*%*ͷ௨৴͕Ͱ͖ΔΑ͏ʹͳΔϞϊ .*%*ϙʔτ΍ 64#ϙʔτ͕ͳ͍ σόΠεͰ΋ .*%*௨৴͕Ͱ͖Δ

Slide 46

Slide 46 text

ΤϑΣΫλʔΛૢ࡞͢Δ characteristic.addEventListener( 'characteristicvaluechanged‘, (event) => { const data = event.target.value; てきとうに処理... } ) biquad Filter Node ૢ࡞ .*%*͸ $-0$,γάφϧ͕͋ΔͨΊ characteristicvaluechanged ͸ΊͬͪΌൃՐ͢Δ ஫ҙ

Slide 47

Slide 47 text

8FC"TTFNCMZ8FC8PSLFS 8FC$SZQUP"1*  8FC"TTFNCMZͱ 8FC8PSLFS

Slide 48

Slide 48 text

8FC"TTFNCMZ

Slide 49

Slide 49 text

8FC"TTFNCMZ ϒϥ΢β༻ͷόΠφϦίʔυΛ༻ҙͯ͠ ͦΕΛ +BWB4DSJQUଆ͔Βಈ͔ٕ͢ज़ XBTN

Slide 50

Slide 50 text

XBTN ͷ࡞Γํ $$ --7. 3VTU wasm-pack (P ,PUMJO/BUJWF ͜ΕΒͷࢿ࢈Λ 8FCʹ࣋ͪࠐΉ͜ͱ͕Ͱ͖Δ

Slide 51

Slide 51 text

FNTDSJQUFO % emcc -O3 file.c -o file.wasm ୯ҰϑΝΠϧʹରͯ͠ % ./emconfigure ./configure % ./emmake make % emcc -O3 project.bc -o project.wasm ϓϩδΣΫτʹରͯ͠ -O3 ͸ϦϦʔεϏϧυʹదͨ͠࠷దԽ େจࣈͷΦʔͱ θϩ͡Όͳ͍Α

Slide 52

Slide 52 text

$ˠ XBTN ͷಓͷΓ #include EMSCRIPTEN_KEEPALIVE int add(int x, int y) { return x + y; } EMSCRIPTEN_KEEPALIVE ࢀর͕ͳ͍ؔ਺͕࠷దԽͰ ফ͞Εͯ͠·͏ Λ͚ͭͳ͍ͱɺ % emcc -O3 add.c -o add.wasm add.c ͬͦ͘͞Ͱ͖ͨ

Slide 53

Slide 53 text

+BWB4DSJQUͰಈ͔͢ const { instance } = await WebAssembly.instantiateStreaming(fetch('add.wasm'), {}); const result = instance.exports.add(1, 1); console.log(result); // -> 2 WebAssembly ʹ͸ଞͷಡΈࠐΈํ΋༻ҙ͞Ε͍ͯΔ instantiateStreaming ͕Ұ൪ޮ཰త ͚Ͳ

Slide 54

Slide 54 text

ݟ͔ͭΒͳ͍ NPEVMF ͍ΖΜͳ NPEVMF͕ͳ͍ΑͱݴΘΕΔ ελϯυΞϩϯͰಈ͔ͳ͍ܗࣜͰ XBTN ʹίϯύΠϧ͖ͯͯ͠Δ Ͱ΋ɺͦͬͪͷ΄͏͕ܰྔͩ͠ແବ͕ͳ͍

Slide 55

Slide 55 text

ݟ͔ͭΒͳ͍ NPEVMF await WebAssembly.instantiateStreaming(fetch('add.wasm'), imports); ͖ͬ͞͝·͔͍ͯͨ͠ୈҾ਺Λ͔ͭͬͯɺ ͦΕͧΕͷ NPEVMFΛఆ͍ٛͯ͘͠ඞཁ͕͋Δ const imports = { env: { __memory_base: 0, memory: new WebAssembly.Memory({ initial: 512 }), wasi_snapshot_preview1: (args) => { console.log(args); } } }; ͜Μͳ͔Μ͡

Slide 56

Slide 56 text

XBTN ͔Β JNQPSUͨؔ͠਺ console.log('instance.exports.add →', instance.exports.add); OBUJWFDPEFʹͳ͍ͬͯΔ

Slide 57

Slide 57 text

"TTFNCMZ4DSJQU export function add(a: i32, b: i32): i32 { return a + b; } 5ZQF4DSJQUͷײ֮Ͱॻ͚Δ % npm install --save-dev assemblyscript % npx asc add.ts -b add.wasm -O3 ɾͪΐͬͱ +4ͷॲཧૣ͍ͨ͘͠ͱ͜Ζ͕͋Δ ɾܭࢉΛଟ͘ͷ৔ॴͰ࢖͍ճ͢ $$ ͱ͔͸ա৒͚ͩͲ ͜͏͍͏ͱ͖ʹศར

Slide 58

Slide 58 text

8FC8PSLFS 8FC8PSLFS

Slide 59

Slide 59 text

8FC8PSLFS +BWB4DSJQUΛϝΠϯεϨου͔Β֎ͯ͠ɺ όοΫάϥ΢ϯυʹ͢Δٕज़ +BWB4DSJQU ϝΠϯεϨου 8PSLFS εϨου ॏ͍ॲཧ͸ ϝΠϯεϨουΛࢭΊͯ͠·͏ 8PSLFSʹ·͔ͤͯ ऴΘͬͨΒڭ͑ͯ΋Β͏ ݟͯͷ௨Γ ॏ͍ॲཧ

Slide 60

Slide 60 text

8FC8PSLFSΛ૊ΈࠐΉ const worker = new Worker('worker.js'); ͜ͷ࣌఺͔Β ͸ಈ͖࢝ΊΔ worker.js 8PSLFSࣗମ͸ී௨ͷ +BWB4DSJQU ͨͩɺσʔλͷड͚౉͠͸ QPTU.FTTBHF Ͱߦ͏ worker.postMessage('Hello from client');

Slide 61

Slide 61 text

σʔλͷड͚౉͠ const worker = new Worker('worker.js'); worker.postMessage('Hello from client'); worker.addEventListener('message', (message) => { console.log(message.data); // -> 'Hello from worker' }); DMJFOUKT self.postMessage('Hello from worker'); self.addEventListener('message', (message) => { console.log(message.data); // -> 'Hello from client' }); XPSLFSKT self ͸ͳͯ͘΋ಈ͘ const worker: Worker = self; Ͱ΋ඍົʹܕ͕ҧ͏͔Β 5ZQF4DSJQUͳΒɺ ͱͯ͠΋Α͍

Slide 62

Slide 62 text

σʔλͷड͚౉͠ͷࠔΔͱ͜Ζ ී௨ʹ QPTU.FTTBHF ͰσʔλૹΔͱίϐʔ͞ΕΔ ॏ͍ॲཧ͕Ͱ͖ΔͬͯݴͬͯΔ͚Ͳ .# ͘Β͍ͷಈըϑΝΠϧͳΜͯૹͬͨΒɺ ίϐʔ͞Εͯ (# ΋ϝϞϦΛͻͬഭͯ͠͠·͏ 5SBOTGFSBCMF0CKFDUΛ࢖͏ʂ

Slide 63

Slide 63 text

5SBOTGFSBCMF0CKFDU const video = new Uint8Array(500 * 1024 * 1024); worker.postMessage({ type: 'SEND_VIDEO', video }, [video.buffer]); QPTU.FTTBHF ͷୈҾ਺ʹ "SSBZͰ "SSBZ#VGGFS ͔ .FTTBHF1PSU ͔ *NBHF#JUNBQ Λ౉͢ 8PSLFS DMJFOU video

Slide 64

Slide 64 text

5SBOTGFSBCMF0CKFDU const video = new Uint8Array(500 * 1024 * 1024); worker.postMessage({ type: 'SEND_VIDEO', video }, [video.buffer]); QPTU.FTTBHF ͷୈҾ਺ʹ "SSBZͰ "SSBZ#VGGFS ͔ .FTTBHF1PSU ͔ *NBHF#JUNBQ Λ౉͢ 8PSLFS DMJFOU video video ͸ DMJFOU͔Βॴ༗ݖ͕ 8PSLFSʹҠΔ QPTU.FTTBHF ޙ DMJFOUͰࢀরͰ͖ͳ͍

Slide 65

Slide 65 text

଎͞ͷҧ͍ DMJFOUଆ worker.postMessage({ type: 'START_TIMER' }); const video = new Uint8Array(500 * 1024 * 1024); worker.postMessage({ type: 'SEND_VIDEO', video }); DMJFOUKTʢͦͷ··ૹΔʣ worker.postMessage({ type: 'START_TIMER' }); const video = new Uint8Array(500 * 1024 * 1024); worker.postMessage({ type: 'SEND_VIDEO', video }, [video.buffer]); DMJFOUKTʢ5SBOTGFSBCMF0CKFDUʣ

Slide 66

Slide 66 text

଎͞ͷҧ͍ XPSLFSଆ let startTime = null; self.addEventListener('message', (message) => { const { type, video } = message.data; switch (type) { case 'START_TIMER': startTime = performance.now(); break; case 'SEND_VIDEO': console.log(performance.now() - startTime); break; } }); XPSLFSKT

Slide 67

Slide 67 text

଎͞ͷҧ͍ ݁Ռ DMJFOUKTʢͦͷ··ૹΔʣ DMJFOUKTʢ5SBOTGFSBCMF0CKFDUʣ 866.2800000165589 0.9349999600090086 ര଎ ͍ͭͰʹলϝϞϦ

Slide 68

Slide 68 text

දݱʗମݧΛߟ͑Δ

Slide 69

Slide 69 text

ը૾ʗಈըΞϓϦ͕ΊͬͪΌߴػೳʹͳͬͯΔ ࡱͬͨΒ͙͢ʹ $MPVEʹ͕͋ͬͯ ୭͕ࣸͬͯΔ͔ɺͲ͜ʹ͍͔ͨ·ͱΊͯ͘ΕΔ ৔ॴผ ਓ෺ผ ͱͯ΋΂ΜΓʂ

Slide 70

Slide 70 text

ҰํͰ ࣗ෼ͷࣸਅɾಈըΛʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓ͍ͩͬͯΔ ʮͰ΋ɺ$MPVEʹ͋͛ΕͨΒɺखݩͷ༰ྔݮΒͤΔ͠ͳʔʜʯ ʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓɿ ʮϓϥΠϕʔτΫϥ΢υΈ͍ͨͷ࢖͑͹ʁʯ ఢɿ ʮͦ͏͍͏ͷͬͯຊ౰ʹ๣ௌ͞Εͯͳ͍͔ͱ͔ɺ ෼ੳʹ࢖ΘΕͯͳ͍͔ͱ͔Θ͔Μͳ͘ͳ͍ʁʁʯ ʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓɿ

Slide 71

Slide 71 text

ࣗ෼ͰʢϩʔΧϧͰʣ΍Δ͔͠ͳ͍͡ΌΜʂ ը૾͸αϜωΠϧ੾Γग़͠Λͯ͠ ಈը͸Τϯίʔυ αϜωΠϧ੾Γग़͠Λͯ͠ ҉߸Խͨ͠΋ͷ͚ͩΛ֎ʹग़͢Α͏ʹ͠Α͏ ΍Δ͔͠ͳ͍ ʢʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓஊ ʣ

Slide 72

Slide 72 text

΍Δͧ ҉߸Խ͞Εͯͳ͍σʔλΛͲ͔͜ʹૹΔͳΜͯͰ͖ͳ͍ʂ ը૾ͷαϜωΠϧԽ *NBHF.BHJDL ͕࢖͑ͦ͏ ಈըͷΤϯίʔυ ''.1&(͕͍͍ͳ

Slide 73

Slide 73 text

import * as Magick from 'https://knicknic.github.io/wasm-imagemagick/magickApi.js'; const call = async function() { const fetchedSourceImage = await fetch('sample.png‘); const arrayBuffer = await fetchedSourceImage.arrayBuffer(); const sourceBytes = new Uint8Array(arrayBuffer); const files = [{ name: 'srcFile.png', content: sourceBytes }]; const command = ['convert', 'srcFile.png', '-rotate', '90', '-resize', '200%', 'out.png']; const processedFiles = await Magick.Call(files, command); const firstOutputImage = processedFiles[0]; document.getElementById('rotatedImage').src = URL.createObjectURL(firstOutputImage['blob']); console.log('created image ' + firstOutputImage['name']); }; call(); XBTNJNBHFNBHJDL *NBHF.BHJDL Λ XBTN Ͱಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ

Slide 74

Slide 74 text

import * as Magick from 'https://knicknic.github.io/wasm-imagemagick/magickApi.js‘; const call = async function() { const fetchedSourceImage = await fetch('sample.png‘); const arrayBuffer = await fetchedSourceImage.arrayBuffer(); const sourceBytes = new Uint8Array(arrayBuffer); const files = [{ name: 'srcFile.png', content: sourceBytes }]; const command = ['convert', 'srcFile.png', '-rotate', '90', '-resize', '200%', 'out.png']; const processedFiles = await Magick.Call(files, command); const firstOutputImage = processedFiles[0]; document.getElementById('rotatedImage').src = URL.createObjectURL(firstOutputImage['blob']); console.log('created image ' + firstOutputImage['name']); }; call(); XBTNJNBHFNBHJDL *NBHF.BHJDL Λ XBTN Ͱಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ ͜Εܥɺσʔλ͸͍͍ͩͨ "SSBZ#VGGFS Ͱ΍ΓͱΓ͢Δ

Slide 75

Slide 75 text

import * as Magick from 'https://knicknic.github.io/wasm-imagemagick/magickApi.js‘; const call = async function() { const fetchedSourceImage = await fetch('sample.png‘); const arrayBuffer = await fetchedSourceImage.arrayBuffer(); const sourceBytes = new Uint8Array(arrayBuffer); const files = [{ name: 'srcFile.png', content: sourceBytes }]; const command = ['convert', 'srcFile.png', '-rotate', '90', '-resize', '200%', 'out.png']; const processedFiles = await Magick.Call(files, command); const firstOutputImage = processedFiles[0]; document.getElementById('rotatedImage').src = URL.createObjectURL(firstOutputImage['blob']); console.log('created image ' + firstOutputImage['name']); }; call(); XBTNJNBHFNBHJDL *NBHF.BHJDL Λ XBTN Ͱಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ *NBHF.BHJDL Ͱ࢖͑ΔίϚϯυ͸͍͍ͩͨಈ͘

Slide 76

Slide 76 text

const ffmpeg = new Worker('/workers/ffmpeg-worker-webm.js'); const call = async () => { const fetchedSourceMov = await fetch('sample.mov'); const arrayBuffer = await fetchedSourceMov.arrayBuffer(); const item = new Uint8Array(arrayBuffer); await new Promise((resolve, reject) => { ffmpeg.postMessage({ type: 'run', MEMFS: [{ name: 'input', data: item }], arguments: ['-ss', '2', '-i', 'input', '-f', 'image2', '-vframes', '1', 'out.jpg'] }); }); }; call(); GGNQFHKT GGNQFH Λ XBTN ͱ XPSLFSͰಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ

Slide 77

Slide 77 text

const ffmpeg = new Worker('/workers/ffmpeg-worker-webm.js'); const call = async () => { const fetchedSourceMov = await fetch('sample.mov'); const arrayBuffer = await fetchedSourceMov.arrayBuffer(); const item = new Uint8Array(arrayBuffer); await new Promise((resolve, reject) => { ffmpeg.postMessage({ type: 'run', MEMFS: [{ name: 'input', data: item }], arguments: ['-ss', '2', '-i', 'input', '-f', 'image2', '-vframes', '1', 'out.jpg'] }); }); }; call(); GGNQFHKT GGNQFH Λ XBTN ͱ XPSLFSͰಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ ઌʹशͬͯ "SSBZ#VGGFS ʹͯ͠Δ͚ͩ

Slide 78

Slide 78 text

const ffmpeg = new Worker('/workers/ffmpeg-worker-webm.js'); const call = async () => { const fetchedSourceMov = await fetch('sample.mov'); const arrayBuffer = await fetchedSourceMov.arrayBuffer(); const item = new Uint8Array(arrayBuffer); await new Promise((resolve, reject) => { ffmpeg.postMessage({ type: 'run', MEMFS: [{ name: 'input', data: item }], arguments: ['-ss', '2', '-i', 'input', '-f', 'image2', '-vframes', '1', 'out.jpg'] }); }); }; call(); GGNQFHKT GGNQFH Λ XBTN ͱ XPSLFSͰಈ࡞Ͱ͖ΔΑ͏ʹͯ͘͠ΕͯΔϞδϡʔϧ .&.'4 8FC"TTFNCMZͰ࣋ͬͯΔϑΝΠϧγεςϜͷ̍ͭ ϝϞϦۭؒΛ࢖ͬͨϑΝΠϧγεςϜ

Slide 79

Slide 79 text

ffmpeg.onmessage = (event) => { switch (event.data.type) { case 'done': if (msg.data.MEMFS[0]) { const textDecoder = new TextDecoder(); const thumbUnit8 = msg.data.MEMFS[0].data; const img = textDecoder.decode(thumbUnit8); document.getElementById('thumb').src = img; } break; } }; GGNQFHKTʢσʔλͷडऔʣ

Slide 80

Slide 80 text

ffmpeg.onmessage = (event) => { switch (event.data.type) { case 'done': if (msg.data.MEMFS[0]) { const textDecoder = new TextDecoder(); const thumbUnit8 = msg.data.MEMFS[0].data; const img = textDecoder.decode(thumbUnit8); document.getElementById('thumb').src = img; } break; } }; GGNQFHKTʢσʔλͷडऔʣ #ZUF4USFBNΛ 4USJOHʹ͢ΔͨΊ

Slide 81

Slide 81 text

͋ͱ͸҉߸Խ αʔόʔΛ࢖Θͣʹɺ +BWB4DSJQU͚ͩͰαϜωΠϧɺΤϯίʔυ͕Ͱ͖ͦ͏ʂ ҉߸Խ΋ࣗલͰ΍͔ͬͯΒαʔόʔʹσʔλΛૹΖ͏ XBTN ͨͪ

Slide 82

Slide 82 text

8FC$SZQUP"1*

Slide 83

Slide 83 text

8FC$SZQUP"1* ·ͣɺݤΛͭ͘Δ const cryptoKey: CryptoKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'] ); const jwk = await crypto.subtle.exportKey('jwk', cryptoKey); ࡞ΓऴΘͬͨΒ FYQPSUͯ͠ *OEFYFE%# ͱ͔ʹอଘ͓ͯ͘͠ͱྑ͍

Slide 84

Slide 84 text

8FC$SZQUP"1* ·ͣɺݤΛͭ͘Δ const cryptoKey: CryptoKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'] ); ҉߸Խར༻Ϟʔυ const jwk = await crypto.subtle.exportKey('jwk', cryptoKey); ࡞ΓऴΘͬͨΒ FYQPSUͯ͠ *OEFYFE%# ͱ͔ʹอଘ͓ͯ͘͠ͱྑ͍

Slide 85

Slide 85 text

8FC$SZQUP"1* ·ͣɺݤΛͭ͘Δ const cryptoKey: CryptoKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'] ); ݤ͕ΤΫεϙʔτՄೳ͔Ͳ͏͔ ҉߸Խར༻Ϟʔυ const jwk = await crypto.subtle.exportKey('jwk', cryptoKey); ࡞ΓऴΘͬͨΒ FYQPSUͯ͠ *OEFYFE%# ͱ͔ʹอଘ͓ͯ͘͠ͱྑ͍

Slide 86

Slide 86 text

8FC$SZQUP"1* ·ͣɺݤΛͭ͘Δ const cryptoKey: CryptoKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'] ); ҉߸Խͱ෮߸Խ͕ڐՄ͞Εͨݤ ݤ͕ΤΫεϙʔτՄೳ͔Ͳ͏͔ ҉߸Խར༻Ϟʔυ const jwk = await crypto.subtle.exportKey('jwk', cryptoKey); ࡞ΓऴΘͬͨΒ FYQPSUͯ͠ *OEFYFE%# ͱ͔ʹอଘ͓ͯ͘͠ͱྑ͍

Slide 87

Slide 87 text

'JMFΛ҉߸Խ͢Δ·Ͱ const textEncoder = new TextEncoder(); const reader = new FileReaderSync(); const blob = new Blob([file as File], { type: file.type }); const stringItem: string = reader.readAsDataURL(blob); const encodedBlob: Uint8Array = textEncoder.encode(stringItem); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); const cryptedBuffer: ArrayBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encodedBlob ); const cryptedItem = new Uint8Array(cryptedBuffer);

Slide 88

Slide 88 text

'JMFΛ҉߸Խ͢Δ·Ͱ const textEncoder = new TextEncoder(); const reader = new FileReaderSync(); const blob = new Blob([file as File], { type: file.type }); const stringItem: string = reader.readAsDataURL(blob); const encodedBlob: Uint8Array = textEncoder.encode(stringItem); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); const cryptedBuffer: ArrayBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encodedBlob ); const cryptedItem = new Uint8Array(cryptedBuffer); ΍΍͍͚͜͠Ͳ 8FC$SZQUP"1*ʹ͔͚ΕΔܗʹ͍ͯ͠Δ͚ͩ

Slide 89

Slide 89 text

'JMFΛ҉߸Խ͢Δ·Ͱ const textEncoder = new TextEncoder(); const reader = new FileReaderSync(); const blob = new Blob([file as File], { type: file.type }); const stringItem: string = reader.readAsDataURL(blob); const encodedBlob: Uint8Array = textEncoder.encode(stringItem); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); const cryptedBuffer: ArrayBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encodedBlob ); const cryptedItem = new Uint8Array(cryptedBuffer); ͕͜͜҉߸ԽΛͯ͠Δͱ͜Ζ

Slide 90

Slide 90 text

'JMFΛ҉߸Խ͢Δ·Ͱ const textEncoder = new TextEncoder(); const reader = new FileReaderSync(); const blob = new Blob([file as File], { type: file.type }); const stringItem: string = reader.readAsDataURL(blob); const encodedBlob: Uint8Array = textEncoder.encode(stringItem); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); const cryptedBuffer: ArrayBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encodedBlob ); const cryptedItem = new Uint8Array(cryptedBuffer); ॳظԽʢΠχγϟϧʣϕΫτϧ ಉ͡ΞΠςϜΛಉ͡ݤͰ҉߸Խͯ͠΋ ݁Ռ͕มΘΔΑ͏ʹ͢ΔͨΊʹඞཁ

Slide 91

Slide 91 text

ͪͳΈʹ෮߸Խ const textDecoder = new TextDecoder(); const rawBuffer : ArrayBuffer = await crypto.subtle.decrypt( { name: 'AES-GCM', iv }, cryptoKey, cryptedItem ); const rawItem = new Uint8Array(rawBuffer); const thumb: string = textDecoder.decode(rawItem); crypto.subtle.decrypt Λ࢖͔ͬͯΒ҉߸Խͷ൓ରͷॱংͰ TUSJOH·Ͱ͍࣋ͬͯ͘

Slide 92

Slide 92 text

%&.0 Ͱ౉͞ΕͨࣸਅɾಈըΛ ੈքʹ͹Εͳ͍Α͏ʹखݩͰॲཧ͔ͯ͠Β ҉߸ԽΛͯ͠Ξοϓϩʔυͯ͠ΈΑ͏ IUUQTZPVUVCFPF9R#K8,: IUUQTZPVUVCFCR3RIU,1*

Slide 93

Slide 93 text

1VTI"1*͍··Ͱͷ "1*  1VTI"1*

Slide 94

Slide 94 text

1VTI"1* ΞϓϦͷΑ͏ʹ௨஌͕ग़ͤΔ࢓૊Έ ͍͔ͭ͘ͷ࣮૷ͷ࢓ํ͕͋Δ͚ΕͲ 'JSFCBTF$MPVE.FTTBHJOH͕؆୯ͰԠ༻·ͰͰ͖Δ ˞"OESPJEͷΈରԠ

Slide 95

Slide 95 text

'JSFCBTF$MPVE.FTTBHJOH { name: 'app-name‘, short_name: 'app-shrt‘, ..., gcm_sender_id: 'xxxxxxxxxxxx' }; 'JSFCBTFͰϓϩδΣΫτΛ࡞੒ gcm_sender_idΛݟ͚ͭͯ NBOJGFTUKTPO ʹ௥Ճ NBOJGFTUKTPO )5.-ʹ௥Ճ

Slide 96

Slide 96 text

4FSWJDF8PSLFSͷ௥Ճ 4FSWJDF8PSLFSɿϖʔδΛดͯ͡΋ಈ͍ͯ͘ΕΔ 8PSLFS navigator.serviceWorker.register(‘/service-worker.js') navigator ͔Β௥Ճ͢Δ service-worker.js ผͷϥΠϑαΠΫϧͰ ಈ͖ग़͢ XJOEPX

Slide 97

Slide 97 text

'JSFCBTF͔Βͷ௨஌Λड͚Δ ͜ΕͰ 8FCϖʔδ͕ όοΫάϥ΢ϯυʗλεΫΩϧঢ়ଶͰ΋௨஌͕ड͚औΕΔ import * as firebase from 'firebase/app'; import 'firebase/messaging'; const messaging = firebase.messaging(); messaging.setBackgroundMessageHandler((payload) => { console.log(payload); }); TFSWJDFXPSLFSKT

Slide 98

Slide 98 text

8FCϖʔδʹ͍Δͱ͖ͷ௨஌ import * as firebase from 'firebase/app'; import 'firebase/messaging'; const messaging = firebase.messaging(); messaging.onMessage((payload) => { console.log(payload); }); Ͱ΋ड͚औΕΔ͚Ͳ addEventListener('push', () => {}); 'JSFCBTFͰߦ͘ͳΒ PO.FTTBHF Ͱ 0, DMJFOUKTʢ8PSLFS͡Όͳ͍ํͰʣ

Slide 99

Slide 99 text

import * as firebase from 'firebase/app'; import 'firebase/messaging'; const messaging = firebase.messaging(); const registration = await navigator.serviceWorker.register('/service-worker.js'); try { await messaging.requestPermission(); messaging.usePublicVapidKey(FIREBASE_PUBLIC_VAPID_KEY); messaging.useServiceWorker(registration); const token = await messaging.getToken(); console.log(token); } catch (e) { console.log('rejected!'); } ௨஌ͷڐՄͱ UPLFOͷऔಘ

Slide 100

Slide 100 text

import * as firebase from 'firebase/app'; import 'firebase/messaging'; const messaging = firebase.messaging(); const registration = await navigator.serviceWorker.register('/service-worker.js'); try { await messaging.requestPermission(); messaging.usePublicVapidKey(FIREBASE_PUBLIC_VAPID_KEY); messaging.useServiceWorker(registration); const token = await messaging.getToken(); console.log(token); } catch (e) { console.log('rejected!'); } ௨஌ͷڐՄͱ UPLFOͷऔಘ 'JSFCBTFͷίϯιʔϧ͔Β࣋ͬͯ͜ΕΔ ௨஌ͷڐՄΛऔΓʹߦ͘ ͜͜Ͱ UPLFOΛखʹೖΕΔ

Slide 101

Slide 101 text

௨஌ڐՄͷμϝͳྫ ϖʔδ͸͍͙ͬͯ͢ʹ௨஌ڐՄΛऔΖ͏ͱ͢Δ 8FCαΠτ ͱͯ΋ةݥ ͲΜͳίϯςϯπ͕ͦ͜ʹ͋Δ͔Θ͔Βͳ͍Ϣʔβʔ͕ ڐՄ͢ΔϝϦοτ͕ͳ͍ ͳΜͷؾͳ͠ʹɺϒϩοΫΛ͞ΕΔͱυϝΠϯͰڋ൱͞ΕΔͷͰɺ ೋ౓ͱϢʔβʔʹ௨஌ΛૹΔνϟϯε͕ͳ͘ͳΔʹͻͱ͍͠

Slide 102

Slide 102 text

഑ྀͨ͠ྫ ࣗલͷμΠΞϩάͰαϯυϘοΫεతʹଅ͢ͷ͕ྑ͍ $MJDL Ϣʔβʔ͕௨஌Λ΄͍͠ͱײͦ͡͏ͳ৔໘Ͱ΍Δͱ͍͍ΑͶ ͓ؾʹೖΓͷϢʔβʔͷ৽ண͕ؾʹͳΓ·ͤΜ͔ʁ ΠϕϯτͷεέδϡʔϧΛ͓஌Βͤ͠·͢Α ͋ͳ͕ͨ޷͖ͦ͏ͳهࣄ͕ͰͨΒ͓ಧ͚ͯ͠ྑ͍ʁ ͨͱ͑͹͜Μͳ

Slide 103

Slide 103 text

ಛఆͷϢʔβʔʹ௨஌͢Δ https://fcm.googleapis.com/v1/projects/{project-id}/messages:send ͜͜ʹ 1045͢Δ headers: { 'content-type': 'application/json', authorization: `Bearer ${VALID_OAUTH_2_0_TOKEN}` }, body: JSON.stringify({ message: { token, notification: { title: 'これはタイトル', body: 'こっちは本文' } } })

Slide 104

Slide 104 text

ಛఆͷϢʔβʔʹ௨஌͢Δ https://fcm.googleapis.com/v1/projects/{project-id}/messages:send ͜͜ʹ 1045͢Δ headers: { 'content-type': 'application/json', authorization: `Bearer ${VALID_OAUTH_2_0_TOKEN}` }, body: JSON.stringify({ message: { token, notification: { title: 'これはタイトル', body: 'こっちは本文' } } }) (PPHMF"1*ΫϥΠΞϯτϥΠϒϥϦͰ +85Λऔಘ

Slide 105

Slide 105 text

ಛఆͷϢʔβʔʹ௨஌͢Δ https://fcm.googleapis.com/v1/projects/{project-id}/messages:send ͜͜ʹ 1045͢Δ headers: { 'content-type': 'application/json', authorization: `Bearer ${VALID_OAUTH_2_0_TOKEN}` }, body: JSON.stringify({ message: { token, notification: { title: 'これはタイトル', body: 'こっちは本文' } } }) (PPHMF"1*ΫϥΠΞϯτϥΠϒϥϦͰ +85Λऔಘ ͖ͬ͞ͷ UPLFO

Slide 106

Slide 106 text

දݱʗମݧΛߟ͑Δ

Slide 107

Slide 107 text

͔͜͜Β͸ڠྗͯ͠΋Βͬͨௐࠪ݁Ռ΋దٓग़͍ͯ͘͠Α ͝ڠྗ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ

Slide 108

Slide 108 text

ੈքதηϯαʔͰҲΕ͔͑ͬͯΔ Թ౓͕Θ͔Γ·͢ ࣪౓Λײ͡·͢ Ի͕ฉ͑͜·͢

Slide 109

Slide 109 text

ੈքதηϯαʔͰҲΕ͔͑ͬͯΔ ۙ͘ͷ #MVFUPPUI͕ݟΕ·͢ ໌Δ͞Λ൑ఆ͠·͢ Ի͕ฉ͑͜·͢ Ҡಈ଎౓͕Θ͔Γ·͢ Χϝϥ͋Γ·͢ ͍ͭͰʹɺ͍͍ͩͨΦϯϥΠϯ

Slide 110

Slide 110 text

͍͕ͭ͜൓ضΛ຋͢ͱාͦ͏ ৐ͬऔΒΕΔͱ·͍ͣ

Slide 111

Slide 111 text

23ΛಡΈࠐΉ͚ͩͰ 63-ʹδϟϯϓ service-worker Πϯετʔϧ͞ΕΔ ͋ͱ͸௨஌ڐՄ͑͞΋Β͑Ε͹ λεΫΩϧ͞Εͯͯ΋ಈ͔ͤͦ͏ 1VTI"1*Λߟ͑Δͱ

Slide 112

Slide 112 text

ಈ͔ͤͦ͏ʁ ௨஌ग़ͤΔ͚ͩ͡Όͳ͍ͷʁ ௨஌ϝοηʔδͱσʔλϝοηʔδ͕͋Δ ௨஌ϝοηʔδɿ ௨஌Λग़͚ͩ͢ͷϝοηʔδ σʔλϝοηʔδɿ σʔλΛड͚औͬͯ 4FSWJDF8PSLFS ಺Ͱॲཧ͢Δ

Slide 113

Slide 113 text

ಈ͔ͤͦ͏ʁ ௨஌ग़ͤΔ͚ͩ͡Όͳ͍ͷʁ ௨஌ϝοηʔδͱσʔλϝοηʔδ͕͋Δ ௨஌ϝοηʔδɿ ௨஌Λग़͚ͩ͢ͷϝοηʔδ σʔλϝοηʔδɿ σʔλΛड͚औͬͯ 4FSWJDF8PSLFS ಺Ͱॲཧ͢Δ ʮΉΉʯ

Slide 114

Slide 114 text

message: { token, data: { ... } } message: { token, notification: { title: 'これはタイトル‘, body: 'こっちは本文‘ } } ௨஌ϝοηʔδ σʔλϝοηʔδ ௨஌Λग़͞ͳͯ͘΋ྑ͍ 4FSWJDF8PSLFS ͕ಈ࡞͢Δ

Slide 115

Slide 115 text

4FSWJDF8PSLFS ͰͰ͖Δ͜ͱ WorkerNavigator Navigator battery connection geolocation lock permissions serviceWorker storage xr vibrate clipboard usb bluetooth credentials :Battery Status API :Network Information API :Geolocation API :Web Lock API :Permission API :ServiceWorkerContainer :Storage API :Web XR Device API :Vibration API :Clipboard API :Web USB :Web Bluetooth :Credentials Container connection lock permissions storage :Network Information API :Web Lock API :Permission API :Storage API 'FUDI"1*͕ಈ͘ ͋ͱ

Slide 116

Slide 116 text

4FSWJDF8PSLFS ͰͰ͖Δ͜ͱ WorkerNavigator Navigator battery connection geolocation lock permissions serviceWorker storage xr vibrate clipboard usb bluetooth credentials :Battery Status API :Network Information API :Geolocation API :Web Lock API :Permission API :ServiceWorkerContainer :Storage API :Web XR Device API :Vibration API :Clipboard API :Web USB :Web Bluetooth :Credentials Container connection lock permissions storage :Network Information API :Web Lock API :Permission API :Storage API 'FUDI"1*͕ಈ͘ ͋ͱ ʮ͋ͬʯ

Slide 117

Slide 117 text

%&.0 ࢦఆͨ͠ 63-Λୟ͖ʹߦͬͯ΋Β͓ IUUQTZPVUVCF)HR/XHIMTX

Slide 118

Slide 118 text

#PUOFUͷΑ͏ͳৼΔ෣͍ service-worker ߈ܸϓϩάϥϜೖΓ ߈ܸର৅ 63-Λ̍ͭ౿Ή͚ͩͰ #PUOFUʹͳΔةݥੑ %%04߈ܸʂ

Slide 119

Slide 119 text

ΩϟϦΞճઢͱ 8*'*ซ༻Ͱ *1มΘͬͪΌͬͯ ϒϩοΩϯά΋Ή͍͔ͣ΋ʁ ௐࠪ݁Ռ Ұ೔ͷ͏ͪʹͲͷ͘Β͍ *1มΘΔʁ Ұਓ͋ͨΓ <ݸ> ೔Ͱ࢖༻͢Δ *1ΞυϨε Մ΋ͳ͘ෆՄ΋ͳ͘

Slide 120

Slide 120 text

ϗϯτ͸ͦΜͳ৺഑͡Όͳ͍ ͍͍ͩͨ͜Ε͕कͬͯ͘ΕΔ

Slide 121

Slide 121 text

ྑ͍࢖ΘΕํ΋ߟ͍͑ͨ

Slide 122

Slide 122 text

දݱʗମݧΛߟ͑Δ ͖͠Γͳ͓͠

Slide 123

Slide 123 text

ΠέͯΔ 8FCΞϓϦ࡞͚ͬͨͲ ӡӦ͍ͯ͘͠ҡ࣋අ͕͖͍ͭ

Slide 124

Slide 124 text

ΠέͯΔ 8FCΞϓϦ࡞͚ͬͨͲ ӡӦ͍ͯ͘͠ҡ࣋අ͕͖͍ͭ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ ޿ࠂ

Slide 125

Slide 125 text

Ծ૝௨՟Λ۷ͬͯΈΔʁ $PJOIJWF Ͱѱ໊ΛͻΖΊͨʠϒϥ΢βϕʔεϚΠχϯάʡ ແڐՄͰ΍Δͷ͸μϝͳͷ͸΋ͪΖΜͷ͜ͱ ޿ࠂ͸ग़ͨ͘͠ͳ͍ ҡ࣋අ͸୲อ͍ͨ͠ ͜͏͍͏৚݅ԼͰ͸ྑ͍ΞΠσΞͰ͸͋Δ

Slide 126

Slide 126 text

Ͱ΋ڐՄΛऔͬͨ·ͱ΋ͳར༻Ͱ΋ 69ΘΔ͍͘ͳ͍ʁ 8FCΞϓϦ࢖ͬͯΔ࠷தʹ ೤͘ͳΔ ి஑৯͏ ॏ͍ Ϣʔβʔ཭Εͦ͏

Slide 127

Slide 127 text

ࠒ߹͍Λݟͯ΍Δ Ұ൪࢖ͬͯͳͯ͘ɺόοςϦʔ΋৺഑ͳͯ͘ ΦϯϥΠϯͰ͔ͭߴ଎Ͱ઀ଓ͞ΕͯΔঢ়ଶ ॆి͞Εͯͯɺ8J'Jʹͭͳ͕ͬͯͳ͍ʁ

Slide 128

Slide 128 text

0 5 10 15 20 25                           TMPXH H H H ຊ౰ͩΖ͔ ௐࠪ݁Ռ Ұ೔தͱ͓ͯ͠ͷ୺຤ͷ଎౓ͬͯͲͷ͘Β͍ʁ ࣌ؒ ਓ਺

Slide 129

Slide 129 text

0 5 10 15 20 25                           TMPXH H H H ຊ౰ͩΖ͔ ௐࠪ݁Ռ Ұ೔தͱ͓ͯ͠ͷ୺຤ͷ଎౓ͬͯͲͷ͘Β͍ʁ ࣌ؒ ਓ਺ ͍͍ͩͨɺ͍ͭ΋଎͍

Slide 130

Slide 130 text

0 5 10 15 20 25                           TMPXH H H H ຊ౰ͩΖ͔ ௐࠪ݁Ռ Ұ೔தͱ͓ͯ͠ͷ୺຤ͷ଎౓ͬͯͲͷ͘Β͍ʁ ࣌ؒ ਓ਺ ͍ͯ͠ݴ͑͹ ͜ͷ΁ΜࠞΜͰΔ

Slide 131

Slide 131 text

0 5 10 15 20 25                           TMPXH H H H ຊ౰ͩΖ͔ ௐࠪ݁Ռ Ұ೔தͱ͓ͯ͠ͷ୺຤ͷ଎౓ͬͯͲͷ͘Β͍ʁ ࣌ؒ ਓ਺ ਂ໷͔Βૣே͸ ͪΐͬͱۭ͍ͯΔʁ

Slide 132

Slide 132 text

3PVOE5SJQ5JNF                                   3PVOE5SJQ5JNF SUU ࣌ࠁ

Slide 133

Slide 133 text

3PVOE5SJQ5JNF                                   3PVOE5SJQ5JNF 0 5 10 15 20 25                           TMPXH H H H ҰͭલͷάϥϑͷԼͷํ SUU ࣌ࠁ

Slide 134

Slide 134 text

ݴ͍͔ͨͬͨ͜ͱ͸ ৸ͯͦ͏ͳ࣌ؒ͸֨ผ଎͍͸ͣʂ ͚ͩͬͨͲ ͍͍ͩͨ଎͍ͳΒɺ·͊ 0,Ͱ͠ΐ͏

Slide 135

Slide 135 text

දݱʗମݧΛߟ͑Δ ̏ͭΊ

Slide 136

Slide 136 text

ʮ͖ͬ͞ϩʔΧϧͰը૾ʗಈըΛ҉߸Խ͚ͨ͠Ͳɺ ΋͏ϩʔΧϧʹ࣋ͬͯΔͷ΋ෆ҆ʯ ʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓɿ ʮͩͬͯ 4FSWJDF8PSLFS͍ͬͯ͏ͷΈͨ͠ʯ ʮͳʹ͞ΕͯΔ͔Θ͔ͬͨ΋Μ͡Όͳ͍ΑͶʯ ʮͦ΋ͦ΋҆৺ͬͯͳʹΛ࣋ͬͯͦ͏͍͏;͏ʹݴͬͯ

Slide 137

Slide 137 text

ʮ͋ɺ҉߸Խͯ͠όϥͯ͠ੈքதʹ෼ࢄͤ͞Αʯ ʠͱ΍͔͘ʡ͞Εͨ͘ͳ͍ਓɿ ڕΛӅ͢ͳΒւͩΑͶ εϚϗͷւ΁

Slide 138

Slide 138 text

ݤ" ݤ# ݤ$ ݤ% ҉߸Խͨ͠ϑΝΠϧΛ෼ׂͯ͠഑෍ɺ഑෍ઌͷݤͰߋʹ҉߸Խ ΋͏ͪΐͬͱ۩ମతʹ͸

Slide 139

Slide 139 text

·ͨ͸ ݤ" ݤ# ݤ$ ݤ% ద౰ͳ਺ϗοϓͤͯ͞ɺ҉߸Խͱෳ߹Λ܁Γସ͑͢ ࠷ऴతʹ %ʹ࣋ͬͯͯ΋Β͏

Slide 140

Slide 140 text

https://fcm.googleapis.com/v1/projects/{project-id}/messages:send headers: { 'content-type': 'application/json', authorization: `Bearer ${VALID_OAUTH_2_0_TOKEN}` }, body: JSON.stringify({ message: { token, data: { ... } } }) 1VTI"1*ͷ࿩ʹཱͪฦΔͱ

Slide 141

Slide 141 text

https://fcm.googleapis.com/v1/projects/{project-id}/messages:send headers: { 'content-type': 'application/json', authorization: `Bearer ${VALID_OAUTH_2_0_TOKEN}` }, body: JSON.stringify({ message: { token, data: { ... } } }) 1VTI"1*ͷ࿩ʹཱͪฦΔͱ ୭ʹૹΔ͔ αʔόʔͷೝূΩʔ ͜ͷ͕̎ͭ͋Ε͹ 8FC1VTI͸ Ͳ͔͜ΒͰ΋୭͔ΒͰ΋ૹΕΔ

Slide 142

Slide 142 text

ฦͯ͠΄͍࣌͠ʢෳ߹࣌ʣ ฦͯ͠ʂ ͍ͬͯ͏ 1VTI௨஌ΛૹΔ ෳ߹ ෳ߹ ෳ߹ ෳ߹ ݟΕΔʂ ݤ" ݤ# ݤ$ ݤ%

Slide 143

Slide 143 text

·ͨ͸ ݤ" ݤ# ݤ$ ݤ% ฦͯ͠ʂ ฦͯͩͬͯ͠ ฦͯͩͬͯ͠ ͓ͬ

Slide 144

Slide 144 text

·ͨ͸ ݤ" ݤ# ݤ$ ݤ% ฦͯ͠ʂ ฦͯͩͬͯ͠ ฦͯͩͬͯ͠ ͓ͬ ෳ߹ ෳ߹ ෳ߹ ෳ߹ ݟΕΔʂ

Slide 145

Slide 145 text

                      Ԡ౴࣌ؒ<ඵ> ࣌ࠁ ฏۉԠ౴࣌ؒ ͦΕͬͯݱ࣮తʁ ௐࠪ݁Ռ 1VTI"1*ͬͯΈΜͳͲΕ͘Β͍Ͱฦͯ͘͠ΕΔͷʁ ஗͍

Slide 146

Slide 146 text

ͦΕͬͯݱ࣮తʁ ௐࠪ݁Ռ 1VTI"1*ͬͯΈΜͳͲΕ͘Β͍Ͱฦͯ͘͠ΕΔͷʁ Ԡ౴଎౓ʢฏۉʣ <ඵ> Ұ൪ૣ͔ͬͨԠ౴ʢฏۉʣ <ඵ> Ұ൪஗͔ͬͨԠ౴ʢฏۉʣ <ඵ> Ԡ౴཰ʢฏۉʣ <>

Slide 147

Slide 147 text

1VTIͰͲͷ͘Β͍ૹ৴Ͱ͖Δ ͬͪ͜ͷλΠϓͳΒ ,#ҎԼʹͳΔ·Ͱ෼ׂͨ͠Βཧ࿦্͸͍͚Δ

Slide 148

Slide 148 text

1VTIͰͲͷ͘Β͍ૹ৴Ͱ͖Δ ͬͪ͜ͷλΠϓ͸αʔόʔʹ͚͋ͣͯɺ ࡏΓॲΛڭ͑Δͱ͔͠ͳ͍ͱ͍͚ͳ͍ ͜͜ʹૹͬͨΑ Cc2H5BfqPf+L/Z Cc2H5BfqPf+L/Z ͜͜ʹૹͬͨΑ Cc2H5BfqPf+L/Z ͜͜ʹૹͬͨΑ Cc2H5BfqPf+L/Z

Slide 149

Slide 149 text

·ͱΊ 8FCͰͰ͖ΔମݧΛߟ͑Δձ

Slide 150

Slide 150 text

̏ͭͷδϟϯϧʹ෼͚ͯ 8FC"1*ͷ࢖͍ํΛ঺հ ૊Έ߹Θͤͯ࢖͏ͱ໘ന͍Αͱ͍͏࿩Λఴ͑ͯ 8FC8PSLFS 8FC"TTFNCMZ 1VTI"1* 8FC(- UISFFKT 8FC"VEJP"1* ͳʹ͔໘ന͍͜ͱͷ͖͔͚ͬʹͳͬͯ͘ΕΔͱྑ͍Ͱ͢

Slide 151

Slide 151 text

ંݪ ϨΦφϧυݡ !-FPOBSEP@FOHS ϑϩϯτΤϯυΤϯδχΞɺͨ·ʹ69σβΠφʔ LINE 株式会社 UIT 室 User Interface + Technology team @LINE corp

Slide 152

Slide 152 text

͋Γ͕ͱ͏͍͟͝·ͨ͠