如何自定义浏览器webpush通知主体&图标?

时间:2017-04-26 12:08:09

标签: javascript jquery ruby-on-rails push-notification service-worker

我们如何根据iconbody动态定制浏览器通知@challenge.image@challenge.description

enter image description here

点击webpush-button,我收到了弹出通知,但只有消息的title动态更改。如何才能使其适用于bodyicon

挑战/ show.html.erb

<script>
  $('.webpush-button').on('click', (e) => {
    navigator.serviceWorker.ready
    .then((serviceWorkerRegistration) => {
      serviceWorkerRegistration.pushManager.getSubscription()
      .then((subscription) => {
        $.post('/push', {
          subscription: subscription.toJSON(),
          message: "<%= @challenge.name %>", # This works dynamically for the title, but how can I get message to also dynamically send body and icon so I can use <%= @challenge.image %> for icon and <%= @challenge.description %> for body?
        });
      });
    });
  });
</script>

push_notifications_controller

class PushNotificationsController < ApplicationController
  def push
    Webpush.payload_send(
      message: params[:message],
      endpoint: params[:subscription][:endpoint],
      p256dh: params[:subscription][:keys][:p256dh],
      auth: params[:subscription][:keys][:auth],
      vapid: {
        subject: "mailto:sender@example.com",
        public_key: ENV['VAPID_PUBLIC_KEY'],
        private_key: ENV['VAPID_PRIVATE_KEY']
      }
    )
  end
end

的application.js

  if (navigator.serviceWorker) {
    navigator.serviceWorker.register('/serviceworker.js')
    .then(function(reg) {
       console.log('Service worker change, registered the service worker');
    });
  }
  // Otherwise, no push notifications :(
  else {
    console.error('Service worker is not supported in this browser');
  }

  // When serviceWorker is supported, installed, and activated,
  // subscribe the pushManager property with the vapidPublicKey
  navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
    serviceWorkerRegistration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: window.vapidPublicKey
    });
  });

  // Let's check if the browser supports notifications
  if (!("Notification" in window)) {
    console.error("This browser does not support desktop notification");
  }

  // Let's check whether notification permissions have already been granted
  else if (Notification.permission === "granted") {
    console.log("Permission to receive notifications has been granted");
  }

  // Otherwise, we need to ask the user for permission
  else if (Notification.permission !== 'denied') {
    Notification.requestPermission(function (permission) {
    // If the user accepts, let's create a notification
      if (permission === "granted") {
        console.log("Permission to receive notifications has been granted");
      }
    });
  }

serviceworker.js.erb

console.log('[Service Worker] Hello world!');

var CACHE_VERSION = 'v1';
var CACHE_NAME = CACHE_VERSION + ':sw-cache-';

function onInstall(event) {
  console.log('[Serviceworker]', "Installing!", event);
  event.waitUntil(
    caches.open(CACHE_NAME).then(function prefill(cache) {
      return cache.addAll([

        // make sure serviceworker.js is not required by application.js
        // if you want to reference application.js from here
        '<%#= asset_path "application.js" %>',

        '<%= asset_path "application.css" %>',

        '/offline.html',

      ]);
    })
  );
}

function onActivate(event) {
  console.log('[Serviceworker]', "Activating!", event);
  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);
        })
      );
    })
  );
}

// Borrowed from https://github.com/TalAter/UpUp
function onFetch(event) {
  event.respondWith(
    // try to return untouched request from network first
    fetch(event.request).catch(function() {
      // if it fails, try to return request from the cache
      return caches.match(event.request).then(function(response) {
        if (response) {
          return response;
        }
        // if not found in cache, return default offline content for navigate requests
        if (event.request.mode === 'navigate' ||
          (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
          console.log('[Serviceworker]', "Fetching offline content", event);
          return caches.match('/offline.html');
        }
      })
    })
  );
}

self.addEventListener("push", (event) => {
  let title = (event.data && event.data.text()) || "Yay a message";
  let body = "We have received a push message";
  let icon = '/assets/default.png';

  event.waitUntil(
    self.registration.showNotification(title, { title,body, icon })
  )
});

self.addEventListener('install', onInstall);
self.addEventListener('activate', onActivate);
self.addEventListener('fetch', onFetch);

serviceworker-companion.js

if (navigator.serviceWorker) {
  navigator.serviceWorker.register('/serviceworker.js', { scope: './' })
    .then(function(reg) {
      console.log('[Companion]', 'Service worker registered!');
    });
}

我通过serviceworker gemwebpush gemVAPID tutorial实施推送。

2 个答案:

答案 0 :(得分:1)

event.data中的self.addEventListener("push", (event)=> {...})对象有一个方法json(),该方法将event.data值转换为json。

仅当发送的数据采用正确的json格式时,此功能才有效。

以下是我使用网络推送的示例:

self.addEventListener("push", function onPush(event) {
  var data = event.data.json()
  event.waitUntil(self.registration.showNotification(data.message.title, {
    body: data.message.body,
    icon: data.message.icon,
    actions: [ 
      { action: 'Button one', title: "Button one text" },
      { action: 'Button two', title: "Button two text" }
    ]
  }));
});

以下是来自我的user.rb模型的方法:

 def send_web_push(title: , body: )
    #  the web_push is a payload with I save to the user record,
    #  that's allow me to send web push with background worker. 
    payload = {
      endpoint: web_push['endpoint'], 
      keys: {
        auth: web_push['auth'],
        p256dh: web_push['p256dh'] 
      }
    }
    push = WebPush.new(payload)
    push.set_vapid_details(
      'mailto:support@awesomesupewebapp.com',
      Rails.application.secrets.web_push_public_key,
      Rails.application.secrets.web_push_private_key
    )
    # below is a `:message` key in json format
    push.send_notification({
      message: {
        title: title,                 
        body: body,                  
        icon: "/this_is_my_icon.png" 
      }
    }.to_json)
  end

我为web_push使用了一些其他ruby gem,但我认为它很常见。从该示例中,您应该看到如何更改正文,标题和图标键。

答案 1 :(得分:0)

查看

<%= content_tag(:button, "Foo", class: "webpush-button") %>

<script>
  $('.webpush-button').on('click', (e) => {
    navigator.serviceWorker.ready
    .then((serviceWorkerRegistration) => {
      serviceWorkerRegistration.pushManager.getSubscription()
      .then((subscription) => {
        $.post('/push', {
          subscription: subscription.toJSON(),
          message: "<%= @challenge.name %>", 
          body: "<%= @challenge.why %>",
          icon: "/assets/default.png"
        });
      });
    });
  });
</script>

<强>控制器

class PushNotificationsController < ApplicationController
  def push
    Webpush.payload_send(
      message: JSON.generate({ 
        title: params[:message],
        body: params[:body],
        icon: params[:icon]
        }),
      endpoint: params[:subscription][:endpoint],
      p256dh: params[:subscription][:keys][:p256dh],
      auth: params[:subscription][:keys][:auth],
      vapid: {
        subject: "mailto:sender@example.com",
        public_key: ENV['VAPID_PUBLIC_KEY'],
        private_key: ENV['VAPID_PRIVATE_KEY']
      }
    )
  end
end

<强> JS

self.addEventListener("push", (event) => {
  var data = event.data.json();
  let title = (event.data && data.title) || "Yay a message";
  let body =  (event.data && data.body) || "We have received a push message";
  let icon =  (event.data && data.icon) || "/assets/blue-astronaut.png";

  event.waitUntil(
    self.registration.showNotification(title, { title,body, icon })
  )
});