The Unknowns of PWA App

Designing a PWA is very easy. Just add manifest file and you are done. But there are some pointers which you should know about before deciding whether to build a PWA app or a native app. As my hobby project, I decided to build a PWA called Chibaree. The app is for small kids to know the world by pictures. It is built in ReactJS. You can open it on your Chrome mobile browser and experience it. It is still in the development stage, but I thought it would be good to share my experience about the hurdles I faced.
Performance Score
You are well aware that Google ranks sites based on factors like mobile responsiveness and performance. Having both improves search results, which really matters when you want to increase the visibility when no one knows about your app.
You can check how well your app scores using Lighthouse. I insist on checking the score on PageSpeed Insights from Google and NOT on localhost. It uses Lighthouse behind the scenes, but it will use insights based on data from your actual users around the world and user’s experience. If it doesn’t have enough data (e.g., users have not started using your app) then it will use its default configuration. It is the same as testing on a browser with a live URL.
To test it using PageSpeed Insights, you need to host your site somewhere, like GitHub pages, which uses HTTPS protocol. In short, you will get a real score. If you test it on localhost then it might give the wrong performance score because of your machine’s configuration.

Even though my app is small and lightweight, the overall score is just 45. It’s bad and I am working on it to take it beyond 80. The real reason behind the poor score is LCP (Largest Contentful Paint). It is a metric that measures how much time it takes to paint the largest element on a page it loads. In my case, the largest element is an image. You can explore the importance of each metric with quick help from Google. Why is this metric so important? Because of its weightage in calculating performance scores. It is 25%. If you improve this score, then your other scores will also improve automatically. The last column in the below image represents the weightage of different metrics.

So, what should I do? Should I remove images from my page to improve the LCP score? Well, I cannot do that because my use-case doesn’t allow me to do so. Another question you might ask is what’s the matter with images. The short answer is that there is nothing wrong with images or their sizes or anything related to it.
The main problem is when it starts painting those images. This process happens after 4.5s, based on the test report. Then what consumes initial 4.5 seconds? This time is spent loading JS and CSS bundles from the server. Out of those 4.5 seconds, a good amount of time is spent in loading one big bundle and that is of third-party libraries I have used.

If all the bundles, including third-party packages, get loaded in 1 second, then my overall score would jump to more than 80. But how to reduce the loading time of bundles? Load them when needed. Of course, I have used the lazy loading feature of React Router to load feature modules when a user visits corresponding pages. I can lazy load what I have created and NOT what others have created. Here I mean to refer to third-party packages.
Recently, I have learnt that we can also lazy load third-party packages. Once I complete the implementation of it, I will discuss about the approach in another article.
Another way to improve scores is having less DOM. If your layouts are different for mobile and desktop, I recommend you to use the device-detect library. Through those load components based on devices. Do not use CSS properties to show/hide layouts. Earlier I was using this approach and my score was 28. Even though the content is not painted on the screen, the DOM still exists and it is considered in performance score calculation.
App Packaging
No matter how much effort you spend on building your app, without an audience it’s waste of time. You need to reach out to people in as many ways as possible. Luckily that has become easier now with PWA apps.
Installing PWA is one of the major drivers in convincing developers to avoid creating native apps if the look and feel of the app are going to be the same on the website and app. But that is good for developers. What about actual users?
Browser
Support for installing PWA through Chrome (on mobile) is much better than other browsers. Apart from all the good features — app icon, offline support, faster, linkable — the one which I liked most is Richer Installation.
You can now add your app’s screenshots to enhance the installation experience. This experience should not be taken for granted. It is the entry point for your app. Just add an array of images with their size and type. As per the guidelines, the Width and Height of the image must be at least 320px and at most 3840px. Also, at the moment, only PNG and JPEG formats are supported. GIF is expected in future.

Play Store
I asked my friend to download the app for feedback. He quickly opened Play Store but could not find the app. Of course, I was expecting him to download it from the browser. I had to explain the whole PWA technology to make him understand why he needed to download it from the browser. I just laughed at myself. Rather than taking users to the app, I had to take the app to users. I quickly started working towards making my app available on Play Store, App Store and Microsoft store. I have completed the Play Store part and will finish the rest soon.

Let me be very frank, if you want your app to feature on all stores, you need to start at least one month early. It requires a lot of efforts. However, there are some pointers which you need to consider while packaging app for various stores. Below are specific to Play Store. We will cover rest in another article.
Package Builder
You can create a package either through Bubblewrap from Google or PWABuilder from Microsoft. Bubblewrap is a CLI tool, so if you are comfortable with commands, then you will like it. One thing I didn’t like about Bubblewrap is that if your app doesn’t have a good performance score (remember what I said earlier?), it won’t generate .assetlinks.json file.
This file helps you to hide the url bar when you open the PWA app installed through the Play Store else it will give you a browser feeling. But why? It is required to claim ownership of your app otherwise someone else would create an Android app for your app. For that reason, you need to deploy this file on your server at the root level of the code inside the .well-known directory. The below screenshot shows that .apk and .aab packages are generated but .assetlinks.json could not due to failure in achieving the performance score.

Other things you need to take care of are that you must have JDK and Android tools on your system. If you don’t have them, Bubblewrap commands will install them for you. Do not try the manual approach. Again, using this tool, you will be able to generate packages for Play Store only.
Another way to create a package is through PWABuilder. This is the simplest way to get the job done in a few minutes (if you have everything ready). I recommend it. Behind the scenes, it uses Bubblewrap.
No matter what build tool you use, you still need to meet the PWA Score criteria. This is different from the performance score. The good thing about PWABuilder is that it just counts PWA Score and not performance score to create a package.

You can use PWABuilder for all stores.

Below files will be generated for Android.

Trusted Web Activity (TWA)
In a native app, if we want to display web content, then we use web view. But it has some limitations. It cannot access the web state (content, cookie, storage, etc). Also, the performance varies based on the Android OS version.
To extend the capabilities of the web view, Google introduced Trusted Web Activity. An activity (a screen) serving the web content over a trusted (HTTPS) channel. It can serve the content in full screen, read web state and is lightweight. This same TWA is used in PWA. In short, the app we use after downloading from the Play Store opens TWA. One of the features mentioned above, reading web state, is more promising in terms of PWA.
Suppose a user logs in to the app from a browser and then he downloads the app from Play Store. When he opens the app, it won’t ask for the login again. Why? The downloaded app can read the web state and thus share the same state. This gives a seamless experience.
App Publishing
Once the package (.aab) is ready, you can create your developer account on Google Play and fill up all the necessary details. One roadblock you might encounter is Google WILL NOT approve your PWA app if your app falls in the Education category and is meant for kids aged lower than 13. The app designed for lower than 13 age group falls in Family Library. The cause for this is like your own friend becomes your enemy. I mean to say, unlike native app which requires approval on every app update, PWAs don’t need to go through such process as it’s a web based app.
This same benefit turns to disadvantage for Education category. Because you might launch an app with good cause but what if after Google approves your app and then you change your app content completely? As per the recent discussions on various forums, this policy might change in future, but till then I suggest either you launch your app for 13+ age group or create native app. This is one thing that I was not aware of from the beginning else I would have gone with native app approach. But considering other advantages of PWA, like supporting all platforms, I don’t regret the decision I took.
App Size
One benefit of PWA that I clearly see is the app size. It is the size of your package and not the application. Because your application still runs on TWA of Chrome browser which is already installed on the device. You can take advantage of this and name your app “<app name> Lite” to attract the audience.

Translation
This is a blessing in disguise feature. As my app is multi-lingual, Chrome suggests auto-translation. I have not done anything special for it, but this feature has played well on my part.
Native App Feeling
Accidental Selection
While using the app if you press it longer on any text then it will suggest copy-paste option. This might give a browser-based feeling.
Zooming
As it is a web app, you can zoom in and out. It is good in my case where the user can zoom in on an image. But it might not be in other use cases.
Scroll Effect
The real differentiator between native and web app is scrolling. I believe the speed of scrolling is slow in the web app. If your app has long-list screens and those screens are the most used ones, then do consider this aspect. It is not that every user will notice it.
Local Storage
If you store any user activity data in local storage then it might be tricky. Every time you change JSON object structure, you need to recreate it on local storage. For example, in my case, I store game scores in local storage. After a few months, I decided to change the structure. Those who installed the app after this change didn’t face any issues. But those who were already using the app did face it. The code to read updated JSON didn’t work with the old structure, which is quite obvious. So, you need to migrate your local data as well based on the app version.
The best practice is to store as much data as you can on a database server where migration is a little easier.
Splash Screen
You need to establish an emotional connection with your users and for that, you can take the help of a splash screen. If you have a logo and background colour configured in your manifest file, then Chrome will generate a splash screen automatically for you. But this is not up to the mark. And custom splash screen is not supported yet.
Conclusion
It is not an easy decision whether to go PWA or the native app route. If your criteria is performance, then a native app will be a good option. You can still have some screens in the native app as web screens using TWA. However, if you think most of the users would use the web app, then PWA can become your choice as it will save development efforts and real money.