<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Code Train &#187; iphone</title>
	<atom:link href="http://thecodetrain.co.uk/tag/iphone/feed/" rel="self" type="application/rss+xml" />
	<link>http://thecodetrain.co.uk</link>
	<description>Where Neil Crosby talks about coding on the train...</description>
	<lastBuildDate>Wed, 18 Aug 2010 18:22:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Geolocation &amp; Beer: Part 1 &#8211; Finding the user</title>
		<link>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/</link>
		<comments>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/#comments</comments>
		<pubDate>Wed, 05 May 2010 22:10:37 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[barcamb]]></category>
		<category><![CDATA[barcamp]]></category>
		<category><![CDATA[beer]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[w3c]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=389</guid>
		<description><![CDATA[<p>I recently attended <a href="http://barcamb.ltheobald.co.uk/">BarCamb3</a>, a BarCamp held at the lovely <a href="http://www.red-gate.com/">Red Gate Software</a> offices in Cambridge.  My main contribution to the event was talking about a silly little weekend learning project I&#8217;ve been working on &#8211; <a href="http://beernear.me/">Beer Near Me</a>.  </p>

<p>I&#8217;ve split the presentation I gave up into three separate blog posts, which I&#8217;ll be putting up over the next few days.  This one will cover basic use of the <code>navigator.geolocation</code> API, with the next two showing you how to use the data that gives you to <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">find out where the user actually is</a>, and to <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/">plot that data using Google&#8217;s static maps API</a>.</p>

<p>To start, I should explain that Beer Near Me was only ever intended to be used as a platform to be used to help me learn about the <a href="http://dev.w3.org/geo/api/spec-source.html"><code>navigator.geolocation</code> API</a> and how it works.  All the data that gets shown by the site was initially kind of secondary to me, as was the map that I use to show it off.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.001.png" alt="GeoLocation &#038; Beer"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.009.png" alt="What will I talk about?"></p>

<p>Of course, <code>navigator.geolocation</code> turned out to be far easier to work with than I expected.</p>

<h2>Support for navigator.geolocation</h2>

<p>The first thing to be aware of is that right now, support for <code>navigator.geolocation</code> is pretty poor.  If you&#8217;re using Firefox 3.5+ or Mobile Safari you can use it out of the box, and you can <a href="http://www.wait-till-i.com/2010/03/04/google-chrome-getting-navigator-geolocation/">turn on geolocation support in Chrome</a>, but apart from that you&#8217;re plain out of luck.  Since the idea behind Beer Near Me was to learn about <code>navigator.geolocation</code> that means that right now I&#8217;m not supporting any other APIs.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.011.png" alt="navigator.geolocation support"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.012.jpg" alt="Other APIs are available"></p>

<p>It&#8217;s not all doom and gloom though.  There are implementations of the API available for use in other browsers as plugins &#8211; for example <a href="http://en.wikipedia.org/wiki/Mozilla_Geode">Geode</a> will get you support in earlier versions of Firefox 3, and Google Gears opens up the ability to play with geolocation in some other browsers.  There&#8217;s also <a href="http://www.loki.com">Loki</a> (a Skyhook based plugin) that will get you support over a whole bunch of browsers but uses a differently specified API. Of course, I&#8217;ve not actually used any of these, so your guess is as good as mine as to whether they are any good or not.  I seem to remember Loki looking interesting a couple of years ago.</p>

<h2>Finding a location</h2>

<p>So, how to actually use <code>navigator.geolocation</code>?  Well, a good place to start would be checking whether the browser supports it.  We&#8217;ll do this in JavaScript, since that&#8217;s the only place we can reliably perform the check.</p>

<pre><code>if (navigator.geolocation) {
    // do geolocation
} else {
    // say sorry to the user
}
</code></pre>

<p>Pretty simple.  It&#8217;s your standard JavaScript functionality check.  If we have the functionality available then we can actually do something with it.</p>

<pre><code>navigator.geolocation.getCurrentPosition(
    foundLocation, // a user generated function
    noLocation,    // yup, user generated too
    {
        enableHighAccuracy: true,
        maximumAge: 1800,
        timeout: 30
    }
);
</code></pre>

<p>Here, we&#8217;re calling <code>getCurrentLocation()</code> with two callback functions and some options.  Once the browser (and the user) has decided whether or not to return a location, either the <code>foundLocation</code> or <code>noLocation</code> functions that you get to write are called, and the user&#8217;s location is passed into them.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.013.jpg" alt="GeoLocation check"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.014.jpg" alt="getCurrentPosition"></p>

<p>Before we get to those callback functions though, lets talk for a minute about the options we&#8217;re passing into <code>getCurrentPosition()</code>.  Essentially, what we&#8217;re saying in the code above is:</p>

<blockquote>
  <p>Try to give me highly accurate positioning if possible. I&#8217;d like to actually know where I am.</p>
  
  <p>Oh, and if you have a position cached that&#8217;s no older than 30 minutes, could you give me that immediately please?  I know that kind of contradicts what I said a moment ago, but I know better than you.</p>
  
  <p>And one more thing &#8211; if it takes you longer than 30 seconds to work out where you are, just give up.  There&#8217;s a good fellow.</p>
</blockquote>

<p>And that&#8217;s it really, with that little bit of code we&#8217;ve set up the browser to do some magic and try and work out where it is.</p>

<h2>Watching for changes to the user&#8217;s location</h2>

<p>The only problem with this is that the iPhone in particular seems a bit rubbish at following these instructions.  The first result it sends back seems to be uniformly Not Good, and generally quite old.  So what can we do about that?  Thankfully, there&#8217;s an easy answer provided to us in the API &#8211; the <code>watchPosition()</code> function.  This uses exactly the same parameters as <code>getCurrentLocation()</code> and can simply be dropped in as a replacement for it.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.015.jpg" alt="Keep finding the user"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.016.jpg" alt="You've got a location!"></p>

<p><code>watchPosition</code> does what you&#8217;d expect it to do.  Instead of finding a location once, it will keep watching the user&#8217;s location and call the success function whenever the location changes.  The thing that <code>watchPosition()</code> is most useful for though, is getting more accurate locations as the user&#8217;s device tries different location finding techniques.</p>

<p>You see, different devices will try and locate themselves in different ways.  Some of the techniques they&#8217;ll use will be be quick, some slow, and some very expensive when it comes to battery life.  For example, here&#8217;s what the iPhone does, as I understand it:</p>

<ol>
<li><p>First, the iPhone will look to see if there&#8217;s a location cached in its memory and give you that if available.</p></li>
<li><p>If you&#8217;re still watching for new locations, it will then try and grab a general location from the cell towers it knows about.</p>

<p>Depending on the number of towers available, this might give you really good, or really bad accuracy.  For example, in Bedford (where I live), using cell tower triangulation I get an accuracy which basically covers the entire town.  Not particularly useful.  It is quick though, and doesn&#8217;t really cost much in terms of power.</p></li>
<li><p>If the cell tower triangulation wasn&#8217;t awesome then the iPhone will gather information about all the WIFI hotspots it can see.  </p>

<p>This data gets sent to Skyhook, which does a whole bunch of triangulation and sends back a result.  This is obviously slower than just hitting the cell towers, but it can give you a really accurate result depending on where you are (better than GPS in some built up areas).</p></li>
<li><p>Finally, if you&#8217;re still looking for a location, the iPhone will fire up the GPS.  </p>

<p>This is expensive, slow, and drains the battery, so is left as a last resort.  It generally gives the best quality results though.</p></li>
</ol>

<p>So, you see, things aren&#8217;t necessarily as simple as asking for a position.  A whole bunch of stuff can be going on in the background, and grabbing the best location the user&#8217;s device knows about as time goes on can be very useful.</p>

<h2>Using the location we&#8217;ve found</h2>

<p>So, now that we&#8217;re requesting a location, what do we do once we actually get one?  Lets have a look.</p>

<pre><code>foundLocation = function(position) {
    // position.coords.latitude
    // position.coords.longitude
    // position.coords.accuracy
    // and more…
}
</code></pre>

<p>As you can see, the function we call on location finding success gets passed a single parameter &#8211; <a href="http://dev.w3.org/geo/api/spec-source.html#position_interface"><code>position</code></a>.  This object contains a <code>coords</code> object, and a <code>timestamp</code> representing the time the location was determined.  It&#8217;s the <code>coords</code> object we&#8217;re interested in right now, since that contains the latitude, longitude and accuracy (measured in metres) of the user&#8217;s current location &#8211; all the information a grown chap could need for finding some beer.  Other applications might make use of the altitude, heading and speed information, but that&#8217;s not vital when looking for beer, so I&#8217;m ignoring it for now.</p>

<h2>Putting it all together</h2>

<p>Quickly putting all this together, here&#8217;s some JavaScript you can copy and paste into a page to see this all in action.</p>

<pre><code>/*global document, navigator */
var beerLocation = {
    foundLocation: function (position) {
        beerLocation.setPara(
            "Lat = " + position.coords.latitude + 
            ", lon = " + position.coords.longitude + 
            ", accuracy = " + position.coords.accuracy + "m");
    },

    noLocation: function () {
        beerLocation.setPara("Boo! You didn't share your location!");
    },

    noGeoLocation: function () {
        beerLocation.setPara(
            "Sorry, but your browser doesn't support geolocation.");
    },

    setPara: function (text) {
        var p = document.getElementById('location-info');
        if (!p) {
            p = document.createElement('p');
            p.id = 'location-info';
            document.body.appendChild(p);
        }

        p.innerHTML = text;
    }
};

if (navigator.geolocation) {
    navigator.geolocation.watchPosition(
        beerLocation.foundLocation, 
        beerLocation.noLocation,
        {
            enableHighAccuracy: true,
            maximumAge: 120000
        }
    );
} else {
    beerLocation.noGeoLocation();
}
</code></pre>

<p>Alternatively, take a look at it in situ and in action on my <a href="http://projects.thecodetrain.co.uk/geolocation/">geolocation test page</a>.  The location shown by this page will keep updating as you move around or your device&#8217;s accuracy improves.  For best results, try it out on an iPhone.</p>

<h2>And finally</h2>

<p>And that&#8217;s how easy it is to find a user&#8217;s location and keep updating it.  You just need to do something with the latitude and longitude once you&#8217;ve found it.</p>

<p>In <a href="http://beernear.me/">Beer Near Me</a> I do two things with the location once it&#8217;s been found &#8211; I <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">tell the user the street address of the location</a>, and I display it on a map.  And, of course, I&#8217;ll be writing about how I&#8217;m doing that in the next couple of posts.</p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>I recently attended <a href="http://barcamb.ltheobald.co.uk/">BarCamb3</a>, a BarCamp held at the lovely <a href="http://www.red-gate.com/">Red Gate Software</a> offices in Cambridge.  My main contribution to the event was talking about a silly little weekend learning project I&#8217;ve been working on &#8211; <a href="http://beernear.me/">Beer Near Me</a>.  </p>

<p>I&#8217;ve split the presentation I gave up into three separate blog posts, which I&#8217;ll be putting up over the next few days.  This one will cover basic use of the <code>navigator.geolocation</code> API, with the next two showing you how to use the data that gives you to <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">find out where the user actually is</a>, and to <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/">plot that data using Google&#8217;s static maps API</a>.</p>

<p>To start, I should explain that Beer Near Me was only ever intended to be used as a platform to be used to help me learn about the <a href="http://dev.w3.org/geo/api/spec-source.html"><code>navigator.geolocation</code> API</a> and how it works.  All the data that gets shown by the site was initially kind of secondary to me, as was the map that I use to show it off.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.001.png" alt="GeoLocation &#038; Beer"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.009.png" alt="What will I talk about?"></p>

<p>Of course, <code>navigator.geolocation</code> turned out to be far easier to work with than I expected.</p>

<h2>Support for navigator.geolocation</h2>

<p>The first thing to be aware of is that right now, support for <code>navigator.geolocation</code> is pretty poor.  If you&#8217;re using Firefox 3.5+ or Mobile Safari you can use it out of the box, and you can <a href="http://www.wait-till-i.com/2010/03/04/google-chrome-getting-navigator-geolocation/">turn on geolocation support in Chrome</a>, but apart from that you&#8217;re plain out of luck.  Since the idea behind Beer Near Me was to learn about <code>navigator.geolocation</code> that means that right now I&#8217;m not supporting any other APIs.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.011.png" alt="navigator.geolocation support"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.012.jpg" alt="Other APIs are available"></p>

<p>It&#8217;s not all doom and gloom though.  There are implementations of the API available for use in other browsers as plugins &#8211; for example <a href="http://en.wikipedia.org/wiki/Mozilla_Geode">Geode</a> will get you support in earlier versions of Firefox 3, and Google Gears opens up the ability to play with geolocation in some other browsers.  There&#8217;s also <a href="http://www.loki.com">Loki</a> (a Skyhook based plugin) that will get you support over a whole bunch of browsers but uses a differently specified API. Of course, I&#8217;ve not actually used any of these, so your guess is as good as mine as to whether they are any good or not.  I seem to remember Loki looking interesting a couple of years ago.</p>

<h2>Finding a location</h2>

<p>So, how to actually use <code>navigator.geolocation</code>?  Well, a good place to start would be checking whether the browser supports it.  We&#8217;ll do this in JavaScript, since that&#8217;s the only place we can reliably perform the check.</p>

<pre><code>if (navigator.geolocation) {
    // do geolocation
} else {
    // say sorry to the user
}
</code></pre>

<p>Pretty simple.  It&#8217;s your standard JavaScript functionality check.  If we have the functionality available then we can actually do something with it.</p>

<pre><code>navigator.geolocation.getCurrentPosition(
    foundLocation, // a user generated function
    noLocation,    // yup, user generated too
    {
        enableHighAccuracy: true,
        maximumAge: 1800,
        timeout: 30
    }
);
</code></pre>

<p>Here, we&#8217;re calling <code>getCurrentLocation()</code> with two callback functions and some options.  Once the browser (and the user) has decided whether or not to return a location, either the <code>foundLocation</code> or <code>noLocation</code> functions that you get to write are called, and the user&#8217;s location is passed into them.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.013.jpg" alt="GeoLocation check"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.014.jpg" alt="getCurrentPosition"></p>

<p>Before we get to those callback functions though, lets talk for a minute about the options we&#8217;re passing into <code>getCurrentPosition()</code>.  Essentially, what we&#8217;re saying in the code above is:</p>

<blockquote>
  <p>Try to give me highly accurate positioning if possible. I&#8217;d like to actually know where I am.</p>
  
  <p>Oh, and if you have a position cached that&#8217;s no older than 30 minutes, could you give me that immediately please?  I know that kind of contradicts what I said a moment ago, but I know better than you.</p>
  
  <p>And one more thing &#8211; if it takes you longer than 30 seconds to work out where you are, just give up.  There&#8217;s a good fellow.</p>
</blockquote>

<p>And that&#8217;s it really, with that little bit of code we&#8217;ve set up the browser to do some magic and try and work out where it is.</p>

<h2>Watching for changes to the user&#8217;s location</h2>

<p>The only problem with this is that the iPhone in particular seems a bit rubbish at following these instructions.  The first result it sends back seems to be uniformly Not Good, and generally quite old.  So what can we do about that?  Thankfully, there&#8217;s an easy answer provided to us in the API &#8211; the <code>watchPosition()</code> function.  This uses exactly the same parameters as <code>getCurrentLocation()</code> and can simply be dropped in as a replacement for it.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.015.jpg" alt="Keep finding the user"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.016.jpg" alt="You've got a location!"></p>

<p><code>watchPosition</code> does what you&#8217;d expect it to do.  Instead of finding a location once, it will keep watching the user&#8217;s location and call the success function whenever the location changes.  The thing that <code>watchPosition()</code> is most useful for though, is getting more accurate locations as the user&#8217;s device tries different location finding techniques.</p>

<p>You see, different devices will try and locate themselves in different ways.  Some of the techniques they&#8217;ll use will be be quick, some slow, and some very expensive when it comes to battery life.  For example, here&#8217;s what the iPhone does, as I understand it:</p>

<ol>
<li><p>First, the iPhone will look to see if there&#8217;s a location cached in its memory and give you that if available.</p></li>
<li><p>If you&#8217;re still watching for new locations, it will then try and grab a general location from the cell towers it knows about.</p>

<p>Depending on the number of towers available, this might give you really good, or really bad accuracy.  For example, in Bedford (where I live), using cell tower triangulation I get an accuracy which basically covers the entire town.  Not particularly useful.  It is quick though, and doesn&#8217;t really cost much in terms of power.</p></li>
<li><p>If the cell tower triangulation wasn&#8217;t awesome then the iPhone will gather information about all the WIFI hotspots it can see.  </p>

<p>This data gets sent to Skyhook, which does a whole bunch of triangulation and sends back a result.  This is obviously slower than just hitting the cell towers, but it can give you a really accurate result depending on where you are (better than GPS in some built up areas).</p></li>
<li><p>Finally, if you&#8217;re still looking for a location, the iPhone will fire up the GPS.  </p>

<p>This is expensive, slow, and drains the battery, so is left as a last resort.  It generally gives the best quality results though.</p></li>
</ol>

<p>So, you see, things aren&#8217;t necessarily as simple as asking for a position.  A whole bunch of stuff can be going on in the background, and grabbing the best location the user&#8217;s device knows about as time goes on can be very useful.</p>

<h2>Using the location we&#8217;ve found</h2>

<p>So, now that we&#8217;re requesting a location, what do we do once we actually get one?  Lets have a look.</p>

<pre><code>foundLocation = function(position) {
    // position.coords.latitude
    // position.coords.longitude
    // position.coords.accuracy
    // and more…
}
</code></pre>

<p>As you can see, the function we call on location finding success gets passed a single parameter &#8211; <a href="http://dev.w3.org/geo/api/spec-source.html#position_interface"><code>position</code></a>.  This object contains a <code>coords</code> object, and a <code>timestamp</code> representing the time the location was determined.  It&#8217;s the <code>coords</code> object we&#8217;re interested in right now, since that contains the latitude, longitude and accuracy (measured in metres) of the user&#8217;s current location &#8211; all the information a grown chap could need for finding some beer.  Other applications might make use of the altitude, heading and speed information, but that&#8217;s not vital when looking for beer, so I&#8217;m ignoring it for now.</p>

<h2>Putting it all together</h2>

<p>Quickly putting all this together, here&#8217;s some JavaScript you can copy and paste into a page to see this all in action.</p>

<pre><code>/*global document, navigator */
var beerLocation = {
    foundLocation: function (position) {
        beerLocation.setPara(
            "Lat = " + position.coords.latitude + 
            ", lon = " + position.coords.longitude + 
            ", accuracy = " + position.coords.accuracy + "m");
    },

    noLocation: function () {
        beerLocation.setPara("Boo! You didn't share your location!");
    },

    noGeoLocation: function () {
        beerLocation.setPara(
            "Sorry, but your browser doesn't support geolocation.");
    },

    setPara: function (text) {
        var p = document.getElementById('location-info');
        if (!p) {
            p = document.createElement('p');
            p.id = 'location-info';
            document.body.appendChild(p);
        }

        p.innerHTML = text;
    }
};

if (navigator.geolocation) {
    navigator.geolocation.watchPosition(
        beerLocation.foundLocation, 
        beerLocation.noLocation,
        {
            enableHighAccuracy: true,
            maximumAge: 120000
        }
    );
} else {
    beerLocation.noGeoLocation();
}
</code></pre>

<p>Alternatively, take a look at it in situ and in action on my <a href="http://projects.thecodetrain.co.uk/geolocation/">geolocation test page</a>.  The location shown by this page will keep updating as you move around or your device&#8217;s accuracy improves.  For best results, try it out on an iPhone.</p>

<h2>And finally</h2>

<p>And that&#8217;s how easy it is to find a user&#8217;s location and keep updating it.  You just need to do something with the latitude and longitude once you&#8217;ve found it.</p>

<p>In <a href="http://beernear.me/">Beer Near Me</a> I do two things with the location once it&#8217;s been found &#8211; I <a href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">tell the user the street address of the location</a>, and I display it on a map.  And, of course, I&#8217;ll be writing about how I&#8217;m doing that in the next couple of posts.</p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Adding a vCard to your iPhone Address Book from a web page</title>
		<link>http://thecodetrain.co.uk/2009/11/adding-a-vcard-to-your-iphone-address-book-from-a-web-page/</link>
		<comments>http://thecodetrain.co.uk/2009/11/adding-a-vcard-to-your-iphone-address-book-from-a-web-page/#comments</comments>
		<pubDate>Sun, 29 Nov 2009 00:43:52 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[addressbook]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mobilesafari]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[scratching an itch]]></category>
		<category><![CDATA[vcard]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=334</guid>
		<description><![CDATA[<p>It can&#8217;t be done. Well, not obviously anyway.</p>

<p>A couple of weeks ago, I realised that <a href="http://neilcrosby.com/vcard">my public vCard</a> was less useful than it might be.  One of the specific reasons that I created it was to make it easy for people to add a bunch of my contact information to their address books when I met them, rather than them having to manually type in a whole load of stuff that was on a business card.  It turns out that this is great when that person&#8217;s sat at their own computer, but if they&#8217;re (for example) using an iPhone then things become a little more difficult.</p>

<p>You see, the iPhone doesn&#8217;t like to use MobileSafari to download files.  That&#8217;s fine in general &#8211; you don&#8217;t get a filesystem to peruse on the iPhone, so the only way that downloads would be useful is if the iPhone already knows what to do with them.  That&#8217;s why applications are allowed to register their own custom URL schemes. </p>

<p>Unfortunately, by default the iPhone only registers <a href="http://developer.apple.com/safari/library/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html">a few URL schemes</a> for use within web pages &#8211; <code>mailto:</code>, <code>tel:</code> and <code>sms:</code> as pseudo protocols, as well as specific URL structures for Google Maps, YouTube and iTunes links.  This makes it impossible to do things like adding an address to the Address Book or an event to the Calendar with a single click on a link in a webpage &#8211; you just get a message that reads &#8220;Download failed. Safari cannot download this file&#8221;.</p>

<p>This is clearly a pain. As a phone, it seems reasonable that you should be able to easily add contacts to your Address Book. Unfortunately, either Apple thinks you shouldn&#8217;t be able to do this from a webpage or they just didn&#8217;t consider it as a usecase.</p>

<p>It turns out that they did consider that you might like to open email attachments though. If someone sends you an email that contains a VCF file then you <em>are</em> able to open it and see its contents. If you then scroll down to the bottom of the file you&#8217;re greeted with two options, allowing you to &#8220;Create New Contact&#8221; or &#8220;Add to Existing Contact&#8221;.  Suddenly a world full of contact adding goodness is opened up to you.</p>

<p>So, what I&#8217;ve decided to do with my vCard is a little bit of user agent sniffing in my PHP. Currently I assume that every other device in the world other than the iPhone will do something sensible with the normal VCF file (or the microformatted data that&#8217;s on the page itself), so I listen out for the iPhone&#8217;s user agent. If I see it then I swap out the link to download the VCF file with one that takes the user to a page containing a form allowing them to enter their email address. Once they do, the VCF file is immediately emailed to them and they can add my card to their address book.</p>

<p>Right now the look and feel of the <a href="http://neilcrosby.com/vcard/via-email/">the email form</a> that iPhone users are directed to could be described as rudimentary at best, but it works.  At some point in the future I&#8217;ll get round to making it look a bit more pretty.</p>

<p>As a solution, I&#8217;m fairly happy with this.  Whilst it&#8217;s nowhere near as nice as being able to simply click on a link and add a contact to your address book, it does at least mean that it becomes possible to add a contact from a web page.  Certainly it&#8217;s a better solution than not allowing users access to the content at all.  It&#8217;s also entirely possible that this solution would work for other filetypes, such as calendar events.</p>

<p>My only concern is that this problem may be in existence in other devices other than the iPhone as well.  It would almost certainly make sense to make the email option available to users of other devices as well.</p>

<p>So there you have it &#8211; to allow a user to add a contact to their Address Book from a webpage on the iPhone don&#8217;t try and get them to download it, let them receive it via email instead. </p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>It can&#8217;t be done. Well, not obviously anyway.</p>

<p>A couple of weeks ago, I realised that <a href="http://neilcrosby.com/vcard">my public vCard</a> was less useful than it might be.  One of the specific reasons that I created it was to make it easy for people to add a bunch of my contact information to their address books when I met them, rather than them having to manually type in a whole load of stuff that was on a business card.  It turns out that this is great when that person&#8217;s sat at their own computer, but if they&#8217;re (for example) using an iPhone then things become a little more difficult.</p>

<p>You see, the iPhone doesn&#8217;t like to use MobileSafari to download files.  That&#8217;s fine in general &#8211; you don&#8217;t get a filesystem to peruse on the iPhone, so the only way that downloads would be useful is if the iPhone already knows what to do with them.  That&#8217;s why applications are allowed to register their own custom URL schemes. </p>

<p>Unfortunately, by default the iPhone only registers <a href="http://developer.apple.com/safari/library/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html">a few URL schemes</a> for use within web pages &#8211; <code>mailto:</code>, <code>tel:</code> and <code>sms:</code> as pseudo protocols, as well as specific URL structures for Google Maps, YouTube and iTunes links.  This makes it impossible to do things like adding an address to the Address Book or an event to the Calendar with a single click on a link in a webpage &#8211; you just get a message that reads &#8220;Download failed. Safari cannot download this file&#8221;.</p>

<p>This is clearly a pain. As a phone, it seems reasonable that you should be able to easily add contacts to your Address Book. Unfortunately, either Apple thinks you shouldn&#8217;t be able to do this from a webpage or they just didn&#8217;t consider it as a usecase.</p>

<p>It turns out that they did consider that you might like to open email attachments though. If someone sends you an email that contains a VCF file then you <em>are</em> able to open it and see its contents. If you then scroll down to the bottom of the file you&#8217;re greeted with two options, allowing you to &#8220;Create New Contact&#8221; or &#8220;Add to Existing Contact&#8221;.  Suddenly a world full of contact adding goodness is opened up to you.</p>

<p>So, what I&#8217;ve decided to do with my vCard is a little bit of user agent sniffing in my PHP. Currently I assume that every other device in the world other than the iPhone will do something sensible with the normal VCF file (or the microformatted data that&#8217;s on the page itself), so I listen out for the iPhone&#8217;s user agent. If I see it then I swap out the link to download the VCF file with one that takes the user to a page containing a form allowing them to enter their email address. Once they do, the VCF file is immediately emailed to them and they can add my card to their address book.</p>

<p>Right now the look and feel of the <a href="http://neilcrosby.com/vcard/via-email/">the email form</a> that iPhone users are directed to could be described as rudimentary at best, but it works.  At some point in the future I&#8217;ll get round to making it look a bit more pretty.</p>

<p>As a solution, I&#8217;m fairly happy with this.  Whilst it&#8217;s nowhere near as nice as being able to simply click on a link and add a contact to your address book, it does at least mean that it becomes possible to add a contact from a web page.  Certainly it&#8217;s a better solution than not allowing users access to the content at all.  It&#8217;s also entirely possible that this solution would work for other filetypes, such as calendar events.</p>

<p>My only concern is that this problem may be in existence in other devices other than the iPhone as well.  It would almost certainly make sense to make the email option available to users of other devices as well.</p>

<p>So there you have it &#8211; to allow a user to add a contact to their Address Book from a webpage on the iPhone don&#8217;t try and get them to download it, let them receive it via email instead. </p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2009/11/adding-a-vcard-to-your-iphone-address-book-from-a-web-page/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Five ways to make offline working easier</title>
		<link>http://thecodetrain.co.uk/2008/10/five-ways-to-make-offline-working-easier/</link>
		<comments>http://thecodetrain.co.uk/2008/10/five-ways-to-make-offline-working-easier/#comments</comments>
		<pubDate>Tue, 28 Oct 2008 18:15:14 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[distributed version control]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[list]]></category>
		<category><![CDATA[mamp]]></category>
		<category><![CDATA[marsedit]]></category>
		<category><![CDATA[offline]]></category>
		<category><![CDATA[php function index]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=129</guid>
		<description><![CDATA[<p>Nowadays an &#8220;always on&#8221; existence is far less of a pipe dream than it was even a year ago.  Usable wireless hotspots have popped up everywhere and many of us have data tariffs on our mobile phones.  It&#8217;s no surprise then that many people simply expect to always have a network connection and become flummoxed when this is taken away from them.</p>

<p>Not having a connection to the outside world shouldn&#8217;t be a blocker to getting work done though.  On my commute to and from work I have no internet connection available to my laptop and it really doesn&#8217;t stop me from getting anything done.  In fact, being disconnected from the cloud actually helps to free my mind and reduce the distractions that so often occur when I am connected.</p>

<p>A few people have asked me what my setup is for working on the train, so here&#8217;s a brief rundown of what I have on my laptop:</p>

<h3>A Development Environment</h3>

<p>For me, this is <a href="http://www.mamp.info/en/index.php">MAMP</a>, a simple installation LAMP setup for the Mac.  I personally currently run MAMP Pro, which costs money but gives me an easy interface for creating Virtual Hosts which I find very handy.</p>

<h3>Documentation</h3>

<p>Just as important as the development environment is the documentation to go with it.  If there&#8217;s a language or tool that you use that has documentation available for it then download it &#8211; you&#8217;ll regret your decision not to if you need it and you&#8217;re away from a network connection.</p>

<p>Because I write a lot of PHP and it&#8217;s a little inconsistent in its naming conventions I&#8217;m constantly in and out of the documentation.  I find the <a href="http://www.artissoftware.com/phpfi/">PHP Function Index</a> application invaluable on the train, as it makes the PHP documentation searchable and also allows you to download and keep an offline copy of all the user comments from PHP.net.</p>

<h3>MarsEdit</h3>

<p>Right now I&#8217;m working in <a href="http://www.red-sweater.com/marsedit/">MarsEdit</a>, the really rather nice blog entry writing tool.  It allows me to write entries for multiple blogs, store them locally and sync with the blog servers when I have a network connection.  It has built in support for Markdown (which matters to me) and gives a nice preview of your entries as you write them.  I really wish it would let me turn on a column to show the &#8220;Post Status&#8221; of my entries though &#8211; it would make finding the half finished things so much easier.</p>

<h3>Git</h3>

<p>I&#8217;ve only just started using git (check out <a href="http://github.com/NeilCrosby">my profile on GitHub</a>), but it&#8217;s looking like it should fit my usage nicely.  Working on the train means that there are plenty of times when I solve a problem and then want to move on to a new one.  With my previous setup of an SVN server on a completely separate machine I couldn&#8217;t commit my code before starting the second problem.  With git though, I can commit any changes I want locally and then upload them to an external server later at my leisure.  Apparently, I can even use git on the train for intermediary commits and then commit back to my normal SVN repository when I get home.</p>

<h3>A backup network connection</h3>

<p>Of course, there are times when you really do need a network connection and then a phone with a decent data plan really comes in handy.  On those occasions though Sod&#8217;s Law will apply and you won&#8217;t have any signal.  When that happens I just sit back, relax and move onto something else.</p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>Nowadays an &#8220;always on&#8221; existence is far less of a pipe dream than it was even a year ago.  Usable wireless hotspots have popped up everywhere and many of us have data tariffs on our mobile phones.  It&#8217;s no surprise then that many people simply expect to always have a network connection and become flummoxed when this is taken away from them.</p>

<p>Not having a connection to the outside world shouldn&#8217;t be a blocker to getting work done though.  On my commute to and from work I have no internet connection available to my laptop and it really doesn&#8217;t stop me from getting anything done.  In fact, being disconnected from the cloud actually helps to free my mind and reduce the distractions that so often occur when I am connected.</p>

<p>A few people have asked me what my setup is for working on the train, so here&#8217;s a brief rundown of what I have on my laptop:</p>

<h3>A Development Environment</h3>

<p>For me, this is <a href="http://www.mamp.info/en/index.php">MAMP</a>, a simple installation LAMP setup for the Mac.  I personally currently run MAMP Pro, which costs money but gives me an easy interface for creating Virtual Hosts which I find very handy.</p>

<h3>Documentation</h3>

<p>Just as important as the development environment is the documentation to go with it.  If there&#8217;s a language or tool that you use that has documentation available for it then download it &#8211; you&#8217;ll regret your decision not to if you need it and you&#8217;re away from a network connection.</p>

<p>Because I write a lot of PHP and it&#8217;s a little inconsistent in its naming conventions I&#8217;m constantly in and out of the documentation.  I find the <a href="http://www.artissoftware.com/phpfi/">PHP Function Index</a> application invaluable on the train, as it makes the PHP documentation searchable and also allows you to download and keep an offline copy of all the user comments from PHP.net.</p>

<h3>MarsEdit</h3>

<p>Right now I&#8217;m working in <a href="http://www.red-sweater.com/marsedit/">MarsEdit</a>, the really rather nice blog entry writing tool.  It allows me to write entries for multiple blogs, store them locally and sync with the blog servers when I have a network connection.  It has built in support for Markdown (which matters to me) and gives a nice preview of your entries as you write them.  I really wish it would let me turn on a column to show the &#8220;Post Status&#8221; of my entries though &#8211; it would make finding the half finished things so much easier.</p>

<h3>Git</h3>

<p>I&#8217;ve only just started using git (check out <a href="http://github.com/NeilCrosby">my profile on GitHub</a>), but it&#8217;s looking like it should fit my usage nicely.  Working on the train means that there are plenty of times when I solve a problem and then want to move on to a new one.  With my previous setup of an SVN server on a completely separate machine I couldn&#8217;t commit my code before starting the second problem.  With git though, I can commit any changes I want locally and then upload them to an external server later at my leisure.  Apparently, I can even use git on the train for intermediary commits and then commit back to my normal SVN repository when I get home.</p>

<h3>A backup network connection</h3>

<p>Of course, there are times when you really do need a network connection and then a phone with a decent data plan really comes in handy.  On those occasions though Sod&#8217;s Law will apply and you won&#8217;t have any signal.  When that happens I just sit back, relax and move onto something else.</p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2008/10/five-ways-to-make-offline-working-easier/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
