Introducing native behaviours to embedded webs in apps
There is a never ending discussion about mobile native development and web/hybrid development. Actually, we can find a lot of interesting articles about it, such us:
Mobile developers tend to prefer native app development instead of web or hybrid apps. Several managers will choose the opposite. So, what is the best option then?
Analysing the whole picture to make a decision
There isn’t a perfect solution for all the companies. Every case should be analysed independently before making a decision. Actually, without understanding the whole picture, the decision cannot take place. We need to be able to answer at least these questions before that:
- What is the cost difference between developing native apps (iOS & Android) versus web/hybrid ones?
- Can the company assume that cost?
- Do we have the knowledge to achieve it?
- Can the company hire people to fill the gap if required?
- Which are the real differences from a customer perspective between both developments?
As you might notice, these are just a representative set of question we should understand first. For example, it makes no sense to force a start-up (which has a very limited budget) to develop an app for iOS & Android before testing if the product is really interesting to the audience and it can create a business case. Even the opposite case, an international company should not think that money is unlimited and they can do whatever they consider: Resources are always limited.
From my own experience, I have been working for several companies and I found scenarios where the best decision was different from other ones. For example, in my current company we built a retail application where we sell a lot of different products. As it is a private community, we are focused on delivering a very good customer experience, so the native development was the right decision as company was able to generate benefits to build it on three platforms (Android, iOS & Web).
But then, after a huge cost on the payments development for web, company realised that maybe the effort is not valuable for mobile (connecting to so many different payments API in any platform), because payments are always being changed and it is not affordable to change it for three platforms in a short time. So, the decision was that payments would remain as an embedded web for native development. But, how can we keep the focus on the customer experience? What did we do?
Introducing a Communication Framework
Even though that we needed to include the payments as an embedded web view, we decided to enrich the experience by giving a native behaviour to the embedded web. But how?
We present the web view during the checkout process, but we are also showing some native components, such us the Toolbar (Navigation Bar for iOS) to control the navigation. Actually, that toolbar should manage the back button based on the presented content on the web, but also should show a close button or not based on the checkout step the customer is (to avoid issues like the cart dilemma).
So we decided to implement a communication framework which allow us to communicate between native & web code. It consists on an interface between the web JavaScript code and client-side (Android/iOS) code. By doing this, we are allowing the web itself to launch native code, so we will the web the responsibility to control how the Toolbar (Navigation bar) should be configured at any time.
Defining the data layer
Firstly, we need to define the protocol to include the information we will send from the web to the native code. We decided to go on a simple JSON. For example, we can consider that we have a CommunicationFrameworkData which contains a navigationBar which is a JSON structure which will contain all data related to toolbar configurations for mobile devices:
- backUrl — So when the app user taps on back, the app performs a custom forward navigation to the specified url
- navigationTitle — So the native title is updated according what webview page is loaded
- isBackButtonVisible — It will control the back button on the left side of the toolbar
- isCloseButtonVisible — It will control the close button on the right side of the toolbar
So one example might be:
Sending the data from the web
Secondly, we need to include the code into the web which will send the info when we consider (in our case, when page is loaded). For that, we need to agree on the JavaScript interface name. For this example we can define it as mobileCommunicationFramework. Then, it is just a matter to access that interface and post the JSON:
We can redefine the postMessage for Android, but as it is blocked for iOS, we decided to call both with the same nomenclature. Anyway, having it in a method for posting the info for both platform would be ideal.
Receiving and processing the data on Android
Once web is sending the data, we just need to register our Android native code to receive these calls. For that we need to add the JavaScript connections.
Summarising, we just need to enable JavaScript and add the JavaScript interface to the WebView. This will include a callback where we will have defined with the annotation @JavaScriptInterface the postMessage method.
With the previous example, anytime the web dispatch a postMessage call, this native code will be executed. In our example, we will update the Toolbar with the values from the JSON, but it is up to us to decide more things to consider, not just the Toolbar.
Receiving and processing the data on iOS
Similar to Android, we need to connect the JavaScript calls to iOS native code.
For that purpose, we can define our protocols where we add the script message handler. Actually, in this case, the message handler has by definition the postMessage method, so we cannot change it (as we can on Android). Then, we can simply check the message type and use a decoder to get our data and be able to process it.
Conclusion
We cannot think that always a native or a hybrid development is the best option. We need to analyse each case to detect in an agile way which development is the best one for a specific case based on the development but also in the maintainability.
We don’t have to go for a full native/hybrid case. We can find the perfect balance between both worlds and even try to add native behaviours when using embedded web views, so we can control some native elements from the web itself. And JavaScript is helping us there a lot by opening a door to execute native code from the web.