LoginSignup
6
5

More than 5 years have passed since last update.

イベント通知アプリの作成(firebaseベース)

Last updated at Posted at 2020-07-24

いろいろ試行錯誤しましたが、PWAでのPush通知はちょっと難しいと判断しfirebaseを使っての通知にすることとしました。

動作結果

先に結果から
webにアクセスして通知を許可すると、こんな感じで通知されます。
通知.png

ページを閉じていても通知が届きます(Windows10)
画面右下にこんな感じで通知されます
通知_画面右下.png
通知リストにもこんな感じで出てきます
通知_web画面開いていない時.png

index.html

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>xxxxxxxxxxx Scheduler</title>

    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <link rel="manifest" href="/manifest.json">
    <!-- ios用tag -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-title" content="PWA">
    <link rel="apple-touch-icon" href="./img/app-icon-120x120.png" sizes="120x120">
    <link rel="apple-touch-startup-image" href="./img/zeni_splash.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/siimple@3.1.1/dist/siimple.min.css" />
    <link href="https://fonts.googleapis.com/css?family=Poiret+One" rel="stylesheet">
    <link type="text/css" rel="stylesheet" href="./css/bigapple.css">

    <!-- update the version number as needed -->
    <script defer src="/__/firebase/5.8.3/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="/__/firebase/5.8.3/firebase-auth.js"></script>
    <script defer src="/__/firebase/5.8.3/firebase-database.js"></script>
    <script defer src="/__/firebase/5.8.3/firebase-messaging.js"></script>
    <script defer src="/__/firebase/5.8.3/firebase-storage.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script defer src="/__/firebase/init.js"></script>

    <script type="text/javascript">
      // service workerが有効なら、service-worker.js を登録します
      if ('serviceWorker' in navigator) {
        console.log("service-worker ON");
        navigator.serviceWorker.register('./firebase-messaging-sw.js').then(function() { console.log('Service Worker Registered'); });
     }
    </script>

  </head>
  <body>
    <!-- HEADER -->
  <div class="ens-title-area">
    <div class="ens-title">
      <img class="ens-logo" src="./img/xxxxxxxxxxxxxxx.png" alt="ロゴ"/>
      EVENT NOTICE SERVICE
    </div>
  </div>
  <!-- MAIN CONTENTS -->
  <div class="wrapper">
    <div class="page_title"><p><span>xxxxxxxxxxx Scheduler</span></p></div>
    <div class="bg_wrapper">
      <div class="contents_wrapper">
        <div id="canvas"></div>
        <div class="form_area">
          <div>
            <label for="event_title">イベント名:</label><input type="text" id="event_title">
          </div>
          <div>
            <label for="event_date">イベント日:</label><input type="date" id="event_date">
          </div>
        </div>
        <div id="btn_area" class="btn_area">
          <button class="enable_click" id="get_btn" onclick="">イベント取得</button>
          <button class="enable_click" id="write_btn" onclick="">イベント追加</button>
        </div>
      </div>
    </div>
    <!-- FOOTER -->
    <div class="ens-footer">Copycenter 2018 xxxxx Limited.</div>
  </div>
  <script src="./js/jquery.js"></script>
<script src="./js/firebase.js"></script>
index.html
    <script>
        var config = {
    apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    authDomain: "xxxxxxxxxxxxxxxxxxxxxxx",
    databaseURL: "xxxxxxxxxxxxxxxxxxxxxxxxx",
    projectId: "xxxxxxxxxxxxxx",
    storageBucket: "xxxxxxxxxxxxxxxxxxxxxx",
    messagingSenderId: "xxxxxxxxxxxxxxxxxxx"
  };
  firebase.initializeApp(config);
  // firestoreインスタンスの生成
  var db = firebase.firestore();
  // タイムスタンプの設定を記述
    var setting = { timestampsInSnapshots:true };
    db.settings(setting);

  // メッセージングの初期化
  var messaging = firebase.messaging();
    // 画面表示時の通知
    messaging.onMessage(function(payload) {
    console.log("Message received. ", payload);
    alert(payload.notification.title+"\r\n"
        +payload.notification.body+"\r\n"
        +payload.notification.icon);
  });
$(function(){

//プッシュ通知パーミッション取得
  messaging.requestPermission()
  .then(function() {
    //ユーザー毎のトークンを取得して画面に表示する
    messaging.getToken()
    .then(function(token) {
      console.log('Token refreshed.');
      console.log(token);
      db.collection("tokens").add({
        token: token
      });
      document.getElementById("txtIIToken").value = token;
    })
    .catch(function(err) {
      console.log('Unable to retrieve refreshed token ', err);
    });
  })
  .catch(function(err) {
    console.log('Unable to get permission to notify.', err);
  });

  $("#write_btn").bind("click touchstart", function(){
    // フォームから値を取得
        var event_title = document.getElementById("event_title").value;
        var event_date  = document.getElementById("event_date").value;
        event_date = modEventDate(event_date);

        // 日付を取得
        var now = getNowDate();

        // イベント追加
        addEvent(db, "events", event_title, event_date, now);

        // フォームの初期化
        document.getElementById("event_title").value = "";
        document.getElementById("event_date").value = "";
    db.collection("tokens").get().then(function(querySnapshot) {
            querySnapshot.forEach(function(doc) {
        console.log(doc.get("token"));
        // イベント通知
        $.ajax({
          url:'https://fcm.googleapis.com/fcm/send',
          type:"POST",
          headers:{
            "Authorization":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "Content-Type":"application/json"
          },
          contentType: 'application/json',
          dataType: "json",
          data:JSON.stringify({
            notification: {
              title: "イベント通知", // 通知タイトル
              body: "新しいイベントが追加されました。", // 通知内容
              click_action: "https://xxxxxxxxxxxxxx.firebaseapp.com/", // クリック時の動き
              icon: "./img/icon.png" // 通知アイコン
            },
            to: doc.get("token") // 送信対象
          }),
          success:function(json) {
            console.log("success");
            console.log(json);
          },
          error: function() {},
          complete: function() {}
        });

      });
    });


  });

  // イベント取得クリック時
  $("#get_btn").bind("click touchstart", function(){
    // 初期化
    document.getElementById("canvas").innerHTML = ""

        // イベント全件取得
        db.collection("events").get().then(function(querySnapshot) {
            querySnapshot.forEach(function(doc) {
                document.getElementById("canvas").innerHTML += 
                    doc.get('event_date');;
                document.getElementById("canvas").innerHTML +=
                    doc.get('event_name'); + " <br /> ";
                document.getElementById("canvas").innerHTML += "<hr />";
            });
        });
  });

});

// イベント追加関数
function addEvent(db, doc, name, date, now){
    db.collection(doc).add({
        event_name: name,
        event_date: date,
    });
}
// 日付フォーマット変更処理
function modEventDate(date){
    var result = date.replace("-", "/");
    // "-"が存在する限り繰り返し
    while(result !== date) {
        date = date.replace("-", "/");
        result = result.replace("-", "/");
    }
    //TODO:スマホからだとyyyymdになるためyyyymmddに変換
    //     無理矢理だが今は動けば良いので機会があれば修正する。
    var tmpDate
    tmpDate = new Date(date);
    var yyyy = tmpDate.getFullYear();
    var mm   = ("00" + (tmpDate.getMonth()+1)).slice(-2);
    var dd   = ("00" + tmpDate.getDate()).slice(-2);
    var res  = yyyy + "/" + mm + "/" + dd;
    return res;
}

// 現在時刻の取得関数
function getNowDate(){
    var date = new Date();
    var yyyy = date.getFullYear();
    var mm   = ("00" + (date.getMonth()+1)).slice(-2);
    var dd   = ("00" + date.getDate()).slice(-2);
    var res  = yyyy + "/" + mm + "/" + dd;
    return res;
}
  </script>

firebase-messaging-sw.js

firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/3.7.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.7.0/firebase-messaging.js');

// service-worker.js
self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
});

self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
});


// 現状では、この処理を書かないとService Workerが有効と判定されないようです
self.addEventListener('fetch', function(event) {});


firebase.initializeApp({
    'messagingSenderId': 'xxxxxxxxxxxxxx'
});

// メッセージングの初期化
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
      body: payload.notification.body,
      icon: payload.notification.icon
    };
  return self.registration.showNotification(notificationTitle,notificationOptions);
});

manifest.json

manifest.json
{
  "name": "PWA Sample",
  "short_name": "PWA",
  "background_color": "#fc980c",
  "icons": [
    {
      "src": "./img/BIG_APPLE.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./img/BIG_APPLE_144.png",
      "sizes": "144x144",
      "type": "image/png"
    }
    ],
  "start_url": "https://xxxxxxxxxxxx.firebaseapp.com/",
  "display": "standalone",
  "theme_color": "#2F3BA2",
  "gcm_sender_id": "xxxxxxxxxxxxx" // firebase送信者は固定
}

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5