Last active
October 5, 2018 06:52
-
-
Save shimx/79530bc2da030511d962fac6e4ce2195 to your computer and use it in GitHub Desktop.
Rails4におけるブラウザプッシュ通知(Web Push Notifications)実装 ref: https://qiita.com/shimx/items/d23bb45b34c89f879db3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "WEB APP NAME", | |
"short_name": "WEB APP", | |
"start_url": "/" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var CACHE_VERSION = 'v1'; | |
var CACHE_NAME = CACHE_VERSION + ':sw-cache-'; | |
function onSWInstall(event) { | |
return event.waitUntil( | |
caches.open(CACHE_NAME).then(function prefill(cache) { | |
return cache.addAll([]); | |
}) | |
); | |
} | |
function onSWActivate(event) { | |
return event.waitUntil( | |
caches.keys().then(function(cacheNames) { | |
return Promise.all( | |
cacheNames.filter(function(cacheName) { | |
// Return true if you want to remove this cache, | |
// but remember that caches are shared across | |
// the whole origin | |
return cacheName.indexOf(CACHE_VERSION) !== 0; | |
}).map(function(cacheName) { | |
return caches.delete(cacheName); | |
}) | |
); | |
}) | |
); | |
} | |
function onSWPush(event) { | |
// event.data are null when Firefox's debugger push | |
// event.data are PushMessageData object and cannot exec event.data.json, event.data.text => 'Test push message from DevTools.' | |
var json = event.data ? event.data.json() : {"title" : "DEBUG TITLE", "body" : "DEBUG BODY"}; | |
return event.waitUntil( | |
self.registration.showNotification(json.title, { | |
body: json.body, | |
icon: json.icon, | |
data: { | |
target_url: json.target_url | |
} | |
}) | |
); | |
} | |
function onSWNotificationClick(event) { | |
event.notification.close(); | |
return event.waitUntil( | |
clients.openWindow(event.notification.data != null ? event.notification.data.target_url : '/') | |
); | |
} | |
self.addEventListener('install', onSWInstall); | |
self.addEventListener('activate', onSWActivate); | |
self.addEventListener("push", onSWPush); | |
self.addEventListener("notificationclick", onSWNotificationClick); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// javascript | |
if (Notification.permission == "denied") { | |
console.log('ブロックされています'); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'webpush' | |
payload = { | |
endpoint: @endpoint, # ブラウザでregistration.pushManager.getSubscription()で取得したsubscriptionのendpoint | |
p256dh: @p256dh, # 同じくsubscriptionのp256dh | |
auth: @auth, # 同じくsubscriptionのauth | |
ttl: @ttl, # 任意の値 | |
vapid: { | |
subject: 'mailto:info@example.org', # APPサーバのコンタクト用URIとか('mailto:' もしくは 'https://') | |
public_key: Rails.application.secrets.web_push[:vapid_public_key], | |
private_key: Rails.application.secrets.web_push[:vapid_private_key] | |
}, | |
message: { | |
icon: 'https://example.com/images/demos/icon-512x512.png', | |
title: title, | |
body: body, | |
target_url: target_url # 任意のキー、値 | |
}.to_json | |
} | |
# NOTE: payload_sendの例外 | |
# RuntimeError の場合 Webpush::Error | |
# Error の場合 Webpush::ConfigurationError | |
# Net::HTTPGone 410 の場合 Webpush::InvalidSubscription | |
# Net::HTTPSuccess 2XX 以外の場合 Webpush::ResponseError | |
Webpush.payload_send(payload) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onSWPush(event) { | |
var json = event.data.json(); // payloadのmessage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
navigator.serviceWorker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#<Net::HTTPBadRequest 400 UnauthorizedRegistration readbody=true> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
expiration: 12 * 60 * 60 # defaultは 24 * 60 * 60 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# lib/webpush/request.rb | |
def jwt_payload | |
{ | |
aud: audience, | |
exp: Time.now.to_i + expiration, | |
sub: subject, | |
} | |
end | |
def expiration | |
@vapid_options.fetch(:expiration, 24*60*60) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data: { | |
target_url: json.target_url | |
} | |
function onSWNotificationClick(event) { ... } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Gemfile | |
gem 'serviceworker-rails' | |
gem 'webpush' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'webpush' | |
vapid_key = Webpush.generate_key | |
puts vapid_key.public_key # 公開鍵 | |
puts vapid_key.private_key # 秘密鍵 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
WEB_PUSH_VAPID_PUBLIC_KEY="公開鍵" | |
WEB_PUSH_VAPID_PRIVATE_KEY="秘密鍵" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
web_push: | |
:vapid_public_key: <%= ENV['WEB_PUSH_VAPID_PUBLIC_KEY'] %> | |
:vapid_private_key: <%= ENV['WEB_PUSH_VAPID_PRIVATE_KEY'] %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Rails.application.configure do | |
config.serviceworker.routes.draw do | |
match "/serviceworker-user.js" => "user/serviceworker/serviceworker.js" | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 自身が設置した manifest.json のパスを記述する --> | |
<link rel="manifest" href="/manifest.json"> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WebPushが使えるか | |
var isEnableWebPushBrowser = function() { | |
// SWが使えないブラウザ | |
if (!navigator.serviceWorker) { | |
return false; | |
} | |
var ua = navigator.userAgent.toLowerCase(); | |
// UAにChromeが含まれている為、明示的にEdgeとOpera(Webkit)を弾く | |
if (ua.indexOf("edge") >= 0 || ua.indexOf("opr") >= 0) { | |
return false; | |
} | |
// Chrome 52 以降OK | |
if (ua.match(/chrom(e|ium)/)) { | |
var raw = ua.match(/chrom(e|ium)\/([0-9]+)\./); | |
if (raw && parseInt(raw[2], 10) >= 52) { | |
return true; | |
} | |
} | |
// Firefox 48 以降OK | |
if (ua.indexOf("firefox") >= 0) { | |
var raw = ua.match(/firefox\/([0-9]+)\./); | |
if (raw && parseInt(raw[1], 10) >= 48) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
// WebPushが使えるブラウザの場合 | |
// NOTE: 今回はWebPushだけなので。他でSW使いたかったら要変更 | |
if (isEnableWebPushBrowser()) { | |
var convertWebPushSubscriptionJson = function(subscription) { | |
var jsonData = {}; | |
if (subscription) { | |
jsonData = { | |
endpoint: subscription.endpoint, | |
key: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('p256dh')))).replace(/\+/g, '-').replace(/\//g, '_'), | |
auth: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('auth')))).replace(/\+/g, '-').replace(/\//g, '_') | |
}; | |
} | |
return jsonData; | |
}; | |
// ブラウザPush通知を有効にする | |
var webPushSubscribe = function() { | |
return navigator.serviceWorker.getRegistration().then(function(registration) { | |
// ブラウザPush通知用VAPID | |
var vapidPublicKey = new Uint8Array(<%= Base64.urlsafe_decode64(Rails.application.secrets.web_push[:vapid_public_key]).bytes %>); | |
return registration.pushManager.subscribe({ | |
userVisibleOnly: true, | |
applicationServerKey: vapidPublicKey | |
}).then(function(subscription) { | |
// API叩いてDBに登録するなどの処理 | |
console.log(convertWebPushSubscriptionJson(subscription)); | |
return; | |
})["catch"](function(err) { | |
return console.log(err); | |
}); | |
}); | |
}; | |
// ブラウザPush通知を無効にする | |
var webPushUnSubscribe = function() { | |
return navigator.serviceWorker.getRegistration().then(function(registration) { | |
return registration.pushManager.getSubscription().then(function(subscription) { | |
if (!subscription) { | |
return; | |
} | |
return subscription.unsubscribe().then(function(success) { | |
// API叩いて無効にするなどの処理 | |
return; | |
})["catch"](function(error) { | |
return console.log(error); | |
}); | |
}); | |
}); | |
}; | |
// SWインストール | |
// NOTE: SWインストール済みかどうかはブラウザ側で判断される | |
navigator.serviceWorker.register('/serviceworker-user.js', { scope: '/' }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment