はじめに

画面を開いていないときやログインしていないときでも通知ができたらいいなと思いませんか?
本記事では、Firebase Cloud Messaging (FCM) と Service Worker を利用して、Webアプリケーションにバックグラウンドプッシュ通知を実装する方法を解説します。
「お手軽に実装する」をコンセプトに、プッシュ通知を表示させるための基本的な実装から、実用性を高めるための通知クリック時の動作カスタマイズまで、ステップ・バイ・ステップでご紹介します。また、本記事で紹介する技術が、SAPシステムのような業務アプリケーションにおいてどのように活用できるか、その応用例についても触れていきます。
※本記事で紹介する内容は、SAPの標準機能ではなく、GoogleのFirebase Cloud Messaging (FCM) とService Worker を利用したカスタム実装です。また、記事内のコードはGoogle Chromeブラウザのみで動作確認を行っております。
通知機能実装の背景
SAP Fioriの標準通知機能は非常に便利ですが、ログイン状態かつ対象の画面がブラウザで開かれている間しか通知を受け取れないという制約があります。ログアウト状態でもブラウザさえ開いていれば、通知を受け取ることができるようにしたいというのが、今回の実装を行うことになった背景です
SAP Fioriの標準通知機能について紹介しているブログ記事はこちらです。
このプッシュ通知を実装することで、例えば以下のようなことができるようになります。
- 長時間バッチ処理の完了通知: ユーザーが時間のかかるレポート生成やデータ更新処理を開始した後、アプリ画面を閉じても処理完了を確実に通知できます。これにより、ユーザーは処理が終わるまでアプリ画面を開いて待機する必要がなくなります。
- ワークフローや承認依頼の通知: 新しい承認依頼が発生した際に、担当者がどのデバイスを利用していても即座に通知を届け、ビジネスプロセスの停滞を防ぎます 。
- 重要なアラートの配信: 在庫僅少やシステムエラーなど、即時対応が求められる事象を関係者にプッシュ通知することで、迅速な初動を促します。
Part 1:プッシュ通知機能を実装する
まずは、アプリ画面が閉じていても通知を受け取れる仕組みの全体像と、その実装手順を見ていきましょう。

FCMとService Workerの役割
Webプッシュ通知の実現には、通知を「配信する仕組み」と「受け取る仕組み」が必要です。
・Firebase Cloud Messaging (FCM): Googleが提供するプッシュ通知の配信を担うサービスです。サーバーから各デバイスへ、確実かつスピーディーにメッセージを届けます 。FCMが送信するメッセージには主に「通知メッセージ」と「データメッセージ」があり、今回はSDKが自動で通知を表示してくれる「通知メッセージ」を使い、手軽な実装を目指します。
FCM自体は無料で利用できますが、通知をトリガーするためにCloud Functionsを使用したり、通知内容を生成するためにデータベースからデータを読み取ったりするなど、関連する他のFirebaseサービスやGoogle Cloudサービスには、無料枠を超えると料金が発生する場合があります 。詳細な料金体系については、公式の料金ページをご確認ください。
・Service Worker: ブラウザのバックグラウンドで動作し、プッシュ通知を受け取る役割を担うJavaScriptファイルです。対象のWebページが開かれていない状態でもFCMからのメッセージを受信し、OSに通知を表示させることができます。
処理フロー
全体の処理フローは以下の通りです。

- トークン取得: WebアプリからFCMに対し、デバイスを識別するための一意なトークンを要求します。
- トークン保存: 取得したトークンを、後で通知を送るためにバックエンドサーバー(例:SAP)のデータベースに保存します。
- 通知送信: バックエンドサーバーからFCMへ、通知内容と宛先トークンを指定してリクエストを送信します。
- 通知受信: FCMが対象のデバイスに通知を配信し、Service Workerがバックグラウンドでこれを受け取ります。
- 通知表示: Service Worker内で動作するFCM SDKが通知を処理し、OSの通知表示画面に表示します。
実装手順
Firebaseプロジェクトの準備
まず、メッセージングの中継役となるFirebaseプロジェクトを準備します 。
- Firebaseプロジェクトの作成: Google Firebase Consoleにアクセスし、「プロジェクトを作成」から新しいプロジェクトを作成します。
- Webアプリケーションの追加: プロジェクトダッシュボードで、Webアイコン(
</>)をクリックして新しいWebアプリケーションを追加します。アプリを登録すると、firebaseConfigというJavaScriptオブジェクトが生成されるので、これをコピーしておきます 。 - VAPIDキーの生成: プロジェクト設定 >「Cloud Messaging」タブに移動し、「ウェブプッシュ証明書」セクションで「キーペアを生成」ボタンをクリックします。生成されたVAPIDキー(公開鍵)も後ほど使用します 。


フロントエンドの実装 (SAPUI5)
次に、SAPUI5アプリケーション側でService Workerを登録し、FCMからデバイストークンを取得します。
BaseController.jsやComponent.jsなど、アプリケーションの初期化時に実行される場所に以下の処理を実装します。
コードはこちら
// Firebaseプロジェクトの設定 (手順1でコピーしたもの)
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};
// ウェブプッシュ証明書 (VAPID) キー (手順1で生成したもの)
const vapidKey = "YOUR_VAPID_KEY";
/**
* Service Workerを登録し、FCMトークンを取得する
*/
async function initializeFirebaseMessaging() {
// Service Workerが利用可能かチェック
if (!('serviceWorker' in navigator)) {
console.warn('Service Workerはサポートされていません。');
return;
}
try {
// Firebase SDKを動的にインポート
const { initializeApp } = await import("https://www.gstatic.com/firebasejs/11.2.0/firebase-app.js");
const { getMessaging, getToken } = await import("https://www.gstatic.com/firebasejs/11.2.0/firebase-messaging.js");
// Service Workerのスクリプトファイルを登録
const swUrl = sap.ui.require.toUrl("your/path/to/firebase-messaging-sw.js");
const registration = await navigator.serviceWorker.register(swUrl);
console.log('Service Workerが正常に登録されました:', registration);
// Firebaseを初期化
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
// FCMトークンを取得
const currentToken = await getToken(messaging, {
serviceWorkerRegistration: registration,
vapidKey: vapidKey
});
if (currentToken) {
console.log("FCM登録トークン:", currentToken);
// 取得したトークンをバックエンドサーバーに送信して保存する
// (例: ODataサービスを呼び出す)
// this._sendTokenToBackend(currentToken);
} else {
console.warn("FCMトークンが取得できませんでした。通知の許可が必要です。");
}
} catch (error) {
console.error('プッシュ通知の初期化中にエラーが発生しました:', error);
}
}
// 適切なタイミングで初期化処理を呼び出す
// 例: onInit内
// initializeFirebaseMessaging();Service Workerの実装
Webアプリケーションのルートディレクトリにfirebase-messaging-sw.jsという名前でファイルを作成します。このファイルがバックグラウンドでの通知受信を担います。
コードはこちら
// in firebase-messaging-sw.js
// Service Worker専用のFirebase SDKモジュールをインポート
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.2.0/firebase-app.js";
import { getMessaging, onBackgroundMessage } from "https://www.gstatic.com/firebasejs/11.2.0/firebase-messaging-sw.js";
// Firebaseプロジェクトの設定 (フロントエンドと同じもの)
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};
// Firebaseを初期化
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
/**
// バックグラウンドでメッセージを受信した際の処理
// 「通知メッセージ」の場合、SDKが自動で通知を表示するため、このハンドラは通常不要です。
*/
onBackgroundMessage(messaging, (payload) => {
console.log('[service-worker.js] Received background message ', payload);
});テスト方法
実装した内容が正しく動作するか、curlコマンドを使ってFCMサーバーに直接リクエストを送り、テストします。
アクセストークンの取得: ローカル環境にGoogle Cloud CLIをインストールし、Firebaseプロジェクトのサービスアカウントキーを使って認証後、以下のコマンドでOAuth 2.0アクセストークンを取得します。
コードはこちら
gcloud auth print-access-tokencurlコマンドの実行: 取得したアクセストークンと、フロントエンドで取得したFCM登録トークンを使って、以下のコマンドを実行します。
コードはこちら
curl -X POST \
-H "Authorization: Bearer <手順1で取得したアクセストークン>" \
-H "Content-Type: application/json" \
-d '{
"message": {
"token": "<フロントエンドで取得したFCM登録トークン>",
"notification": {
"title": "プッシュ通知テスト",
"body": "プッシュ通知テスト"
},
"webpush": {
"fcm_options": {
"link": "https://"
}
}
}
}' \
https://fcm.googleapis.com/v1/projects/<あなたのFirebaseプロジェクトID>/messages:sendコマンド実行後、デスクトップに以下のような通知が表示されれば成功です。

Part 2:通知クリック時の動作をカスタマイズする
Part 1で実装した通知をクリックすると、fcm_options.linkで指定したURLが開きます。しかし、この標準の動作には以下の制約があります。
「すでに同じドメインのページが開いている場合、そのタブがフォーカスされるだけで、指定したURLには遷移しない」
例えば、Fiori Launchpadのホーム画面 (.../Shell-home) を開いている状態で、特定のアプリ画面 (.../SalesOrder-display&/123) へ直接遷移させたい通知をクリックしても、ホーム画面がフォーカスされるだけで画面は切り替わりません。これだと遷移処理の要件を満たせない場合があります。
この問題を解決するため、Service Workerのクリックイベントを以下のようにカスタマイズする必要があります。
notificationclickイベントによる実装方法
firebase-messaging-sw.jsを以下のように修正します。ポイントは、Firebase SDKを初期化する前に、自前のクリックイベントリスナーを定義することです。これにより、SDKのデフォルト動作を上書きします 。
コードはこちら
// in firebase-messaging-sw.js
/**
* ユーザーが通知をクリックしたときのハンドラ
* Firebase SDKの初期化より先に定義する
*/
self.addEventListener('notificationclick', event => {
console.log('カスタム notificationclick イベント受信', event);
// 通知を閉じる
event.notification.close();
// 通知のペイロードから遷移先URLを取得する
// バックエンドからは"data"ペイロードにURLを含めてもらう想定
let urlToOpen = null;
if (event.notification.data && event.notification.data.FCM_MSG && event.notification.data.FCM_MSG.data && event.notification.data.FCM_MSG.data.transitionUrl) {
urlToOpen = event.notification.data.FCM_MSG.data.transitionUrl;
}
// URLが見つからない場合のフォールバック先
if (!urlToOpen) {
urlToOpen = '/'; // アプリのトップページなど
}
// 既存のタブを探さず、常に指定されたURLを開く
event.waitUntil(
clients.openWindow(urlToOpen).then(windowClient => windowClient? windowClient.focus() : null)
);
});
// --- 以下、Part 1と同じ ---
// Firebase SDK のスクリプトをロード
importScripts("https://www.gstatic.com/firebasejs/11.2.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/11.2.0/firebase-messaging-compat.js");
// (以下、Firebaseの初期化処理など)この実装により、バックエンドから送信するメッセージのdataフィールドに遷移先のURL(例:transitionUrl)を含めることで、ユーザーを意図した通りの画面へ誘導できるようになります。
※ この方法はSDKの処理を上書きするため、他の動作などに影響が出る可能性があります。
実際にこの方法を使う場合は、検証を慎重に行うことをお勧めします。
おわりに
本記事では、FCMとService Workerを用いて、基本的なWebプッシュ通知を実装する方法から、より実践的なクリック動作のカスタマイズまでを解説しました。
ご紹介した方法は、特にSAPのような業務システムにおいて、ユーザー体験と業務効率を大きく改善するポテンシャルを秘めています。意外と簡単に実装できる、プッシュ通知の仕組みです。ご自身のアプリケーションにも導入を検討してみてはいかがでしょうか。
投稿者プロフィール

-
2023年にIT未経験で入社。
AWSを使用したシステム開発に2年間ほど携わり、現在はSAP Fioriのアプリ開発に取り組んでいます。
業務を通じて得た経験を積極的に発信していきたいと思っています!
趣味は野球観戦です。