Notice: wp_enqueue_style was called incorrectly. Scripts and styles should not be registered or enqueued until the wp_enqueue_scripts, admin_enqueue_scripts, or login_enqueue_scripts hooks. Please see Debugging in WordPress for more information. (This message was added in version 3.3.0.) in /home/vinova/blog.vinova.sg/wp-includes/functions.php on line 4161
Azure vs GCP part 18: Mobile App Development (GCP) - Vinova - Vibrant Innovators

Azure vs GCP part 18: Mobile App Development (GCP)

I tested Azure Mobile Apps in previous article, but I totally forget about “App Center”, the new Azure offering for Mobile App development. However, I test GCP solution in this article anyways, and get back to Mobile Center later.

Firebase

Firebase is a platform that developers can easily develop mobile (iOS and Android) and Web app.

When I start learning Google cloud, Firebase was the first service I had an opportunity to play with and later I realize google has way large set of services as Google Cloud Platform.

This may cause a bit of confusion as GCP and Firebase are two separate services at the moment, but Google put many integrations between these two and eventually it may end up one service.

Key Features for Developer

It offers several key features for mobile application development.

  • Multi-platform: It provides SDK for iOS/Android/Web/Unity. It also offers C++ SDK for iOS/Android and SDK for Admin purpose.
  • Authentication: It supports various providers and user store.
  • Data access: There are several choices for data. Realtime Database, Firestore and Storage.
  • Offline: Support offline mode and synchronization capability when goes back to online for Realtime Database and Firestore
  • Notification: Notify to mobile devices.
  • Hosting and Function: It also provide hosting for static content and Functions.

Key Features for Operation

In addition to Developer Experience, it offers operation features such as:

  • Autoscaling: Some services has auto-scaling features.
  • Staging: Hosting provides staging capability.

Try it!

Unfortunately for C# developers, I couldn’t find an official SDK and tutorial. So in this case, I use Node.js (to try web).

Create firebase project and install SDK

First of all, I need to create a Firebase Project.

1. Go to Firebase console and login by using google account, then click “Add project”.

2. Enter project name and create the project. You can link to GCP Project as well.

3. Open command prompt or console, and run the following command.

npm install -g firebase-tools

Create web application project

Next, create web application project.

1. Run following command to create web application and initialize for firebase.

mkdir firebase-web
cd firebase-web
firebase init

2. Firebase SDK initializes the project. Select Database and hosting.

3. Then, select the firebase project to associate. I can create new project from here but I still need to create firebase project manually in console.

4. Select default option to database and hosting and complete the initialization. Run the following command to serve the application.

5. Access to the URL displayed in to confirm it’s up and running. http://localhost:5000 by default.

6. Stop the service and open the folder via Visual Studio Code.

7. By default, all the scripts are embed in html file. add main.js file to public folder.

8. “Cut” the scripts from index.html where firebase SDK code exists, and link to main.js instead.

9. Create immediate function inside main.js

(function(){

    document.addEventListener('DOMContentLoaded', function() {
         try {
          let app = firebase.app();
          let features = ['auth', 'database', 'messaging', 'storage'].filter(feature => typeof app[feature] === 'function');
          document.getElementById('load').innerHTML = `Firebase SDK loaded with ${features.join(', ')}`;
        } catch (e) {
          console.error(e);
          document.getElementById('load').innerHTML = 'Error loading the Firebase SDK, check the console.';
        }
      });

}());

10. Do the same for css and run “firebase serve” again to confirm it still runs as expected.

Realtime Database

Though there are several other choices to storing data, I use realtime database here as it is the most basic option for my understanding.

1. Firstly, enable realtime database. Go to firebase console and select “database”, then click “get started” for realtime database.

2. Select “test mode” which opens up security for testing and enable it.

3. Click “Add child” to add field.

4. Add “text” field and enter any value.

5. Edit the main.js as following.

(function () {

    document.addEventListener('DOMContentLoaded', function () {
        try {
            let txtDB = document.getElementById('txtDB');
            let dbRef = firebase.database().ref().child('text');
            dbRef.on('value', snap => txtDB.innerText = snap.val());
        } catch (e) {
            console.error(e);
        }
    });
}());

6. Update the index.html body.

<body>
   id="txtDB"
  </div>
  <script defer src="/main.js"></script>
</body>

7. Save all and refresh the page. I can see the value from database.

8. Change the value in database and confirm the change reflect realtime.

Authentication

Firebase supports multiple authentication provider by default. This time, I use Facebook sign-in as I did in Azure. In addition, firebase provides SDK firebase-ui which includes ui for authentication. I use this sdk this time.

1. Firstly, enable authentication on console. Go to Firebase console, and select “Authentication” and click “SET UP SIGN-IN METHOD”.

2. Click “Facebook” check enable. Then add necessary information indicated in the screen.

3. Replace the code in main.js to use firebase auth.

(function () {

    document.addEventListener('DOMContentLoaded', function () {
        try {
            let txtDB = document.getElementById('txtDB');
            let dbRef = firebase.database().ref().child('text');
            dbRef.on('value', snap => txtDB.innerText = snap.val());

            // Attach click event to sign-out button
            document.getElementById('sign-out').addEventListener('click', function () {
                firebase.auth().signOut();
            });

            // Monitor authentication status change.
            firebase.auth().onAuthStateChanged(function (user) {
                if (user) {
                    // User is signed in.
                    var displayName = user.displayName;
                    var email = user.email;
                    var emailVerified = user.emailVerified;
                    var photoURL = user.photoURL;
                    var uid = user.uid;
                    var phoneNumber = user.phoneNumber;
                    var providerData = user.providerData;
                    user.getIdToken().then(function (accessToken) {
                        document.getElementById('account-details').textContent = JSON.stringify({
                            displayName: displayName,
                            email: email,
                            emailVerified: emailVerified,
                            phoneNumber: phoneNumber,
                            photoURL: photoURL,
                            uid: uid,
                            accessToken: accessToken,
                            providerData: providerData
                        }, null, '  ');
                    });
                    document.getElementById('firebaseui-auth-container').style.display = 'none';
                    document.getElementById('sign-out').style.display = 'block';                    
                } else {
                    // User is signed out.
                    document.getElementById('firebaseui-auth-container').style.display = 'block';
                    document.getElementById('sign-out').style.display = 'none';
                    document.getElementById('account-details').textContent = 'null';
                }
            }, function (error) {
                console.log(error);
            });

            // Create Firebase UI Configuration
            var uiConfig = {
                signInSuccessUrl: 'index.html',
                signInOptions: [
                    firebase.auth.FacebookAuthProvider.PROVIDER_ID
                ]
            };

            // Initialize the FirebaseUI Widget using Firebase.
            var ui = new firebaseui.auth.AuthUI(firebase.auth());
            // The start method will wait until the DOM is loaded.
            ui.start('#firebaseui-auth-container', uiConfig);
        } catch (e) {
            console.error(e);
        }
    });
}());

4. Update index.html to include firebase ui sdk. In the head section, add following.

<script src="https://cdn.firebase.com/libs/firebaseui/2.7.0/firebaseui.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.7.0/firebaseui.css" />

5. Then include necessary elements in body.

<body>
   id="txtDB"
  <div id="firebaseui-auth-container"></div>
  <div id="account-details"></div>
  <script defer src="/main.js"></script>
  <button id="sign-out">SignOut</button>
</body>

6. Save all and refresh the browser. I can see Facebook sign-in button.

7. Sign-in to Facebook and confirm I get my login information.

8. Click “SignOut” button to sign out.

9. Go back to Firebase console and go to Authentication | Users. I can see the user I just logged in is created.

Hosting

Now the web application has database and authentication. Let’s deploy it to hosting server.

1. Run following command.

2. Once deploy completed, access to the URL shown as result of deploy command.

3. Go back to console and select “Hosting” to confirm the information.

Messaging/Push notification

Next, add push notification.

Background worker

User should receives notification even when the browser is not active. To do so, I use background worker.

1. Add firebase-messaging-sw.js file under public folder.

2. Add following script.

// 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.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');

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

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

Register device to notification

First of all, I need to know where to send the notification. To do this, I can ask user permission to do so and get unique id.

1. To send notification, I need to get permission from user and track which device I can push notifications. Update the index.html to include buttons to let user subscribe to notifications.

<body>
   id="txtDB"
  <div id="firebaseui-auth-container"></div>
  <button id="subscribe" style="display:none">Subscribe for notification</button>
  <button id="unsubscribe" style="display:none">Unsubscribe for notification</button>

  <div id="account-details"></div>
  <script defer src="/main.js"></script>
  <button id="sign-out">SignOut</button>
</body>

2. Then add scripts inside loaded event. First of all, define each buttons.

let sucscribe = document.getElementById('subscribe');
let unsubscribe = document.getElementById('unsubscribe');

3. Also define messing object

const messaging = firebase.messaging();

4. Add click event listener for subscribe to create subscription to database. getToken function returns device unique id.

subscribe.addEventListener('click', () => {
    messaging.requestPermission()
        .then(() => messaging.getToken())
        .then((token) => {
            if (token) {
                firebase.database().ref('/tokens').push({
                    token: token,
                    uid: firebase.auth().currentUser.uid,
                    name: firebase.auth().currentUser.displayName
                });
                checkSubscriptionStatus();
            } else {
                console.log('No permission granted');
            }
        })
        .catch((err) => console.log(err));
}

5. Add click event to unsubscribe to delete the token from database. This time, get the item from the array and remove it.

unsubscribe.addEventListener('click', () => {
    messaging.getToken()
        .then((token) => {
            if (token) {
                messaging.deleteToken(token).then(() => {
                    firebase.database().ref('/tokens').orderByChild('uid').equalTo(firebase.auth().currentUser.uid)
                        .once('value').then((snapshot) => {
                            firebase.database().ref('/tokens').child(Object.keys(snapshot.val())[]).remove();
                        })
                });
                checkSubscriptionStatus();
            } else {
                console.log('No permission granted');
            }
        })
        .catch((err) => console.log(err));
});

6. Add checkSubscriptionStatus function which checks current subscription status.

// Check the subscription status
function checkSubscriptionStatus() {
    // Check database if user is signed in
    if (firebase.auth().currentUser) {
        firebase.database().ref('/tokens').orderByChild('uid').equalTo(firebase.auth().currentUser.uid)
            .once('value').then((snapshot) => {
                if (snapshot.val()) {
                    unsubscribe.style.display = 'block';
                    sucscribe.style.display = 'none';
                } else {
                    unsubscribe.style.display = 'none';
                    sucscribe.style.display = 'block';
                }
            });
    }
    // Otherwise, hide them all.
    else {
        unsubscribe.style.display = 'none';
        sucscribe.style.display = 'none';
    }
}

7. To make status check works when sign-in and out, add the function inside onAuthStateChanged. Add it at the last line of the event.

messaging.onMessage(function (payload) {
    console.log('Message received. ', payload);
});

9. Save all and refresh the browser. Sign in if not yet and click “subscribe” button and confirm the tokens has value in database side.

10. Click “unsubscribe” button to confirm the value is deleted.

Send push notification

There are several ways to send notification such as using function, but this time, I use postman to simplify the process.

1. Firstly, get the feature. Go to console and select project settings. Then copy “Server key”.

2. Open postman and use following settings.

  • HTTP Verb: POST
  • Header: Authorization: key=
  • Header: Content-Type: application/json

3. Specify body as following. Replace the “to” value with token which stored in database when you subscribe to push notification. You can also change any values. For icon, I use my dev.to icon, and specify click action to localhost address.

4. Open browser and go to http://localhost:5000, then press F12 to open developer console. Then send notification from Postman. You can see the message received in the console.

5. Minimize the browser and send the notification again. This time, you see push notification popup in the OS.

6. Click the notification and confirm http://localhost:5000 is open.

Summary

Phew, it was a long test!!! My opinion after trying both Azure and GCP (Firebase), both platforms have its own benefits.

[Azure]

  • It provides all basic features which mobile application requires.
  • As it uses normal Azure resources and provide easy to understand quick start samples, it was very straight forward to me.
  • It is also easier to extend the service by using other Azure components as, again, it uses normal Azure resources.
  • Luck of mobile specific features such as testing and deploying, which is actually covered by App Center.
  • It supports C# 🙂

[Firebase]

  • It provides all basic features which mobile application requires.
  • It is easy to play with as everything is in one place, however, it is not easy to find if you start from GCP. I hope firebase becomes part of GCP sooner or later.
  • Great samples in GitHub.
  • Provide more useful services for mobile such as testing, advertisement, dynamic link, etc.
  • Less flexibility or a bit more harder to integrate with GCP services.

So, if your project requires C# or windows application support with other services, I strongly recommend Azure. On the other hand, if your project purely for mobile apps or when you need jump start, I recommend GCP as it is easier to organize components with great samples.

I do further research on both services for testing, debugging, deploying, reporting and analyzing in the future.

References

Web push notification with Firebase
Firebase on the Web – Tutorials

Source

https://dev.to/kenakamu/azure-vs-gcp-part-18-mobile-app-development-gcp-2j1h