• 虹色ミツバチ
  • freoカスタマイズメモ、テンプレート・プラグイン配布/officeTIPS
検索プラグイン

> Entry

PWAでプッシュ通知を実装してみる(4)実際にプッシュ通知を送信・受信する

前回までの記事では、プッシュ通知に必要なトークンを閲覧者に発行させ、購読状況とともにデータベースに記録させるところまでやりました。
今回からはデータベースに登録させた情報を元に、実際にプッシュ通知を送信・受信できるところまでやってみます。

Firebase Cloud Messaging でプッシュ通知を受信する

Google Firebase Cloud Messaging(FCM)でプッシュ通知許可時・購読時に発行されるトークン処理については前回までの記事で解説しているので、今回は受信・送信機能部分を解説します。

PWA化されたサイトでプッシュ通知を受信するにはserviceworker.jsへの記載が必要ですが、FCMを利用する時は、serviceworkerの名前をfirebase-messaging-sw.jsにする必要があります。
既にserviceworkerを利用している場合、serviceworkerの記述をfirebase-messaging-sw.jsに統合する必要があります。

複数のserviceworkerを設置する方法はなくはないようですが、分散させるよりは統合した方が処理が散漫にならず良いと思います。

キャッシュ機能についてのserviceworkerの記載は既に解説していますが、それに追加するプッシュ通知受信に関する記載は下記の通りです。

// Firebase利用準備
importScripts('https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/6.2.0/firebase-messaging.js');
firebase.initializeApp({
    'messagingSenderId': 'YOUR-SEND-ID'
});
const messaging = firebase.messaging();

// フォアグラウンドでのプッシュ通知受信
messaging.onMessage(function(payload) {
    var notificationTitle = payload.data.title; // タイトル
    var notificationOptions = {
      body: payload.data.body, // 本文
      icon: '/pwa_512.png', // アイコン
      click_action: 'https://xxxx.sample.com/' // 飛び先URL
    };

    if (!("Notification" in window)) {
        // ブラウザが通知機能に対応しているかを判定
    } else if (Notification.permission === "granted") {
        // 通知許可されていたら通知する
        var notification = new Notification(notificationTitle,notificationOptions);
    }
});

// バックグラウンドでのプッシュ通知受信
messaging.setBackgroundMessageHandler(function(payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', payload);
    // Customize notification here
    var notificationTitle = payload.notification.title; // タイトル
    var notificationOptions = {
            body: payload.notification.body, // 本文
            icon: payload.notification.icon, // アイコン
    };

    return self.registration.showNotification(notificationTitle,
    notificationOptions);
});

送信された通知の内容はjson形式で受け取ります。
受け取ったjsonをプッシュ通知に変換してブラウザの状態にあわせて表示します。

参考URL

Firebase ドキュメント:JavaScript クライアントでメッセージを受信する

プッシュ通知受信テスト

Google Chromeを使えば、プッシュ通知の受信テストができます。

Firebase Cloud Messaging でプッシュ通知を送信する

プッシュ通知を受信する準備ができても、肝心の送信手続きについては全くの未知数でした。
いろんなサイトを見ても、「サーバーからcURLコマンドを叩けばおk」とかしか書いてなくて、「サーバーってなんだ? サイトを置いてあるWEBサーバーのこと??」とか「cURLってなんだよ」「どうやって叩くのよ」とかいろんな疑問点が噴出していました。

プッシュ通知を送信するためにしたいこと

プッシュ通知を送信するためにしたいことをまとめておきます。

  1. データベースに登録されたトークンをトピックに紐付ける
  2. 通知メッセージの内容は送信する度に変更する
  3. 通知は自動で送信するのではなく通知したいタイミングで手動で送信する

トピックメッセージング(トピック)とは、Firebase Cloud Messagingの機能で複数のトークンに対し一括で通知メッセージを送信する仕組みです。
同じような機能でデバイスグループメッセージングという機能がありますが、こちらはさまざまなスマートフォンモデルに応じて異なるメッセージを送信する場合に使用するものです。

今回はデバイスに応じた処理を行う予定はないので、トピックを利用することにします。

参考URL

Firebase ドキュメント:複数のデバイスにメッセージを送信する
Firebase ドキュメント:ウェブ / JavaScript でデバイス グループにメッセージを送信する

プッシュ通知の送信機能はアプリサーバーに持たせる

当初は、まさに素人考えですが、プッシュ通知を送信するためのPHPなりなんなりをWEB上に上げて、もしくはサイトに組み込んで、そこからプッシュ通知を送信できればベストだなと思っていました。
しかし、Firebase ドキュメントを読むとサーバーキーの機密性を維持するため、プッシュ通知の送信やトピックへの登録などのリクエストをクライアントから送信しないようにと書いてありました。

プッシュ通知の送信に必要なサーバーキー・トークン一覧などを誰でも閲覧可能にすると、たしかに悪意のあるユーザーから偽装されたプッシュ通知を送信される可能性があります。
よって、プッシュ通知はアプリサーバーから送信することにしました。

アプリサーバーといっても、

送信ロジック(認証、送信リクエストの作成、応答の処理などを行うロジック)を作成するために、Admin SDK を使用するか、またはサーバー プロトコルの 1 つを使用するかを決定します。次に、信頼できる環境でロジックを構築します。クライアント アプリケーションからのアップストリーム メッセージングを使用する場合には、XMPP を使用する必要があります。XMPP で必要となる永続的な接続が Cloud Functions ではサポートされないことに注意してください。
Firebase ドキュメント:Firebase Cloud Messaging

ということなので、コマンドプロンプトNode.jsをインストールしてFirebase Admin SDKを利用することにします。

Firebase Admin SDKを利用するにはNode.jsだけではなくJAVA・Python・Go・C#でもOKなようですが、Node.jsが一番なんでもできそうだったのでNode.jsにしました。

参考URL

Firebase ドキュメント:サーバーに Firebase Admin SDK を追加する

コマンドプロンプトにNode.jsをインストールする

そもそもNode.jsってなにかっていうと、サーバーでJavaScriptを利用できるようにするためのもののようです。
FirebaseはJavaScriptで構成されているので、サーバーでNode.jsが必要だというのもうなずけます。

参考URL

エンジニアの入り口:初心者向け!3分で理解するNode.jsとは何か?
Qiita:Windows版 Node.js環境構築方法まとめ

Node.jsのインストールされたコマンドプロンプトにFirebase Admin SDKを追加する
  1. Windowsでサーバーアプリとして利用するディレクトリをどこかに作っておく。
    例えば[C:\webpush]など適当でいいと思います。
  2. Node.js command promptを起動して[1]で作成したディレクトリに移動する。
  3. 下記コマンドを実行する
    $ npm install firebase-admin --save
    
  4. コマンドプロンプトが色々頑張ってこんな感じの画面になる
    2019080601.jpg
  5. [1]で作成したディレクトリを見に行くと、なんかファイルが出来ている
    2019080602.jpg
  6. firebaseのコンソールから[設定]>[サービスアカウント]を開く
  7. [新しい秘密鍵の生成]をクリックする
    2019080603.jpg
  8. [キーを生成]をクリックする
    2019080603.jpg
  9. 秘密鍵ファイルのDLが開始するので[1]とは別のディレクトリに保存する。
    別に[1]と同じでもいいけど、要は公開されないようにすればOK。
    [1]をリポジトリにしてGitで管理する場合などは公開されないように注意すること。
    2019080605.jpg

生成した秘密鍵への紐付けは、コード内に記載して行うこともできます(自分は今回そうしています)が、システムの環境変数を設定する方法もあります。
環境変数を設定したほうが安全ですが、複数のプロジェクトを扱う場合、新しいセッションを開く場合はセッションを再度設定しなければなりません。
環境変数[GOOGLE_APPLICATION_CREDENTIALS]への設定方法は下記Firebaseドキュメントを参考にしてください。

Firebase ドキュメント:サーバーに Firebase Admin SDK を追加する-SDKの追加
Firebase ドキュメント:サーバーに Firebase Admin SDK を追加する-SDK の初期化

プッシュ通知送信処理用のJS

Firebase Admin SDK のインストールが終わったら、これを使ってサーバー側でのプッシュ通知送信処理を作成します。
今回はJavaScriptで作成しました。
下記にサンプルを用意したので、[send-push.js]などのように名前をつけて、Firebase Admin SDKをインストールしたフォルダに保存してください。

// 設定
var admin = require("firebase-admin");
var serviceAccount = require("./YOUR-SERVICE-ACCOUNT.json");//Admin SDK利用のため作成した秘密鍵の場所

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://XXXXXXXXXXXXXXXXXXXXXXXXXX.firebaseio.com"//[Firebaseコンソール→設定→サービスアカウント]で確認できるデータベースのURL
});

// 宛先のトピックを指定
var topic = 'XXXXXX';

var db = admin.firestore();

// DBから取得したトークンを配列に格納
db.collection('users').get()
.then((snapshot) => {
    const entryTokens = [];
    const removeTokens = [];
    snapshot.forEach((doc) => {
        var data = doc.data();
        if(data.subscribe == true){
            entryTokens.push(data.token);
        } else {
            removeTokens.push(data.token);
        }
        
    });

// トピック購読処理
    admin.messaging().subscribeToTopic(entryTokens, topic)
    .then(function(response) {
        // See the MessagingTopicManagementResponse reference documentation
        // for the contents of response.
        console.log('Successfully subscribed to topic:', response);
    })
    .catch(function(error) {
        console.log('Error subscribing to topic:', error);
    });
// トピック購読解除
    admin.messaging().unsubscribeFromTopic(removeTokens, topic)
    .then(function(response) {
        // See the MessagingTopicManagementResponse reference documentation
        // for the contents of response.
        console.log('Successfully unsubscribed to topic:', response);
    })
    .catch(function(error) {
        console.log('Error subscribing to topic:', error);
    });
})
.catch((err) => {
  console.log('Error getting documents', err);
});

// 通知を定義
var message = {
  topic: topic,
  webpush: {
    notification: {
      title: "タイトル",
      body: "通知メッセージ",
      requireInteraction: "true",
      badge: "https://YOUR-DOMAIN/pwa_512.png",
      icon: "https://YOUR-DOMAIN/pwa_512.png",
    },
    fcm_options: {
      link: "https://YOUR-DOMAIN/"
    }
  }
};

// 通知を送る
admin.messaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

変更箇所はいくつかあります。

最初の設定部分は、[firebaseコンソール>設定>サービスアカウント]でも確認できます。
Admin SDK利用のため作成した秘密鍵の場所を明示しておいてください。

送信先トピック名はなんでも構いません。
わかりやすいものを設定しましょう。

Usersテーブルから登録済みトークン一覧を取得し、WEB通知の購読状況に応じてトピックを購読したり削除したりします。

最新のトピック購読者リストが更新できたら、通知を送信します。
通知内容はここで編集します。
fcm_optionsの[link]は通知をクリックした時の飛び先URLです。
受信時のserviceworker側でなく、送信時に色々設定出来たほうがよいと思います。

最後の部分でプッシュ通知を送信します。

ワンポイント

ウェブアプリの場合トピックや送信処理をFirebaseコンソールで操作できない

色々調べたところ、Firebaseコンソールでトピックの登録についてやプッシュ通知の送信自体を操作できるようなことが書いてあったのですが、それはAndroidやiOSだけの話で、どうやらウェブアプリではCloud Messagingのコンソールが利用できないようです。
残念。将来的にできるようになることを期待したいです。

参考URL

Firebase ドキュメント:ウェブや JavaScript でメッセージをトピックに送信する

プッシュ通知の送信を行う

ようやくプッシュ通知の送信を行います。
上記作成した[send-push.js]をNode.jsで実行します。

  1. Node.js command promptを起動する
  2. [push.js]が保存されているフォルダに移動する。
  3. 下記コマンドを実行する
    node send-push.js
    
  4. プッシュ通知送信結果が表示される。
    2019080606.jpg

以上でプッシュ通知の送信作業は完了です。
お疲れさまでした。

2019080607.jpg

最後に

いかがでしたでしょうか。プッシュ通知をPWAでできるようになったことで、様々なサイトでオリジナルの通知を送信できるようになりました。
購読処理の設定を変更して好きなテーマについてのみ通知を受け取れるようにしたり、アプリサーバーの送信処理を変更して時間を指定して通知を送ったりすることもできるようになりそうです。

初心者が初心者なりになんとか実現にこぎつけただけのメモですので、もっといい方法なりやり方があれば教えてください。

続きを読む

ユーザー認証プラグイン

ログイン済でないユーザーがサイトにアクセスした時にログイン画面にリダイレクトするプラグインです。

ダウンロード

導入方法

  1. 上記ファイルをDLして解凍する。[freo]フォルダに[configs][libs]フォルダをアップロードする
  2. [freo]フォルダに[configs][libs]フォルダをアップロードする。
  3. [管理画面→システム→設定管理→プラグインの設定→ユーザー認証プラグイン]にアクセスし、設定値を「ブロックする」に変更する

カスタマイズ方法

本プラグインは、

  • freo/index.php/admin
  • freo/index.php/regist
  • freo/index.php/reissue
  • freo/index.php/login


以外の画面にアクセスした閲覧者がログイン済かどうか診断し、ログインしていなかった場合は[freo/index.php/login]にリダイレクトします。

トップページだけは全閲覧者に見せたい場合、たとえばトップページはログイン済みでないユーザーにも見せる場合、[freo/libs/plugins/freo/config.user_auth.php]の19行目を

    define('FREO_PLUGIN_USER_AUTH_UNLOAD_INIT', 'admin,reissue,regist,login,default');

に変更してください。

更新履歴

2019/07/30
配布開始

続きを読む

PWAでプッシュ通知を実装してみる(3)Firebaseでプッシュ通知に必要なトークンを処理する

前回までの記事で、PWA化にはmagnifest.jsonとserviceworker.jsが必要と解説し、そのサンプルを掲載しました。
今回からは目標だったプッシュ通知について解説します。

プッシュ通知の仕組みとFirebaseを利用することにした経緯

PWAを使ったプッシュ通知では、ブラウザで「プッシュ通知を受け取る」設定をした時に、「トークン」が発行されます。
これはブラウザ単位で発行されるので、PCのGoogle ChromeとスマホのAndroidでは別々のトークンが発行されます。

この「トークン」に対して、PWAを利用したサイト(ウェブアプリ)の管理者がサーバーからCurlコマンドを叩くことでプッシュ通知を送信します。
すなわち、「トークン」をどこかに保存しておく必要がありそうです。

トークンを取得したとしても、プッシュ通知を1件1件送っていくのは時間がかかりそうな気がします。
このサイトのような個人ブログであれば問題はないかもしれませんが、アクセスが多くプッシュ通知の購読者数も多いようなサイトの場合、受信者のタイムラグを減らす意味でも、複数人に一度にプッシュ通知を送信できる仕組みがほしいと感じます。

よって、今回はGoogle Firebase Cloud Messaging(FCM)を使用することにしました。
FCMでは、トークンをトピックというグループに関連付け、そのグループに対してプッシュ通知を送ることで、複数人に対し一度にプッシュ通知を送ることができます。
トークンの取得・トピックへの紐付け・プッシュ通知の受信・送信を、FCMと同じくFirebaseの簡易型データベースであるCloud Firestoreで実装します。

ワンポイント

トークンだけでなく、端末のUAや名前・メールアドレスなど、トークン以外のユーザー情報を取得しているサイトの場合は、データベースのユーザーテーブルにトークンのフィールドを増やすなり、プッシュ通知用のテーブルにユーザー情報を紐付けるなりしてください。
今回は通知を購読すると設定した全てのユーザー向けに通知を送ることを想定しています。
端末ごとに通知を送りたい、年齢ごとに送りたいなど、細かな設定が必要な場合はトークン以外のユーザー情報を取得して保存する別の仕組みが必要になるでしょう。

今回実装したプッシュ通知の概要

一番最初の記事で書いていますが、今回実装したプッシュ通知は、

  • アプリが起動されている状態で
  • ブラウザでプッシュ通知が許可されていて
  • プッシュ通知を受け取る設定になっている時

に受け取ることができるものです。

PWA化したサイトはPC・スマホにインストールすることが可能ですが、アプリを起動していない時にプッシュ通知を受信することはできません
起動していない時にまでプッシュ通知を受け取るのはそれはそれでうざったいという判断もできると思うので、現状は上記の状況で満足しています。

なお、アプリは起動してあるけれど別のアプリを使用している(アプリがバッググラウンドにある)場合は受信可能です。

プッシュ通知実装のためにFirebaseを利用する

プッシュ通知の受信・発信のために、今回は Google Firebase を利用しました。
Firebaseはウェブアプリ・ネイティブアプリのバックグラウンドで行われる様々な機能を担うサービスです。
プッシュ通知の送受信・SNSアカウントとの連携・データベースなど、多種多様な機能を利用することができます。

Firebase にプロジェクトを作成する

Firebaseの各種機能を利用するには、まずはFirebaseにログインし、プロジェクトを作成します。
Gmailアドレスが必要です。

  1. Gmailにログインした状態でFirebaseのコンソールにアクセスする。
  2. 「使ってみる」をクリックする
    20190730-01-01.jpg
  3. 「プロジェクトを作成」をクリックする
    20190730-01-02.jpg
  4. プロジェクト名などを入力して「プロジェクトを作成」をクリックする
    20190730-01-03.jpg
  5. プロジェクトが作成できたら「次へ」をクリックする
    20190730-01-04.jpg
  6. プロジェクト作成完了です。お疲れさまでした。
    20190730-01-05.jpg
Firebase のプロジェクトにアプリを設定する

Firebaseでプロジェクトを作成したら、WEBアプリ(サイト)を設定します。

  1. Firebaseコンソールで「</>」マークをクリックしてWEBアプリを登録します。
    20190730-02-01.jpg
  2. サイト名を入力し、「アプリを登録」をクリックする
    20190730-02-02.jpg
  3. サイトに埋め込むためのFirebase SDKが発行されるのでメモしておく。
    なお、このソースは後から編集するので今すぐ<body>タグ下部に埋め込まなくてOK。
    また、もしメモに失敗しても必要な情報はコンソールから確認することもできる。
    20190730-02-03.jpg
    メモが済んだら「コンソールに進む」をクリックする。
  4. コンソールの左側メニュー「Project Overview」の右にある歯車アイコンをクリックし、「プロジェクトの設定」を選択する。
    20190730-02-04.jpg
  5. 「プロジェクトの設定」の「全般」タブでアプリ情報を確認できる。
    また、同画面下部に(3)でメモしたFirebase SDKも随時確認できる。
    20190730-02-05.jpg

VAPID鍵を設定する

FCMでは「Voluntary Application Server Identification 鍵(VAPID 鍵)」と呼ばれるウェブ認証情報を利用して、ウェブプッシュ サービスへの送信要求が承認されます。
プッシュ通知を利用するには、VAPID鍵ペアをFirebaseプロジェクトに関連付ける必要があります。

  1. Firebaseコンソールからプロジェクトの設定→[クラウドメッセージング]をクリックし、ウェブ設定で「鍵ペアを生成」をクリックする。
    20190730-03-01.jpg
  2. 鍵が生成されるので、今後説明するfirebase.js内でCloud Messaging 利用時に鍵を利用する。
    20190730-03-02.jpg

Firestoreでusersテーブルを作成する

Cloud Firestore は Firebase で使用できる簡易的なデータベースです。
ここではトークンと購読状況を保存するだけの極シンプルなテーブルの作成方法を記載します。

  1. Firebaseコンソールから「開発」→「Database」をクリックする
    20190730-05-01.jpg
  2. 「データベースの作成」をクリックする
    20190730-05-02.jpg
  3. データベース作成用ダイアログが表示されるので、「テストモードで開始」を選択して「次へ」
    20190730-05-03.jpg
  4. ロケーションを設定する。多分どこでもいいとは思うけどなんとなく[asia-east2]を選んでみた。
    20190730-05-04.jpg
  5. 作成されたデータベースが表示される(少々時間がかかるのでおとなしく待つ)
    「コレクションを開始」をクリックする
    20190730-05-06.jpg
  6. コレクション作成ダイアログが表示される
    今回は[users]という名前のコレクションにデータを入れていくので、[users]と入力して「次へ」をクリックする
    20190730-05-07.jpg
  7. [users]コレクションに最初に入れるデータを挿入できる
    ドキュメントID部分で「自動ID」をクリックする
    20190730-05-08.jpg
  8. 自動に採番されたIDがドキュメントID部分に挿入される
    [subscribe]フィールドを[boolean]タイプで「true」に、[token]フィールドを[string]タイプで[適当になんか入れて]作成する
    20190730-05-09.jpg
  9. 挿入したデータが登録されていることを確認する
    20190730-05-10.jpg

Firestoreは、簡易型データベースです。
今回は[users]というテーブル(コレクション)に自動付与されたIDをキー(ドキュメント)にして[subscribe:true, token:任意の文字列]という配列を入れてみました。

このようにコンソールから直接登録値を挿入・編集・削除できますし、サイト(Webアプリ)側から内容を参照・編集することもできます。

参考サイト

Firebaseドキュメント:Cloud Firestore
Firebaseドキュメント:Cloud Firestore データモデル

 

では、実際にサイトでFirebaseを利用する準備をしてみます。

headタグにFirebase SDKを挿入する

サイトでFirebaseを利用するために、headタグにFirebase SDKを挿入します。
Firebaseコンソールでは基本的なスニペットしか取得できませんが、Firebaseの各種機能を使うために、それぞれのライブラリを追加で読み込む必要があります。

例えば、今回はCloud Messaging と Firebase Firestore を利用するので、Cloud Messaging と Firebase Firestore用の ライブラリを追加します。

そのため、headタグには

<script defer src="https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js"></script>
<script defer src="https://www.gstatic.com/firebasejs/6.2.0/firebase-messaging.js"></script>
<script defer src="https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js"></script>
<script defer src="/firebase.js"></script>

のように記載します。

firebase-app.jsがfirebaseを利用するための基本ライブラリです。
firebase-messaging.jsとfirebase-firestore.jsはCloud MessagingとFirebase Firestore用のライブラリです。
個人的にheadタグに色々書き加えていくのが嫌なタイプなので、firebaseを利用する部分の記述はfirebase.jsにまとめ、それを読み込む形にします。

firebase.jsの中身はこんな感じです。

// Firebase設定
var firebaseConfig = {
    apiKey: "YOUR-API-KEY",
    authDomain: "project-XXXXXXXXXX.firebaseapp.com",
    databaseURL: "https://project-XXXXXXXXXX.firebaseio.com",
    projectId: "project-XXXXXXXXXX",
    storageBucket: "project-XXXXXXXXXX.appspot.com",
    messagingSenderId: "YOUR-MESSAGING-SENDER-ID",
    appId: "YOUR-API-ID"
};
firebase.initializeApp(firebaseConfig);

// FCM使用準備
const messaging = firebase.messaging();
messaging.usePublicVapidKey('XXXXXXXXXXXXXXXXXXXXXXXXXX');// VAPIDを設定

// Firestore使用準備
var db = firebase.firestore();
var usersRef = db.collection("users");

メモしたFirebase SDKまたはFirebaseコンソールのプロジェクトの設定→全般タブにFirebase SDKスニペットが記載されているので、そこからconfig設定部分を記載しています。
前回の記事で解説したPWA用のmagnifest.jsonではgcm_sender_idをCloud Messagingを利用するための固定値を挿入しましたが、firebase.jsの[messagingSenderId]はプロジェクト固有のIDを挿入してください。

FCM及びFirestoreを使用するための記載を加えています。
VAPID部分は自分で取得したVAPIDに変更してください。

参考URL

Firebaseドキュメント:FirebaseをJavaScriptプロジェクトに追加する

プッシュ通知購読処理のための領域をサイト内に用意する

当サイトのプッシュ通知は、「プッシュ通知を受信する」とブラウザで設定すれば即購読開始となるものではなく、プッシュ通知購読処理及び購読状況の表示領域をサイト内に用意しており、そのブロックで購読開始・購読終了の手続きを行うことができるようにしました。
プッシュ通知の購読は、「購読する」ボタンの押下をもって行い、プッシュ通知購読の終了は「購読終了する」ボタンの押下をもって行うものとします。

bodyタグ内に例えば下記のように記載してください。

<div id="notification">
    <h3>NOTIFICATION</h3>
    <p>当サイトの更新をプッシュ通知で受け取ることができます。</p>
    <p class="notice"></p>
    <button id="EntryButton" onclick="getSubscription()">プッシュ通知を受け取る</button>
    <button id="RemoveButton" onclick="removeSubscription()">プッシュ通知を解除する</button>
</div>

p.noticeは空でOKです。
プッシュ通知を受け取るボタン・解除するボタンが押下された時、処理結果を表示するための段落です。

getSubscription()は購読処理、removeSubscription()は購読解除処理ですが、こちらの内容は今後firebase.jsに記載していきます。

当サイトでは下画像のようにサブメニューにプッシュ通知用のブロックを設置しています。

20190730-04-01.jpg

プッシュ通知の購読開始・購読解除処理

ここまでの準備が整ったら、プッシュ通知の購読開始・購読解除を行えるようにjsに処理を書き込みます。
firebase.jsに下記のように加筆してください。

// 購読確認を行う
checkSubscription();

// 購読確認処理
function checkSubscription() {
    //通知の承認を確認
    messaging.requestPermission().then(function() {
        //トークンを確認
        messaging.getToken().then(function(token) {
            //トークン発行
            if (token) {
                //トークンがDBに入っているか確認
                usersRef.where('token', '==', token).get().then(function(oldLog){
                    if(oldLog.empty){
                    //入っていなければ購読ボタン表示
                        console.log('トークンは登録されていません。');
                        $('#notification p.caution').text('通知を購読していません。');
                        ShowEntryButton();
                    } else {
                    //入っていれば購読状況確認
                        console.log('トークンはすでに登録されています。');
                        oldLog.forEach(function(doc){
                            var data = doc.data();
                            if(data.subscribe == true){
                            //購読している(=停止ボタン表示)
                                $('#notification p.caution').text('通知を購読しています。');
                                ShowRemoveButton();
                            } else {
                            //購読していない(=開始ボタン表示)
                                $('#notification p.caution').text('購読を解除しました。');
                                ShowEntryButton();
                            }
                        });
                    }
                });
            } else {
                    console.log('通知の承認が得られませんでした。');
                    $('#notification p.caution').text('購読を開始できませんでした。');
                    ShowEntryButton();
            }
        }).catch(function(err) {
                console.log('トークンを取得できませんでした。', err);
                $('#notification p.caution').text('購読を開始できませんでした。');
                ShowEntryButton();
        });
    }).catch(function (err) {
        //プッシュ通知未対応
            console.log('通知の承認が得られませんでした。', err);
            $('#notification p.caution').text('プッシュ通知が許可されていません。ブラウザの設定を確認してください。');
            ShowEntryButton();
    });
}

// 購読処理
function getSubscription() {
    //通知の承認を確認
  messaging.requestPermission().then(function() {
        //トークンを確認
        messaging.getToken().then(function(token) {
            //トークン発行
            if (token) {
                //トークンがDBに入っているか確認
                usersRef.where('token', '==', token).get().then(function(oldLog){
                    if(oldLog.empty){
                    //トークン登録がなければトークン登録・購読設定
                        usersRef.add({
                            token: token,
                            subscribe: true
                        });
                        console.log('トークン新規登録しました。');
                    } else {
                    //トークン登録があれば購読に設定変更
                        oldLog.forEach(function(doc){
                            console.log('トークンはすでに登録されています。');
                            usersRef.doc(doc.id).update({
                                subscribe: true
                            })
                        });
                    }
                    //購読解除ボタン表示
                    ShowRemoveButton();
                });
                //購読状況表示更新
                $('#notification p.caution').text('通知を購読しています。');
            } else {
                console.log('通知の承認が得られませんでした。');
                $('#notification p.caution').text('購読を開始できませんでした。');
                ShowEntryButton();
            }
        }).catch(function(err) {
            console.log('トークンを取得できませんでした。', err);
            $('#notification p.caution').text('購読を開始できませんでした。');
            ShowEntryButton();
        });
  }).catch(function (err) {
        console.log('通知の承認が得られませんでした。', err);
        $('#notification p.caution').text('プッシュ通知が許可されていません。ブラウザの設定を確認してください。');
        ShowEntryButton();
    });
}

// 購読解除処理
function removeSubscription() {
    //通知の承認を確認
    messaging.requestPermission().then(function() {
        //トークンを確認
        messaging.getToken().then(function(token) {
            //トークン発行
            if (token) {
                //トークンがDBに入っているか確認
                usersRef.where('token', '==', token).get().then(function(oldLog){
                    if(oldLog.empty){
                    //トークン登録がなければ購読ボタン表示
                        console.log('トークンは登録されていません。');
                        ShowEntryButton();
                    } else {
                    //トークン登録があれば購読解除を行う
                        oldLog.forEach(function(doc){
                            usersRef.doc(doc.id).update({
                                subscribe: false
                            })
                            .then(function() {
                                console.log("購読を解除しました。");
                                ShowEntryButton();
                            }).catch(function(error) {
                                console.error("Error removing document: ", error);
                            });
                        });
                    }
                });
                //購読状況表示更新
                $('#notification p.caution').text('購読を解除しました。');
            } else {
                console.log('トークンを取得できませんでした。');
                $('#notification p.caution').text('購読を開始できませんでした。');
            }
        }).catch(function(err) {
            console.log('トークンを取得できませんでした。', err);
            $('#notification p.caution').text('購読を開始できませんでした。');
        });
    }).catch(function (err) {
        console.log('通知の承認が得られませんでした。', err);
        $('#notification p.caution').text('プッシュ通知が許可されていません。ブラウザの設定を確認してください。');
        ShowEntryButton();
    });
}

// トークン表示
function displayToken() {
  messaging.getToken().then(token => {
        if (token) {
            console.log(token);
        } else {
            console.log('トークンを取得できませんでした。');
        }
  }).catch(function (err) {
    console.log('トークンの取得時にエラーが発生しました。', err);
  });
}


//購読ボタン表示
function ShowEntryButton() {
    $('#EntryButton').show();
    $('#RemoveButton').hide();
}

//購読取消ボタン表示
function ShowRemoveButton() {
    $('#EntryButton').hide();
    $('#RemoveButton').show();
}

画面表示時にcheckSubscription()を行って、新規訪問者がプッシュ通知の購読を行えるようにしています。
既存の訪問者(トークン発行済)の場合は、プッシュ通知購読状況表示領域の表示内容を更新します。

プッシュ通知購読状況表示領域のボタンが押下された時、getSubscription()で購読処理またはremoveSubscription()で購読解除処理を行います。

処理結果はconsole.logで適宜チェックできるようにしていますが、DBに登録されるトークンの内容は記載していません。
生成されたトークンとFirestoreに登録されるトークンの値が合致しているかを確認する時などのために、トークンを表示するための関数(displayToken())も入れているので、適宜使用してみてください。

参考URL:

Qiita:Progressive Web Apps (PWA) 学習者のメモ その2 (プッシュ通知とFCM)
Firebaseドキュメント:JavaScript Firebase Cloud Messaging クライアント アプリを設定する

今回のまとめ

PWAを使えばプッシュ通知を受信することができるようになりますが、実際に受信するためには様々な設定・処理が必要です。
Firebaseの登録は簡単ですが、やりたいことを実現するためにはドキュメントの読み込みが重要で、頭の悪い私は何度「日本語でおk」と呟いたかわかりません。

FCMだけでは不十分だったところを、Firestoreとの連携で割と理想的なフローに落ち着いて良かったと思います。
次回はプッシュ通知の受信・送信について解説していきたいと思います。

続きを読む

PWAでプッシュ通知を実装してみる(2)とりあえずPWA化するためのmagnifest.jsonとserviceworker

前回の記事ではPWAでプッシュ通知を実装することにした経緯とかざっくりした方法と結果を説明しました。
今回はPWA部分に的を絞って書いていきます。

PWAとは

前回も解説しましたが、PWAとは Progressive Web Apps の略です。
Googleが推進しているウェブをアプリみたいに利用できる機能のことです。

詳しくは前回の記事をご覧ください。

PWA化に必要なもの

PWA化するにあたり、下記のものが必要になります。

  • サイトの全体SSL化
  • 192x192pxと512×512pxのアイコン画像
  • manifest.json
  • serviceworker.js
  • headタグの編集

全体SSL化とアイコン画像はまだしも、magnifest.jsonとserviceworker.jsは無いと思うので、作り方も含めて解説します。

サイト全体のSSL化

頑張ってください。

アイコン画像

192x192px、512x512pxのpng画像があればOKです。
サイトのルートディレクトリに設置してください。

magnifest.json

ウェブアプリのマニフェストをjson形式で記載したものです。
ウェブアプリをインストールする際にこちらの設定が参照されます。

magnifest.jsonはサイトのルートディレクトリに設置します。
また、サイトのheadタグ内にmagnifest.jsonの位置を記載しておく必要があります。

HTMLの記述

サイトのheadタグ内に下記のように記載してください。

    <link rel="manifest" href="/manifest.json">
 magnifest.jsonの記述

magnifest.jsonはjson形式で記載します。
AdobeXDのリファレンスを見ると様々な項目を設定することができますが、当サイトではとりあえず下記のように書いてみました。
適当に改変して使用してください。

{
    "name": "虹色ミツバチ-32877",
    "short_name": "32877",
    "description": "freoカスタマイズメモ、テンプレート・プラグイン配布/officeTIPS",
    "start_url": "/?utm_source=homescreen&utm_medium=pwa",
    "display": "standalone",
    "lang": "ja",
    "dir": "auto",
    "orientation": "any",
    "theme_color": "#bcb782",
    "background_color": "#fffce0",
    "icons": [
        {
            "src": "/pwa_192.png",
            "type": "image/png",
            "sizes": "192x192"
        },
        {
            "src": "/pwa_512.png",
            "type": "image/png",
            "sizes": "512x512"
        }
    ],
    "gcm_sender_id": "103953800507"
}

なお、それぞれの項目は

name サイト(ウェブアプリ)名
short_name ホーム画面に表示されるサイト(ウェブアプリ)名
description サイト(ウェブアプリ)の説明
start_url 起動時に表示されるURL。
PWA化するならこのままでOK。
display 表示モード。
fullscreen、fullscreen、standalone、minimal-uiの4つを設定可能。
通常はstandaloneでOK。
lang 日本語なら「ja」
dir テキストの方向。
ltr(左から右)、rtl(右から左)、autoの3つを設定可能。
日本語はltr(左から右)でOK。
theme_color サイト(ウェブアプリ)のテーマカラー。
OS/ブラウザによって使用方法は異なる。
background_color 背景色。
サイト起動時にこの色が表示されたりする。
icons アイコン用画像。
ホーム画面に表示されたりする。
192x192pxと512x512pxがあればOK。
gcm_sender_id プッシュ通知を受信する場合は必要です。
いらない場合は削ってOKです。
FirebaseのCloud Messagingでプッシュ通知を受信する場合は、挿入値は「103953800507」固定になります。
設置箇所

magnifest.jsonの編集が終わったら、サイトのルートディレクトリに設置してください。

serviceworker.js

serviceworker.jsはウェブアプリをバックグラウンドで実行するスクリプトです。
オフラインのアプリの実現・サポートを行い、キャッシュ機能で画面の表示速度を上げます。

なお、serviceworker.jsのファイル名は[serviceworker]で固定である必要はありません
また、複数のserviceworkerを使用するより、一つのjsファイルにまとめたほうが良いようです。

serviceworker.jsはサイトのルートディレクトリに設置します。
また、サイトのheadタグ内にserviceworker.jsの位置や使用するタイミングなどを記載しておく必要があります。

serviceworker.jsの書き方

serviceworkerの書き方は色々調べましたが、ここが一番参考になる+理想通りに動きました。

Qiita:Service Workerの基本とそれを使ってできること

上記を参考に書いて当サイトで動いているserviceworkerの一部がこちら↓

const VERSION = "1";
const ORIGIN = location.protocol + '//' + location.hostname;

const STATIC_CACHE_KEY = 'static-' + VERSION;
const STATIC_FILES = [
    ORIGIN + '/',
    ORIGIN + '/images/logo.png',
    ORIGIN + '/css/bootstrap.min.css',
    ORIGIN + '/css/bootstrap-reboot.min.css',
    ORIGIN + '/css/common.css',
    ORIGIN + '/css/default.css',
    ORIGIN + '/js/jquery.js',
    ORIGIN + '/js/common.js',
];
const CACHE_KEYS = [
    STATIC_CACHE_KEY
];

self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(STATIC_CACHE_KEY).then(cache => {
            return Promise.all(
                STATIC_FILES.map(url => {
                    return fetch(new Request(url, { cache: 'no-cache', mode: 'no-cors' })).then(response => {
                    return cache.put(url, response);
                    });
                })
            );
        })
    );
});

self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then((cacheNames) => {
            return cacheNames.filter((cacheName) => {
                // STATIC_CACHE_KEYではないキャッシュを探す
                return cacheName !== STATIC_CACHE_KEY;
            });
            }).then((cachesToDelete) => {
            return Promise.all(cachesToDelete.map((cacheName) => {
                // いらないキャッシュを削除する
                return caches.delete(cacheName);
            }));
        })
    );
});

self.addEventListener('fetch', event => {
    // POSTの場合はキャッシュを使用しない
    if ('POST' === event.request.method) {
        return;
    }

    event.respondWith(
        caches.match(event.request)
        .then((response) => {
            // キャッシュ内に該当レスポンスがあれば、それを返す
            if (response) {
                return response;
            }

          // 重要:リクエストを clone する。リクエストは Stream なので
          // 一度しか処理できない。ここではキャッシュ用、fetch 用と2回
          // 必要なので、リクエストは clone しないといけない
            let fetchRequest = event.request.clone();

            return fetch(fetchRequest)
            .then((response) => {
                if (!response || response.status !== 200 || response.type !== 'basic') {
                    // キャッシュする必要のないタイプのレスポンスならそのまま返す
                    return response;
                }

                // 重要:レスポンスを clone する。レスポンスは Stream で
                // ブラウザ用とキャッシュ用の2回必要。なので clone して
                // 2つの Stream があるようにする
                let responseToCache = response.clone();

                caches.open(STATIC_CACHE_KEY)
                .then((cache) => {
                    cache.put(event.request, responseToCache);
                });

                return response;
            });
        })
    );
});

今回はあくまでプッシュ通知を目標にするため、上記タグだけでは不十分ですが、キャッシュの生成・削除までの一連の流れは上記でまかなえます。

上記サンプルserviceworkerのざっくりした解説

1行目がキャッシュの番号です。
サイトを更新するたびにこの番号を増やしていく必要があります。

PWAのサイトはだいぶキャッシュが強いです。
serviceworkerでサイトの更新を明示することにより、キャッシュを増やし古いキャッシュを削除します。
そのため、CMSなどを利用したサイトでは「コメントが増えた時」や「新規投稿を行った時」などにserviceworkerを自動的に更新するしくみが必要だと思います。

現時点で、当サイトでは手動でserviceworkerを更新しています。
そのうちfreo用のPWA化用プラグインを作ってみようとは思ってますが、そのうち。
WordpressではPWA化用プラグインがあるようなのでWordpressの方は検討してみてください。
Wordpress用のPWA化プラグインでこれ以降に解説するプッシュ通知が使えるかどうかは実証してません。

5~14行目でキャッシュ化するファイルを指定しています。
URLだけでなくjQueryやスタイルシート等も入れておくと読み込みが早くなるでしょう。

19行目以下でキャッシュの作成・利用・削除などを行っています。
この辺は先程紹介したQiitaの記事で解説されています。

serviceworker.jsを登録する

serviceworker.jsは作成しルートディレクトリに設置しただけでは動きません。
serviceworker.jsをサイトに登録するため、headタグ内に下記のように記載してください。

<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/serviceworker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}
</script>

このコードは、Service Worker APIが利用可能かどうかを確認し、利用可能な場合は、ページが読み込まれたときに 、 /service-worker.jsのService Workerが登録されます。(参考:はじめてのプログレッシブウェブアプリ

ただし、今回はあくまでプッシュ通知を目標にするため、上記タグだけでは不十分ですが、それでもserviceworkerが実際活躍するかどうかの確認をするなら上記タグだけでもOKです。

serviceworkerで作成したキャッシュの確認方法

キャッシュが正常に動いているかどうかは、GoogleChromeのデベロッパーツールで確認できます。
F12キーでデベロッパーツールを開き、ApplicationタブのCache Storageを見ると、現時点で使用されているキャッシュが表示されます。

2019072901.jpg

serviceworkerで[37]を指定しているため、キャッシュが[37]に登録されています。
管理者がserviceworkerを[38]に変更して更新すると、キャッシュが再生成されます。

正常にキャッシュの作成・削除ができていると、Cache Storageには1つのキャッシュしか保持されません。
[37][38][39]…のように複数のキャッシュが存在する場合、キャッシュの削除に失敗しています。
また、serviceworkerが指定している数字(例えば[37])と違う番号のキャッシュが作成されている場合(例えば[39]など)もキャッシュの作成に失敗しているので注意してください。

特定の画面をキャッシュしない処理

特定のURLをキャッシュしたくない場合、fetchイベント内(上記の例でいうと60行目と61行目の間)に下記のように記載してください。

    // 管理画面はキャッシュを使用しない
    if (/\/admin|\/login|\/user/.test(event.request.url)) {
        return;
    }

上記の例では、

  • http://サイトURL/admin
  • http://サイトURL/login
  • http://サイトURL/user

上記URLでキャッシュを使用しないようにしています。

管理者が作成したコンテンツを表示するのみの画面はキャッシュを利用して構いませんが、閲覧者の操作によってリアルタイムで動的に内容が変更する可能性のある画面はキャッシュを利用しないほうがベターです。

headタグの記載について

PWA化する時、magnifest.jsonとserviceworker.jsの箇所でちょろっと書きましたが、headタグ内にPWA化用のソースを記載する必要があります。

まとめるとこんな感じです。

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#6a5f80"/>
<meta name="apple-mobile-web-app-title" content="32877">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" href="/pwa_512.png" sizes="512x512">
<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/serviceworker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}
</script>

PWAはGoogleが主体となって広がっている新たな機能なので、iOSではまだ未実装な部分があり、iOSでPWAを使用する場合にはメタタグで各種設定を指定する必要があります。

今回のまとめ

今回はプッシュ通知のことはとりあえず置いておいてサイトをPWA化する時に最低限必要なものだけご紹介しました。
今回の記事にあるようにmagnifest.jsonとserviceworker.jsを設置したりして色々やれば、サイトをインストールできるようにしたり、表示を早めたりすることは可能です。

PWA化については他にもいろんなサイトや本で紹介されているので、そちらも併せて参考にしてください。
次回は、いよいよプッシュ通知を送るためのあれこれについて解説していきたいと思います。

続きを読む

PWAでプッシュ通知を実装してみる(1)準備と解説

PWAでプッシュ通知を実装するのが大変だったので書いておきます。

目標はこんな感じ。

  • freoをPWA化する
  • プッシュ通知の購読をサイトから簡単に行えるようにする
  • プッシュ通知の送信は手動で行うものとする(サイトの更新のお知らせとか簡単なものしかしないので)

色々やって結果がこれ。

  • サイトをWindows・Android・iOSにインストールできるようになった
  • 一度キャッシュした画面ならサイトをオフラインでも閲覧できるようになった
  • サイトの表示が軽くなった
  • サイト上にプッシュ通知の購読状況が表示されるようになった
  • サイト上でプッシュ通知の購読開始・購読停止ができるようになった
  • フォアグラウンドのGoogleChrome、Firefoxを利用している複数人に対して一度にプッシュ通知を送信・受信できるようになった
  • フォアグラウンド・バックグラウンドのAndroid(Chrome)を利用している複数人に対して一度にプッシュ通知を送信・受信できるようになった

「色々」の部分が長いので頑張って書いていきます。

PWAでプッシュ通知を実装する前に

まずは前提知識から。

PWAとは

PWAとは Progressive Web Apps の略です。
Googleが推進しているウェブをアプリみたいに利用できる機能のことです。

  • サイトがSSL化されていることが絶対条件
  • オフラインでも動作する
  • プッシュ通知を受信できる
  • サイトをアプリのようにインストールできる
  • 指定したファイルをキャッシュできるので読み込みが早い

ので、ファンの多いサイトや読み物系サイト、CMSを利用していて動作が重いサイトなんかは割といいかもしれないと思い、実装してみることにしました。
ちなみにGoogleは動作が軽いサイトを評価する傾向があるので、SEO的な意味でもメリットはあるのかもしれません。知らんけど。

参考URL
PWA化するにはどうすればいい?

既存サイトをPWA化するのは簡単です。

  • アイコン用の画像を設置する
  • manifest.jsonを設置する
  • service workerを設置する

以上。簡単でしょ?
というのがGoogleの言い分です。んなわけねーだろって思いました。

ちなみにWordpressではPWA化するためのプラグイン(PWA for Wordpress)があるようです。
このサイトはWordpressではないですし、プッシュ通知が最終目標だったので頑張って自作することにしました。

PWA化するためのmanifest.jsonとservice worker.jsの書き方はぐぐるといっぱいありますが、私は下記の記事を参考にしました。
詳細に書いてくださっているので助かりました。

参考URL
プッシュ通知について

プッシュ通知って最近いろんなサイトでやってますよね。
PCだと画面の右下にポコンと出てくるやつです。

あれを実装するにはいろんなサービスがありますが、サービスを使わなくても自分でできるようになりましたよっていうのがPWAのいいところらしいです。
プッシュ通知を受信できる環境を作るにはPWA化だけでOKですが、実際にプッシュ通知を送信・受信するには、PWA化だけでは不十分でした。
自分でできると言いながら今回はGoogleのfirebaseを利用しているので完全自力ではないんですけど、とにかくfirebaseを利用してプッシュ通知の受信・送信ができるようになりました。

ちなみに、今回の方法では、ブラウザでプッシュ通知を受け取る許可をするのと、実際にプッシュ通知を購読するのは別の設定です。
どちらも個別に設定が必要ですが、どちらかが欠けるとプッシュ通知は受け取れません。
プッシュ通知を購読するには、

  1. ブラウザでプッシュ通知を受け取る設定をする
  2. プッシュ通知を購読する

の2点が必要です。
ブラウザ側でプッシュ通知を受け取る設定をしていても、購読しないとプッシュ通知は受け取れません。
PWAとプッシュ通知配信サービスの併用でfirebaseまわりのめんどくさい部分はクリアできそうな気もしますが、まあ勉強のために色々やってみようってことで。

参考URL
firebaseについて

firebaseは、Googleのサービスです。
サイトやアプリをちょっと便利にするのに必要な機能、例えば

  • SNSアカウントでのログイン
  • プッシュ通知の送受信
  • リアルタイムデータベース

などを利用できるようになります。しかも無料で。
容量・転送量に応じて有料プランもありますが個人サイトなら無料で十分だと思います。

firebase側で様々なスクリプトを用意してくれているので、Googleアカウントでログインしてプロジェクトを作成すれば、誰でも利用可能です。
今回は、PWA化したWEBサイトでプッシュ通知を受信・送信するのに、firebaseのCloud MessagingとCloud Firestoreを使用しました。

参考URL
node.jsについて

node.jsとは、サーバー側で動くjavascriptのプラットフォームです。

firebaseを利用してプッシュ通知を送信したりするには、サーバー側(アプリ側)での作業が必要です。
今回はアプリ側の作業をWindowsのコマンドプロンプトで行います。
この時に必要なのがnode.jsです。
node.jsを使わずに他のものを利用しても構わないですが今回はnode.jsにしました。

参考URL
このサイトでプッシュ通知を実装するために今回やったこと

上にもさらっと方法を書いてますが、もうちょっと詳しく書いておきます。

  • サイトをPWA化した(manifest.jsonとserviceworkerの作成)
  • Firebaseにプロジェクトを作成した
  • Firebase Cloud Messagingでプッシュ通知を受信できるようにした
  • プッシュ通知を購読するか購読しないかをサイト上で選択・設定できるようにした
  • 購読状況はサイト上で確認できるようにした
  • 購読開始時に発行されたトークンと購読状況をFirebase Cloud Firestoreに登録するようにした
  • 購読停止時に購読状況を更新するようにした
  • node.jsを使ってコマンドプロンプトからプッシュ通知を送信できるようにした
  • プッシュ通知発信時に購読停止中のトークンをFirebase Cloud Firestoreから取得してトピックから削除するようにした
  • プッシュ通知発進時に購読中のトークンをFirebase Cloud Firestoreから取得してトピックに登録するようにした
  • プッシュ通知はトピック宛に発信するようにした

ただプッシュ通知実装するだけでめっちゃ大変ですやんGoogleの公式ドキュメント意味わかんないしとか思ったんですけどなんとかできたので努力って大事。
これを全部解説していくとあまりに長くなるので分割します。

続きを読む

ページトラックバック数表示プラグイン

freoのページに通知されたトラックバック数を[freo/index.php/page]にアクセスした時に表示されるページ一覧で表示するプラグインです。

特徴

  • [freo/index.php/page]にアクセスした時(ページを検索した時など)に表示されるページ一覧でトラックバック数を表示できます。

ダウンロード

display_page_trackback_count_3287_1_0_0.zip

導入方法

  1. 上記ファイルをDLして解凍する。
  2. [freo]フォルダの中身freo設置フォルダにアップロード。
  3. [freo/templates/internals/page/default.html]の220行目と221行目の間などに下記のソースを記入する。
    <ul class="information">
        <li>トラックバック数:{$plugin_page_trackback_counts[$page.id]}</li>
    </ul>
    
  4. [freo/templates/internals/page/default.html]ファイルをアップロード。

更新履歴

2018/07/09  プラグイン公開・配布開始

続きを読む

ページコメント数表示プラグイン

freoのページに投稿されたコメント数を[freo/index.php/page]にアクセスした時に表示されるページ一覧で表示するプラグインです。

特徴

  • [freo/index.php/page]にアクセスした時(ページを検索した時など)に表示されるページ一覧でコメント数を表示できます。

ダウンロード

display_page_comment_count_3287_1_0_0.zip

導入方法

  1. 上記ファイルをDLして解凍する。
  2. [freo]フォルダの中身freo設置フォルダにアップロード。
  3. [freo/templates/internals/page/default.html]の220行目と221行目の間などに下記のソースを記入する。
    <ul class="information">
        <li>コメント数:{$plugin_page_comment_counts[$page.id]}</li>
    </ul>
    
  4. [freo/templates/internals/page/default.html]ファイルをアップロード。

更新履歴

2018/07/09  プラグイン公開・配布開始

続きを読む

アルバム漫画表示プラグイン

アルバムプラグインで登録した記事を漫画として表示できるプラグインです。
freo公式の漫画表示プラグインのような表示をアルバムプラグインでもできるようにしました。

サンプル

当サイトのアルバムで使用しています。

特徴

表示方法
  • アルバムプラグインで漫画として表示したい記事を登録後、[freo/index.php/album_comic/アルバムID]にアクセスすると画像を漫画状に表示できます。
  • レスポンシブデザインに対応しています。(スマホからアクセス時はリンクURLに関わらず1ページずつ表示します。)
画像のルール補足
  • 表紙が必要な場合、画像のファイル名は、0 からの連番にしてください。(2ページずつ表示させた場合、0 は表紙に、最後は裏表紙になります。)
  • 表紙が不要な場合、画像のファイル名は、1 からの連番にしてください。(2ページずつ表示させた場合、最初から2ページずつ表示されます。)
  • 連番で画像を作成する場合、[01.jpg]や[001.jpg]のように桁数は合わせないようにしてください。
  • 画像の種類は、gif・jpeg・png に対応しています。
  • 画像のサイズは任意ですが、漫画ごとにすべて統一してください。また、大きすぎると表示が遅くなりますし、そもそも画面に入りません。
オプション

漫画を表示する際、URLに特定のパラメーターを付加することで、表示方法をカスタマイズすることができます。(管理画面で漫画を挿入する際に付加されますが、自分で調整することも可能です。)

columns=1
1ページずつ表示します。
direction=ltr
左→右の順で表示します。(2ページずつ表示する場合に有効)
devide=on
ページを分割して表示します。
end=on
終了ページを表示します。
navigation=off
ナビゲーションを非表示にします。

パラメーターは & で連結して、複数指定することができます。例えば ?columns=1&devide=on&direction=ltr のように指定することができます。

終了ページについて

上記オプションで[end=on]を設定した時表示される終了ページは、アルバム記事の本文・コメントが表示されます。

ダウンロード

album_comic_32877_1_0_0.zip

導入方法

  1. アルバムプラグインをDLして実装する。
  2. 上記ファイルをDLして解凍する。
  3. [freo]フォルダに[css][js][libs][templates]フォルダをアップロードする。
  4. [freo/index.php/album_comic/アルバムID]にアクセスして正常にアルバムが漫画表示されるか確認してください。

アルバム一覧表示時にリンクを漫画表示用のリンクに変える方法

[freo/templates/plugins/album/default.html]を編集して、アルバム一覧表示時の記事へのリンクを漫画表示用のリンクに変更します。
たとえば、[freo/templates/plugins/album/default.html]の29行目

<h3><a href="{$freo.core.http_file}/album/view/{$plugin_album.id}">{$plugin_album.datetime|date_format:'%Y/%m/%d'}<!--{if $plugin_album.title}-->{$plugin_album.title}<!--{/if}--></a><!--{if $freo.user.authority == 'root' or $freo.user.authority == 'author'}--><a href="{$freo.core.http_file}/album/admin_form?id={$plugin_album.id}"><img src="{$freo.core.http_url}images/icons/edit.png" alt="編集" title="編集" width="16" height="16" /></a><!--{/if}--></h3>

<h3><a href="{$freo.core.http_file}/album_comic/{$plugin_album.id}">{$plugin_album.datetime|date_format:'%Y/%m/%d'}<!--{if $plugin_album.title}-->{$plugin_album.title}<!--{/if}--></a><!--{if $freo.user.authority == 'root' or $freo.user.authority == 'author'}--><a href="{$freo.core.http_file}/album/admin_form?id={$plugin_album.id}"><img src="{$freo.core.http_url}images/icons/edit.png" alt="編集" title="編集" width="16" height="16" /></a><!--{/if}--></h3>

のように変更します。

カテゴリーID[comic]の記事のみリンク先を変更する

[freo/templates/plugins/album/default.html]の29行目を

<!--{if $plugin_album.category_id == 'comic'}-->
    <h3><a href="{$freo.core.http_file}/album_comic/{$plugin_album.id}">{$plugin_album.title}</a></h3>
<!--{else}-->
    <h3><a href="{$freo.core.http_file}/album/view/{$plugin_album.id}">{$plugin_album.title}</a></h3>
<!--{/if}-->

のように変更します。

更新履歴

2018/05/05 配布開始

 

続きを読む

freoでサイト全体を管理するレスポンシブテンプレート基本セット

freoでサイト全体を管理する場合のテンプレート(レスポンシブ対応)です。

はじめに

テンプレートについて

このテンプレートは、多機能CMSツールfreoの非公式テンプレートです。
当サイトは、このテンプレートを使用することによって発生した不利益・損害等には一切責任を負わないものとします。

テンプレートのカスタマイズについて

テンプレート・スタイルシートの内容はご自由に編集して下さい。
テンプレートの利用・編集について許可を得る必要はありません。

特徴

  • レスポンシブデザインで作成しています。大画面表示・タブレットサイズ表示・スマートフォン表示を切り替えています。
  • スマートフォン以下のサイズで閲覧した際、jQuery[meanmenu]を利用してメインメニューを表示します。

サンプル

https://32877.xii.jp/responsive/index.php

ダウンロード

32877_templates_responsive_basic_1_0_0.zip

導入方法

  1. 公式からfreoをダウンロードし、設置してください。
  2. ご自分のfreoにアクセスし、正常に動いているかどうか確認してください。
  3. 以下のプラグインをダウンロードし、導入してください。
        freo/パンくずリスト表示プラグイン
  4. 必要に応じて、下記のプラグインをダウンロードし、導入してください。
        freo/メール送信プラグイン
        freo/メッセージ登録プラグイン
        freo/拍手送信プラグイン
        32877/ニュースプラグイン
        32877/新着ニュースプラグイン
        32877/バナー付きリンクプラグイン
  5. 本テンプレートをDLし、解凍してください。
  6. [css][js][templates]フォルダを[freo]フォルダにアスキーモードでアップロードしてください。
  7. 更新されない場合は公式のトラブルシューティング「テンプレートを編集しても反映されない」を参照してください。

更新履歴

  2017.10.01  配布開始。

続きを読む

エントリーページ移動

ユーティリティ

Twitter

記事検索

ページ上部へ