DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide
  • Scaling Mobile App Performance: How We Cut Screen Load Time From 8s to 2s
  • Interrupt Testing: Bulletproof Your App for the Real World
  • In-App Browsers in Mobile Apps: Benefits, Challenges, Solutions

Trending

  • How Kubernetes Cluster Sizing Affects Performance and Cost Efficiency in Cloud Deployments
  • How To Introduce a New API Quickly Using Quarkus and ChatGPT
  • How to Merge HTML Documents in Java
  • Creating a Web Project: Caching for Performance Optimization

Offline web applications: a working example

By 
Giorgio Sironi user avatar
Giorgio Sironi
·
Sep. 01, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
37.4K Views

Join the DZone community and get the full member experience.

Join For Free

What happens in the debate for a native application vs. web application in the case offline usage comes into play? Surely you can't use a web application if you do not have an active connection for loading it.

With the boatload of innovations in the HTML5 and related specifications, this has changed. In a few Pomodoros (3 half hours) I could learn how to code a web application able to run in a stable browser like Firefox 5 without a network connection.

What this application does?

Since it serves as an example for this post, it simply loads a remote .php file which changes often, and that represents for example a stream of data such as Twitter's newsfeed.

When the connection is not available, the application displays the data from the last time it was able to connect to the server. Of course, while it is offline it could do anything from slicing bread to executing arbitrary JavaScript code: the point was showing a web application working from the cache and able to recognize that it is currently offline.

This is the first time you load it: index.html is downloaded and it makes an Ajax request for the news feed.

 

If you refresh the page, the browser caches some content I have chosen (index.html), but still the news feed can be downloaded via Ajax:

 

If now you cut the network cable, and refresh again, the application becomes aware that it's offline and retrieves a saved copy of the news (of course it can do anything you can code in JavaScript):

 

What technologies you have used?

First of all, the cache manifest from the Offline Web applications part of the HTML5 specification. With this manifest, I was able to specify that some file should have been cached for offline usage (my page containing JavaScript code and its style sheet). At the same time, other files were listed as always to be loaded from the network (my news feed and some other machinery).

Another crucial technology is the Web Storage, in this case the localStorage JavaScript object which serves as a database for storing the last newsfeed retrieved via Ajax.

And of course I've used Ajax both to retrieve the news feed from my cached main page (that is never reloaded), and to ping the server to check if the connection is really available or if we are just in a LAN.

Which browser you used?

I used Firefox 5, and you need to be aware of a few issues if you want to develop an offline web application.
The cache you have to clear in case you want to reset the application after some changes to the code is in Options (or Preferences on Linux) -> Advanced -> Network tab, at the label "The following websites have stored data for offline use".

Firebug will continue to show HTTP requests as if you were connected to a real server, a value in the Remote IP column; even with localhost, an IP address is usually shown when the connection is really established.

You should check File -> Work offline to simulate being offline, since interrupting the connection won't work while loading from localhost or another hostname pointing to 127.0.0.1.

Which resources you have read?

The wonderful online (and not) book Dive into HTML5 by Mark Pilgrim, which has an introductory chapter on the topic.

A guide from Mozilla about offline resources, which has more examples of cache manifest lines.

This Ed Norton's article about detecting the switch between online and offline status with a real ping, since the JavaScript API cannot be trusted in many implementations.

Show us the code!

Yep, I was going to do that. However there's a repository containing it all if you want to play with it.
First of all, I have an .htaccess file which will work on Apache webservers:

AddType text/cache-manifest .manifest
ExpiresActive On
ExpiresDefault "access"

The first line is necessary to serve the manifest with the right MIME type. The other two are to avoid any caching on the web server (it's already done in the browser), and develop without hassles. It's not a production setting: in that case it should target only the manifest.

Here is my manifest:

CACHE MANIFEST
NETWORK:
/news.php
/ping.js
CACHE:
/style.css
http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js

I only used 2 of the 3 available sections. What is in NETWORK will always be loaded if requested, what is in CACHE will always be cached.

My main page:

<!DOCTYPE HTML>
<html manifest="/cache.manifest">
<head>
    <title>My offline web application</title>
    <link rel="StyleSheet" type="text/css" href="style.css" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
        $(document.body).bind("online", checkNetworkStatus);
        $(document.body).bind("offline", checkNetworkStatus);
        checkNetworkStatus();
    });

    function checkNetworkStatus() {
        console.log('I am checking');
        if (navigator.onLine) {
            // Just because the browser says we're online doesn't mean we're online. The browser lies.
            // Check to see if we are really online by making a call for a static JSON resource on
            // the originating Web site. If we can get to it, we're online. If not, assume we're
            // offline.
            $.ajaxSetup({
                async: true,
                cache: false,
                context: $("#status"),
                dataType: "json",
                error: function (req, status, ex) {
                    console.log("Error: " + ex);
                    // We might not be technically "offline" if the error is not a timeout, but
                    // otherwise we're getting some sort of error when we shouldn't, so we're
                    // going to treat it as if we're offline.
                    // Note: This might not be totally correct if the error is because the
                    // manifest is ill-formed.
                    showNetworkStatus(false);
                },
                success: function (data, status, req) {
                    showNetworkStatus(true);
                },
                timeout: 5000,
                type: "GET",
                url: "ping.js"
            });
            $.ajax();
        } else {
            showNetworkStatus(false);
        }
    }
    
    var currentlyOnline = null;
    function showNetworkStatus(online) {
        if (online != currentlyOnline) {
            if (online) {
                $("#online_status").html("Online");
                $('#news').load('/news.php', function (response) {
                    localStorage.setItem('news', response);
                });
            } else {
                $("#online_status").html("Offline");
                $('#news').html(localStorage.getItem('news'));
            }
            currentlyOnline = online;
        }
    }
    </script>
</head>
<body>
<p>Hello, world!</p>
<div id="news"></div>
<div id="online_status"></div>
</body>
</html>

The <html> element has an attribute pointing to the manifest, and the file loads other resources from the cache like jQuery and the style sheet.

The checkNetworkStatus function is called upon relevant events from the JavaScript API and at the startup: it makes a ping to the web server to verify the connection is open.

The showNetworkStatus function instead executes an action in case the status of the connection changes:

  • it updates the Offline/Online label at the bottom of the page.
  • In the online case, fills the #news div with updated text retrieved by Ajax (saving it).
  • In the offline case, fills the #news div with the last text saved.

ping.js is an empty file:

{}

news.php constantly updates to show the effects of being again online.

<?php
echo '<p>Last update: '. date('Y-m-d H:i:s') . "</p>\n";
?>
<p>Lorem ipsum dolor amet...</p>

Conclusion

We're finished. It's feasible and easy, at least for the base case, to deploy to a desktop or mobile platform which can be used even while offline (but of course it would sync with the server only when the connection is available.) Not good times for native applications...

mobile app

Opinions expressed by DZone contributors are their own.

Related

  • How to Build Scalable Mobile Apps With React Native: A Step-by-Step Guide
  • Scaling Mobile App Performance: How We Cut Screen Load Time From 8s to 2s
  • Interrupt Testing: Bulletproof Your App for the Real World
  • In-App Browsers in Mobile Apps: Benefits, Challenges, Solutions

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!