2018年12月8日 星期六

[Vue] Shopcart example with Firebase Cloud Messaging and Functions (2)


 Vue.js    VueFire    FCM   Cloud Functions 


Introduction


In the previous article, [Vue] Shopcart example with Firebase Cloud Messaging and Functions (1), we had learned how to send a FCM message to client by Google FCM Web api.

We will create server-side codes on Firebase Cloud Functions for sending message in this article.

The architecture should be like this.



Environment


Vue.js 2.5.11
Vue CLI 3.2.1
Firebase Javascript SDK 5.5.8
VueFire 1.4.5



Implement


Install

Requirements:

1.  Node.js
2.  NPM

To initialize the implement environment on your Vue.js (or other) project, use the commands:

$ firebase login
$ firebase init functions


During initialing Firebase Cloud Functions, choose your target Firebase project, implement language (JS or TypeScript) and install the dependent npm packages.
PS. I will use JS in this tutorial.





The Firebase CLI will create the directories and files as below.
index.js is the main source file for your Cloud Functions code.




The packages we need are as following, make sure they are installed to your project.

"dependencies": {
    "cors": "^2.8.5",
    "firebase-admin": "~6.0.0",
    "firebase-functions": "^2.1.0"
  }



Implement Cloud Functions

We will create a Cloud Function with Firebase HTTPS API: functions.https and its listener event: onRequest() to replace sending request to FCM Web api for pushing the discount notification to clients.

Use functions.https to create a function that handles HTTP events. The event handler for an HTTP function listens for the onRequest() event, which supports routers and apps managed by the Express web framework.

The type of onRequest()’s parameter is function(non-null express.Request, non-null express.Response)
We can get the useful properties/methods of express.Request as following,

Prop
Description
Value for example
request.method
Http Method kind
"POST"
request.get("<header>")
Get header’s value
"bearer fdsdfpokendofdg"
request.query.<url param>
Get url param’s value
Url: https://xxx/?age=30

request.query.age will be 30
request.body.<prop>
request.body contains key-value pairs of data submitted in the request body. So we can get the value by prop name.
Assume body is
{"name":"JB"}

request.body.name will be "JB"
request.rawBody
The raw (unparsed) bytes of the request
""


Notice in onRequest(), we can use one of these APIs to send FCM messages:
2.  Admim FCM API (Supports Node, Java, Python and Go)


Legacy FCM server API

const functions = require("firebase-functions")
const cors = require('cors')({ origin: true });
const admin = require("firebase-admin")

admin.initializeApp();

exports.sendDiscountMsg = functions.https.onRequest((request, response) => {
    cors(request, response, () => {
        const userToken = request.get("token");
        const userName = request.get("user-name")
      
        response.end();

        /* Legacy FCM server API : https://firebase.google.com/docs/cloud-messaging/admin/legacy-fcm */
        // Notification details.
        let payload = {
            notification: {
                title: "Advertisements",
                body: `Hi ${userName}, we have special discount for you, visit here for more details!`,
                click_action: "https://xxxxx.firebaseapp.com",
                icon: "dist/firebase-logo.png"
            }
        };
        // Send notifications to device
        return admin.messaging().sendToDevice(userToken, payload);
       
})


Admin FCM API (Node.js)

const functions = require("firebase-functions")
const cors = require('cors')({ origin: true });
const admin = require("firebase-admin")

admin.initializeApp();

exports.sendDiscountMsg = functions.https.onRequest((request, response) => {
    cors(request, response, () => {
        const userToken = request.get("token");
        const userName = request.get("user-name")
       
        response.end();

        /* Admin FCM API (Node.js): https://firebase.google.com/docs/cloud-messaging/admin/send-messages */
        let message = {
            webpush: {
                notification: {
                    title: "Advertisements",
                    body: `Hi ${userName}, we have special discount for you, visit here for more details!`,
                    click_action: "https://xxxxxx.firebaseapp.com",
                    icon: "dist/firebase-logo.png"
                }
            },
            token: userToken
        };

        return 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);
            });
    });
})


As you can see, the request should contains 2 custom header:

Header
Description
Token
User’s registration token
user-name
The display name of user



Deploy the Cloud Functions

Its easy to deploy the Cloud Functions by Firebase CLI:

$ firebase deploy --only functions





Back to Firebase Console, we will see the Functions just deployed.





Example: Send the discount message when user go to shopping page

Now we have the Cloud Functions and we are Serverless :), so we will make the client requests the Function to trigger sending FCM message to himself.
(Ok, I know it’s a weird scenario and please don’t mind)

Lets modify our Vue.js app, add the pushDiscountMsg() to request the Cloud Function with user’s name and token as following,


new Vue({
  el: '#app',
  methods: {
    async setFbMessaging() {
      let msgService = new messagingService();
      //Request permission
      await msgService.requestPermissionAsync();
      //Retrieve token
      await msgService.getTokenAsync();
    },
     pushDiscountMsg(token, user) {
      console.log("Start push msg with token: " + token);
      this.axios
        .get(
          "https://<your domain>.cloudfunctions.net/sendDiscountMsg",
          {
            headers: {
              token: token,
              "user-name": user
            }
          }
        )
        .then(result => {
          console.log(result);
        });
    }
  },
  created() {
    var vm = this;

     vm.setFbMessaging().then(token => {
          vm.pushDiscountMsg(token, firebaseAuth.currentUser);
      });


    //Add callback for receiving FCM
    firebaseMessaging.onMessage(function(payload) {
      let notification = payload.notification;
      alert(notification.body);
    });
  }
};


Demo







Reference





沒有留言:

張貼留言