One thing every web developer should know: no-cache headers

Making coding changes and reloading locally hosted web pages over and over again is a pattern familiar web developers world wide. Another familiar pattern is to constantly wonder if your changes are caching in the browser and not being properly reflected in what you are seeing.

Fear not…there is a very easy fix for this and it doesn’t involve using the browsers empty cache options every single time between page reloads. Simply tell your local web server to send the browser a “no-cache” pragma directive in the HTTP header and then you should be good-to-go.

Once you make this change every web page you serve locally will automatically refresh, every single time. Here’s what the W3C has to say about no-cache headers:

 When the no-cache directive is present in a request message, an application SHOULD forward the request toward the origin server even if it has a cached copy of what is being requested. 

Make the change in Apache. Here’s how you make the change in your /etc/apache2/httpd.conf file on the latest Mac OS running 10.8+. Depending on how your machine is set up you can run the command “sudo pico httpd.conf” then enter your admin password and use the short cuts listed at the button of the pico window or use the ‘up’ and ‘down’ buttons on your keyboard to navigate around the file. Typically, the following text is pasted below any other ‘filesMatch’ tags that may reside in the configuration file. Once you are done be sure to restart apache. On Mavericks the command is “sudo apachectl start”:

<filesMatch "\.(html|htm|js|css)$">
    FileETag None
<ifModule mod_headers.c>
    Header unset ETag
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
</filesMatch>

Make the change on IIS 7. If you want to make the change on Windows 7, Windows 2008/2008R2 or Vista then here is a link to Microsoft Technet. If you are using IIS Manager, in Step 4 choose the expire immediately options. Or, if you are using the command line copy this line and run it:

    <b>appcmd set config /section:staticContent /clientCache.cacheControlMode:DisableCache</b>

If you have some other operating system version hopefully you get the idea from the suggestions above and apply similar changes for your system.

Optimizing your own public web server cache settings. One last note, the no-cache header setting is typically only used in a development environment. To get the best page performance for your visitors you should allow some browser caching. If you want to learn more about optimizing browser caching here is a good article.

References

Optimizing Headers (Google)
RFC 2616, Section 14 Header Field Definitions
Configure HTTP Expires Response Header (IIS 7)
Manipulating HTTP headers with htaccess (you can make the same no-cache header change in httpd.conf in Mavericks)

What all mobile web devs should know about PhoneGap

If you already building or looking into getting started with mobile web applications you should understand the basics of PhoneGap. The name ‘PhoneGap’ is widely recognized, and perhaps more widely misunderstood.

The nudge to write this article was born out of conversations where we stumbled across concrete limitations to modern responsive JavaScript libraries such as bootstrap and jQuery. Limitations that cannot be overcome by adding more brilliant functionality because some JavaScript capabilities simply do not exist within the browser today. Furthermore, other requirements were imposed by political realities, timeframes and expectations.

That’s where PhoneGap steps in. 

So what, tell me what PhoneGap does?

PhoneGap is owned by Adobe and it has an open source top-level Apache Foundation sister project called Cordova. I won’t bore you with its long and twisted history, you can read about it here if you want.

The bottom line is PhoneGap allows you to develop JavaScript mobile applications that have access to certain aspects of the native device such as writing data to a filesystem. Your web application is wrapped within a native mobile application container that gives you JavaScript access to native operating system capabilities beyond what the browser itself is capable of doing!

By native I mean iOS Objective C, Android Java, WindowsPhone, Windows 8, Blackberry 10, Amazon Fire OS and Tizen. Your JavaScript applications runs in a chrome-less browser that gives you special hooks to the operating system. You can also submit PhoneGap applications to the AppStore, Google Play and others.

Who uses this stuff, well you may be using a PhoneGap app from one of these online stores and not even know it. To mention a few: Southwest Airlines and many others.

What limitations can PhoneGap address that responsive libraries don’t?

If your requirements call for all or most of the following items, then PhoneGap is the correct choice for your project today. That may change as HTML5 continues to rapidly grow, but for now I’m sticking with the following bullet points. Stick with me and read through all of these before starting to throw out counter arguments.

JavaScript skillz. If you are an existing JavaScript shop, then PhoneGap leverages your existing JavaScript skills to access capabilities beyond current browser functionality without the need to have an in-depth understanding of Objective C or Java.

Sure, it’s easy to say you can hire expert contractors to develop iOS and Android applications, along with UX designers and testers. But, if your budget doesn’t include the capital costs for these folks and all you have is JavaScript ninjas on staff then the choice is easy.

Or, maybe you have genius-level developers that could easily and quickly spin up on all your need to know on ObjectiveC and Java Android. If this isn’t the case, and your timeframes and budgets don’t allow for this then you’ll need a fallback plan such as PhoneGap.

Access to camera.  Yes, you can currently access the camera on some web browsers today. However, the support on mobile browsers is still inconsistent, limited or non-existent. On the other hand, native device OS’s are expected to have access to cameras If they didn’t it would be considered a serious oversight. PhoneGap provides cross-platform mobile device access to the camera.

Read/write access to SD Card. Just to reiterate, this is both read and write access to a local storage device. Certainly there is a FileReader API in plain old JavaScript, but as far as I know there isn’t a FileWriter or its equivalent yet. If you need the write access to go along with read capabilities then you should be looking at PhoneGap.

[Correction Jan. 27, 2014] I mis-wrote. The FileWriter API exists however it has limited supported across browsers: http://caniuse.com/#search=filewriter. And, examples of it’s use can be found here.

AppStore or Google Play. If you have a requirement to submit your application to the app store then PhoneGap will help you get there. There is no way today for submitting a stand-alone web application for acceptance on AppStore or Google Play. Period. Some will argue that the need for using these online application stores is going away, but that’s a non-issue if you have been directed to meet this requirement a.s.a.p. and your job depends on it. If that’s the case, then PhoneGap will be your friend.

Is there anything else I should know?

Yes…First, PhoneGap is not perfect, but then again few software projects are perfect. You will need to install and know a few things about the native IDEs you want to support. If you want to deploy Android you’ll need to install Eclipse or IntelliJ. For iOS you’ll need to install XCode. Etc. You still have to compile a native project or you can try your hand at Adobe’s PhoneGap Build, which is a cloud based build system for PhoneGap.

It is confusing that there are two projects that share a common/similar code base: PhoneGap and Cordova. Also, Cordova’s documentation has typically been more up to date that Adobe’s. If you do your research you’ll find various performance complaints and bug issues (like I just said are there any software projects that don’t have these??).  Yet, overall it’s a great starting point if you have the needs listed above, and it’s much better than trying to start from scratch given today’s dramatically shortened delivery expectations.

You can absolutely still use bootstrap, jQuery and other JavaScript libraries within PhoneGap. There are caveats, of course, related to application life-cycle issue, navigation as well as App Store and Google Play user interface acceptance guidelines.

If you want to add functionality to PhoneGap because you find some critical thing is missing that you need for your project, the good news is you can develop a custom plug-in.

Last, I should mention Titanium Studio. It also lets you leverage JavaScript skills, with the primary difference being that it converts JavaScript into native byte code rather than just displaying it in a chrome-less view.  Plus it’s comes with its own IDE and MVC Framework.  I’ve never used Titanium so I can’t judge it, however I know people who do use it successfully and love it. It’s one more thing to consider that you should be aware of.

References

Cordova Documentation

PhoneGap Documentation

PhoneGap Platform Support

Using Custom Events in Android Apps

There are two major concepts that provide a foundation for building scalable, native Android applications: loosely coupling requests and responses via events, and moving CPU intensive operations off the main thread. This post looks at events. It seems the online documentation on putting together all the pieces of  using custom events is sparse, at best. I’ll show you one example of how to put all the pieces together to create, dispatch and listen for custom events.  The end result is you will be able to decouple your application and make them more flexible and much less likely to break.

I’ve talked about event-based architectures before, and I think they are even more important when building applications for devices. They give you the ability to take into account processor delays and inconsistent internet connections. Between the three pieces of working with custom events described below you should be able to get up and running pretty quickly. I don’t go into much detail on what’s inside the various example as you can find those individual details by searching for them. It’s putting it all together that’s typically the hardest part.

The Event Class. Here’s an example of the content of an Event Class. I’ve taken this several steps further than most examples to include showing how to handle multiple Event types, which are accessed in this example as enums, and implementing multiple listeners. You can also extend your listeners with additional information of just about any type. In this example, I show using String’s for passing messages, but you could just as easily use custom Objects. This should give you a more realistic example of what goes into a commercial application.

	public class MapViewControllerEvent extends EventObject{

		private static final long serialVersionUID = 1L;

		public MapViewControllerEvent(Object source){
			super(source);
		}
	}

	public enum MapViewEvent{
		/**
		 * Connection to the internet has been lost.
		 */
		CONNECTION_LOST("Connection to the internet has been lost."),
		/**
		 * Connection to the internet has been restored.
		 */
		CONNECTION_RESTORED("Connection to the internet has been restored"),
		/**
		 * The LocationService has shutdown. Check logcat for errors.
		 */
		LOCATION_EXCEPTION("There was an unknown error related to the LocationService"),
		/**
		 * Indicates the LocationService is initialized and ready.
		 */
		LOCATION_INITIALIZED("The LocationService has been initialized. NOTE: it still may fail after a start() attempt."),

		private String description;
		private MapViewEvent(String description){
			this.description = description;
		}
	}

	public interface MapViewControllerEventListener extends EventListener{
		/**
		 * Indicates there has been a location change received from LocationService.
		 * @param event
		 * @param message
		 */
		public void onLocationChangeEvent(MapViewControllerEvent event,String message);
		/**
		 * Indicates whether or not device has internet connectivity.
		 * @param event
		 * @param message
		 */
		public void onConnectionChangeEvent(MapViewControllerEvent event,String message);
	}

	protected EventListenerList eventListenerList = new EventListenerList();

	/**
	 * Adds the eventListenerList for MapViewController
	 * @param listener
	 */
	public void addEventListener(MapViewControllerEventListener listener){
		eventListenerList.add(MapViewControllerEventListener.class, listener);
	}

	/**
	 * Removes the eventListenerList for MapViewController
	 * @param listener
	 */
	public void removeEventListener(MapViewControllerEventListener listener){
		eventListenerList.remove(MapViewControllerEventListener.class, listener);
	}

	/**
	 * Dispatches CONNECTION and LOCATION events
	 * @param event
	 * @param message
	 */
	public void dispatchEvent(MapViewControllerEvent event,String message){
		Object[] listeners = eventListenerList.getListenerList();
		Object eventObj = event.getSource();
		String eventName = eventObj.toString();
		for(int i=0; i<listeners.length;i+=2){
			if(listeners[i] == MapViewControllerEventListener.class){
				if(eventName.contains("CONNECTION"))
				{
					((MapViewControllerEventListener) listeners[i+1]).onConnectionChangeEvent(event, message);
				}
				if(eventName.contains("LOCATION")){
					((MapViewControllerEventListener) listeners[i+1]).onLocationChangeEvent(event, message);
				}
			}
		}
	}

Setup Listeners. Here’s how to set up the listener in your Activity. As an example, I called my Event Class MapViewController, but you can name it anything you like:

_mapViewController = new MapViewController(this);
_mapViewController.addEventListener(new MapViewControllerEventListener() {

	@Override
	public void onLocationChangeEvent(MapViewControllerEvent event,
			String message) {
		String eventName = event.getSource().toString();
		if(eventName.contains("EXCEPTION")){
			//TODO let user know
		}
		else{
			//TODO push UX change
		}

	}

	@Override
	public void onConnectionChangeEvent(MapViewControllerEvent event,
			String message) {
		// TODO Auto-generated method stub

	}
});

Dispatch Event. And, here’s how to dispatch an Event:

dispatchEvent(new MapViewControllerEvent(MapViewEvent.LOCATION_INITIALIZED),"Attempting to start location service.");

EventListenerList Class. For some reason, which I would characterize as a major oversite, Android does not currently provide a public EventListenerList Class. This Class makes creating custom events so much easier. However, the folks of the Firefly Client project for Android saved the day and were kind enough to create and post one publicly under an Apache License. The code is a bit dated, and shows some minor warnings when building Android v4, but it will work just fine. You’ll need to include a copy of this Class in your project to make things work.

So, that’s pretty much it. I hope this info helps you build better and more succesful projects.

References:

Java Tutorial – General Information about Writing Event Listeners

Firefly Client Android – EventListenerList Source Code

[Edited: June 7, 2012 – fixed various minor typos]