In the present world, access to information is an essential need. We want to get hold of all the facts and factoids within an instant, irrespective of time or location. The most feasible ways to do these are via web and mobile apps.
Suppose you are searching for some medications in a medical store, or trying to book a hotel online , or perform some banking transactions, It would be of beneficial to have a mobile app supporting these necessary activities. But in a situation where the internet is not available, the app becomes useless. So just having the mobile app won’t be a solution. It would be useful if some of the static content or basic information of the app are accessible when you have gone offline.
In order to do so, we will ask the user, to sync the app time to time. On successful syncing, data will be stored into the device’s internal storage or SD card. It can be retrieved and used whenever it is necessary.
Let us explore how we can achieve offline syncing step by step using ionic framework.
Offline Syncing
In general, offline syncing can be of two types –
Offline Data Syncing
Data syncing can be done by storing the data and its assets from API into the browser’s local storage,after the user agrees to sync. There can be 3 prevalent cases:
Syncing can be done once the user is online, to stay up-to-date with the current content. If some new data are inserted, we will be downloading and storing them into the local storage. If some data are removed from database, we will be removing it and its assets from local storage.
This method is followed, if the data is subjected to frequent change from time to time. To let the user stay updated with the latest content, we will download the overall data each time the user decides to sync the app.
A field is created in the local storage where the data will be stored. Let us name it as ‘guide’.
angular.module(‘myApp’).constant('LOCAL_STORAGE_KEYS', { guide: 'guides', });
The data object to be stored (let us call it ‘guides’) is converted into JSON text and the JSON text is stored in string format.
window.localStorage[LOCAL_STORAGE_KEYS.guide] = JSON.stringify(guides);
In case the database gets modified and some previously used data were eliminated , we need to exclude those from the local storage. For such purpose there must be a primary key, with respect to which, the local storage objects will be compared. Let us consider “id” as primary key. Each guide will have an unique guide id associated with it.
We are introducing a new field called “sync” and marking it “true” for each matching id between the local storage and api data. Now the objects which does not have sync “true” are deleted and the updated data is stored in the local storage again. Later the sync field is removed.
var guides = window.localStorage[LOCAL_STORAGE_KEYS.guide]; if (!guides) { guides = JSON.stringify({}); //creating an object notation } guides = JSON.parse(guides); if (Object.keys(guides).length) { //For removing data that has been not send from API DataObject.forEach(function(eachGuide) { if (guides[eachGuide.id]) { guides[eachGuide.id].sync = true; } }); angular.forEach(guides, function(value, key) { if (value.sync) { delete value.sync; } else { delete guides[key]; } }); // The updated data is stored into the local storage again window.localStorage[LOCAL_STORAGE_KEYS.guide] = JSON.stringify(guides); }
We need to download the new data as well, and store into the local storage.
a) First we store the id of the new data into an array called downloadedId.
var downloadedId = [ ]; angular.forEach(DataObject, function(valueApi, keyApi) { if (!guides[valueApi.id]) { downloadedId.push(valueApi.id); } });
b) Now we call the API with respective id’s and store the resulting data into the local storage.
angular.forEach(downloadedId, function(value, key) { API call(value) .success(function(data) { guides[value] = data; }) .error(function() { //error code }) .finally(function() { window.localStorage[LOCAL_STORAGE_KEYS.guide] =JSON.stringify(guides); }); }); //for each ends
Offline Image Syncing
For image assets, they are stored in file system of the device. We need two cordova based plugins for this purpose. They can be installed as follows:
There are multiple valid locations to store persistent files on an Android device. To store it in phone memory we need to set preference in config.xml as
<preference name=”AndroidPersistentFileLocation” value=”Compatibility” />
For iOS, we store into the Library directory of the app. The preference is set as:
<preference name=”iosPersistentFileLocation” value=”Library” />
Creating file storage name
We need to create the folder name, in which the images will be stored. This can be your project name, or any other identification name for the folder you prefer. Let us go with the name ‘AppImages’
angular.module(‘myApp’).constant('LOCAL_STORAGE_KEYS', { app: 'AppImages' });
Storing in phone memory
We are using factory in angularjs to create the download image function.
var app = angular.module('app', [ ]); app.factory('saveImage', function(LOCAL_STORAGE_KEYS, $q, $ionicPlatform) { return { downloadImage: function(url, fileName) { var deferred = $q.defer(); window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) { fs.root.getDirectory(LOCAL_STORAGE_KEYS.app, { create: true }, //success callback function(dirEntry) { dirEntry.getFile(fileName, { create: true, exclusive: false }, function(fe) { var p = fe.toURL(); //valid url path on device fe.remove(); var ft = new FileTransfer(); ft.download(encodeURI(url), p, function(entry) { if (entry && entry.toURL) { deferred.resolve(entry.toURL()); } else { deferred.resolve(); } }, function(err) { deferred.reject(err); }, false, null); }, function() { deferred.reject(new Error('get file failed')); } ); }); }, function() { deferred.reject(new Error('get directory failed')); }); return deferred.promise; } }; });
Now, we need to call the downloadImage() function from our controller, in order to the receive the local URL of the image files. The actual URL’s need to be replaced by the local URL path, and then it is stored into the browser’s local storage. In offline session, along with textual data, local image URL will be fetched from the local storage and shown in our app.
saveImage.downloadImage(imageURL, imageName) .then(function(localURL) { var img; img = img.replace(‘actualURL’, ‘localURL’); })
One constraint of using local storage is the limitation in storage space. It has maximum storage capacity of 15MB to 20MB. For storing large amount of data, local storage capacity will get exceeded. For more details on storage capacity of local storage you can visit the link increase local storage capacity. Also in case of storing audio or video files in phone’s internal memory or SD card, insufficient memory will fail to store such files.
Conclusion
We can have lot of benefits from offline storage like increased app performance by caching server data locally on device. Network usage can be limited everytime user uses the app.Hence your ultimate aim for building a robust app, becomes successful.
I have recently used this technology for my latest ionic app, and it works like a charm. Hope this helps you in your app development process as well.
Feel free to provide suggestions and queries in form of comments below.