当应用程序处于后台 FCM 中时更新 Web 应用程序用户界面

Posted

技术标签:

【中文标题】当应用程序处于后台 FCM 中时更新 Web 应用程序用户界面【英文标题】:Updating Web App User Interface when application is in background FCM 【发布时间】:2017-07-18 11:50:15 【问题描述】:

我正在使用 FCM 处理通知,它可以正常工作,直到我需要从 firebase-messaging-sw.js 更新我的 UI,而我的 Web 应用程序在后台。

    我的第一个问题是:是否可以通过服务工作者在后台(当用户不专注于 Web 应用时)更新我的 Web 应用 UI

    其次,如果是这样,怎么做?因为我尝试了几件事但它不起作用,显然做错了什么,当它起作用时,我的网络应用程序处于前台。我究竟做错了什么?

我的代码如下。

my-firebase-service-sw.js

// [START initialize_firebase_in_sw]
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase 
libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-messaging.js');


// My Custom Service Worker Codes
var CACHE_NAME = 'assembly-v0.1.3.1';
var urlsToCache = [
    '/',
    'lib/vendors/bower_components/animate.css/animate.min.css',
    'lib/vendors/bower_components/sweetalert/dist/sweetalert.css',
    'lib/css/app_1.min.css',
    'lib/css/app_2.min.css',
    'lib/css/design.css'
];
var myserviceWorker;
var servicePort;


// Install Service Worker
self.addEventListener('install', function (event) 
    console.log('installing...');
   // Perform install steps
   event.waitUntil(
     caches.open(CACHE_NAME)
     .then(function (cache) 
     console.log('Opened cache');
     return cache.addAll(urlsToCache);
   )
   );
  console.log('installed...');
 );

  // Service Worker Active
  self.addEventListener('activate', function (event) 
  console.log('activated!');
  // here you can run cache management
  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function (cacheNames) 
       return Promise.all(
        cacheNames.map(function (cacheName) 
           if (cacheWhitelist.indexOf(cacheName) === -1) 
            return caches.delete(cacheName);
           
        )
      );
    )
  );
);


self.addEventListener('fetch', function (event) 
  event.respondWith(
    caches.match(event.request)
      .then(function (response) 
        // Cache hit - return response
        if (response) 
          return response;
        

        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response.
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function (response) 
            // Check if we received a valid response
            if (!response || response.status !== 200 || response.type !== 'basic') 
              return response;
            

        // IMPORTANT: Clone the response. A response is a stream
        // and because we want the browser to consume the response
        // as well as the cache consuming the response, we need
        // to clone it so we have two streams.
        var responseToCache = response.clone();

        caches.open(CACHE_NAME)
          .then(function (cache) 
            cache.put(event.request, responseToCache);
          );

        return response;
      
    );
  )
  );
);

self.addEventListener('message', function (event) 
  console.log("SW Received Message: " + event.data);
  // servicePort = event;
  event.ports[0].postMessage("SW Replying Test Testing 4567!");
);

myserviceWorker = self;


// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp(
  'messagingSenderId': '393093818386'
);

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
// [END initialize_firebase_in_sw]

// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// [START background_handler]
messaging.setBackgroundMessageHandler(function (payload) 
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
 // Customize notification here
 // send to client
 console.log('Sending data to notification');
 try 
      myserviceWorker.clients.matchAll().then(function (clients) 
      clients.forEach(function (client) 
      console.log('sending to client ' + client);
      client.postMessage(
          "msg": "401",
          "dta": payload.data
      );
    )
  );
  catch (e) 
    console.log(e);
 
const notificationTitle = payload.data.title;;
const notificationOptions = 
   body: payload.data.body,
   icon: payload.data.icon,
   click_action: "value"
;

 return self.registration.showNotification(notificationTitle,
 notificationOptions);
);
// [END background_handler]

在我的主 javascript 文件中,它接收有效负载。当应用程序在前台时,它会收到它。我主要关心和问题是当应用程序在后台接收有效负载时,前台的所有活动都可以正常工作。

【问题讨论】:

【参考方案1】:

即使您的网站正在打开但没有重点,也可以更新 UI。 获取所有客户端列表后,只需添加启用选项includeUncontrolled。 示例:

messaging.setBackgroundMessageHandler(function (payload) 
    console.log('[firebase-messaging-sw.js] Received background message ', payload);
    self.clients.matchAll(includeUncontrolled: true).then(function (clients) 
       console.log(clients); 
       //you can see your main window client in this list.
       clients.forEach(function(client) 
           client.postMessage('YOUR_MESSAGE_HERE');
       )
     )
);

在您的主页中,只需为来自服务人员的消息添加侦听器即可。 例如:

navigator.serviceWorker.addEventListener('message', function (event) 
    console.log('event listener', event);
);

更多详情请见Clients.matchAll()。

【讨论】:

以上是关于当应用程序处于后台 FCM 中时更新 Web 应用程序用户界面的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序处于后台状态时,FCM 多个推送通知无法正常工作

当应用程序处于后台状态时,Google FCM getIntent 未返回预期数据

当应用程序处于后台状态时,Google FCM getIntent 未返回预期数据

当应用程序处于后台状态时,FCM多次推送通知无法正常工作

当应用程序处于后台/终止并收到 FCM 通知时,如何在 Flutter 中显示本地通知?

FCM 点击如何在应用程序处于后台状态时打开用户指定的活动而不是默认活动