<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Indelible Ink</title>
 <subtitle>Fresh Ink (iPhone)</subtitle>
 <link href="http://www.indelible.org/feeds/ink/iphone.xml" rel="self"/>
 <link href="http://www.indelible.org/ink/" rel="alternate"/>
 <updated>2011-11-22T13:51:43-08:00</updated>
 <id>http://www.indelible.org/ink/</id>
 <author><name>Jon Parise</name></author>
 <rights>Copyright 1999-2011 by Jon Parise. All rights reserved.</rights>

 
   
 

 
 <entry>
   <title>Manually Loading nib Files</title>
   <link href="http://www.indelible.org/ink/nib-loading/"/>
   <updated>2011-06-15T00:00:00-07:00</updated>
   <id>http://www.indelible.org/ink/nib-loading</id>
   <author><name>Jon Parise</name></author>
   <category term="iphone" />
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Interface_Builder&quot;&gt;Interface Builder&lt;/a&gt; is the standard Mac OS and iOS user interface design
tool.  Layouts are saved as &quot;nib&quot; (NeXT Interface Builder) files.  Recent
versions of Interface Builder write these files as XML archives using the
&lt;code&gt;.xib&lt;/code&gt; file extension.&lt;/p&gt;

&lt;p&gt;At runtime, nib files are loaded and assigned an &quot;owner&quot; object that forms the
basis of the layout's object hierarchy.  This &quot;owner&quot; is very often a view
controller object.  In this article, we'll focus specifically on UIKit and its
&lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;UIViewController&lt;/code&gt;&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;The nib loading process is generally abstracted away as part of the standard
&lt;code&gt;UIViewController&lt;/code&gt; initialization process.  Here's a simple example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objectivec&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;initWithNibName:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;SomeNib&amp;quot;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bundle:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// additional view controller initialization&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;-initWithNibName:bundle:&lt;/code&gt; handles all of the nib loading and instantiation
work.  While this is quite convenient, it has one major limitation: the nib
file must have been compiled and bundled (in the &lt;code&gt;NSBundle&lt;/code&gt; sense) along with
the application itself.  Fortunately, it is possible to manually load a nib
from arbitrary data and associate its contents with a view controller.&lt;/p&gt;

&lt;h2&gt;The UINib Class&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/uikit/reference/UINib_Ref/Reference/Reference.html&quot;&gt;&lt;code&gt;UINib&lt;/code&gt;&lt;/a&gt; class provides all of the functionality needed to
manually load nib files.  One reason to do this is to pre-cache the contents
of a nib file in memory, ready for quick deserialization and instantiation
later in the application's lifetime.  Another reason (and our focus here) is
to load the raw nib data from an alternate (non-&lt;code&gt;NSBundle&lt;/code&gt;) source.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;UINib&lt;/code&gt; class provides two methods for loading nibs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+nibWithNibName:bundle:&lt;/code&gt; - load a bundled nib file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+nibWithData:bundle:&lt;/code&gt; - load raw nib data&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Once loaded, the nib's objects can be instantiated and assigned an owner using
the &lt;code&gt;-instantiateWithOwner:options:&lt;/code&gt; instance method.&lt;/p&gt;

&lt;h2&gt;Manual View Controller Loading&lt;/h2&gt;

&lt;p&gt;How can the &lt;code&gt;UINib&lt;/code&gt; class be used in conjunction with a view controller?&lt;/p&gt;

&lt;p&gt;First, the view controller needs to call &lt;code&gt;UIViewController&lt;/code&gt;'s designated
initializer &lt;em&gt;without&lt;/em&gt; a nib name.  Note that passing &lt;code&gt;nil&lt;/code&gt; as the nib name
will trigger an automatic lookup for a nib named the same as the view
controller class, so take care not to fall into that case unintentionally.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objectivec&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;initWithNibName:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bundle:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Because this view controller hasn't loaded a view during initialization, we
must implement the &lt;code&gt;-loadView&lt;/code&gt; method.  This is where all of the manual
loading is performed.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objectivec&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadView&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loadView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;UINib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UINib&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nibWithNibName:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;SomeNib&amp;quot;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bundle:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nib&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;instantiateWithOwner:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;options:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This code effectively reproduces the standard nib loading process that was
previously being handled by &lt;code&gt;-initWithNibName:bundle:&lt;/code&gt; itself.&lt;/p&gt;

&lt;h2&gt;Loading Raw nib Data&lt;/h2&gt;

&lt;p&gt;At this point, our code is now manually loading the nib's objects, but it's
still reading the nib itself from our application bundle.  We can go a step
further and load arbitrary nib data using the &lt;code&gt;+nibWithData:bundle:&lt;/code&gt; method.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objectivec&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadView&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loadView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;NSData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSData&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dataWithContentsOfFile:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;SomeNib.xib.bin&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;UINib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nib&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UINib&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nibWithData:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bundle:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nib&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;instantiateWithOwner:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;options:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The nib data can come from pretty much anywhere, such as from a bundled file
or a network-fetched resource.  The only requirement is that the nib data be
compiled.  To compile an existing &lt;code&gt;.xib&lt;/code&gt; file, use &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/ibtool.1.html&quot;&gt;&lt;code&gt;ibtool&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ibtool SomeNib.xib --compile SomeNib.xib.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Additional Considerations&lt;/h2&gt;

&lt;p&gt;Now that the basic approach has been established, there are a few practical
considerations to keep in mind.  First, we've largely ignored the &lt;code&gt;bundle&lt;/code&gt;
parameter in the above code examples.  This argument instructs the nib loader
where to look for dependent resources, such as images.  Passing &lt;code&gt;nil&lt;/code&gt; implies
that the main application bundle (&lt;code&gt;[NSBundle mainBundle]&lt;/code&gt;) should be used.
There unfortunately doesn't appear to be a way to redirect these lookups to
non-bundle locations, however.&lt;/p&gt;

&lt;p&gt;Next, the nib data needs to be available by the time the view controller is
initialized.  All I/O needs to block, and any stalls could result in a poor
user experience.  Given that, any non-bundled nib data needs to be fetched
&lt;em&gt;before&lt;/em&gt; the view is loaded.&lt;/p&gt;

&lt;p&gt;Lastly, nibs can contain references to &quot;external&quot; objects.  One such example
is the &quot;owner&quot; object, which is explicitly resolved by the call to
&lt;code&gt;-instantiateWithOwner:options:&lt;/code&gt;.  If the nib references any additional
external objects, the loading code must provide those objects via a dictionary
mapping passed through the &lt;code&gt;options:&lt;/code&gt; interface's &lt;code&gt;UINibExternalObjects&lt;/code&gt; key.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Password Composer for iPhone</title>
   <link href="http://www.indelible.org/ink/iphone-pwdcomposer/"/>
   <updated>2009-10-25T00:00:00-07:00</updated>
   <id>http://www.indelible.org/ink/iphone-pwdcomposer</id>
   <author><name>Jon Parise</name></author>
   <category term="iphone" />
   <content type="html">&lt;p&gt;I often use &lt;a href=&quot;http://www.xs4all.nl/~jlpoutre/BoT/Javascript/PasswordComposer/&quot;&gt;Password Composer&lt;/a&gt; (written by Johannes la Poutré)
to generate unique, per-site passwords.  It does an excellent job because it's
simple, unobtrusive, and reliable.  The one downside is that you need to have
it available in order to (re)generate the password for a given web site, and
that isn't always convenient, despite the large number of existing Password
Composer implementations.&lt;/p&gt;

&lt;p&gt;The main place I find myself missing Password Composer is on my iPhone.  The
only current solution that works from Mobile Safari is the &lt;a href=&quot;http://www.xs4all.nl/~jlpoutre/BoT/Javascript/PasswordComposer/password_composer_form.html&quot;&gt;public web-based
interface&lt;/a&gt;, and I'm security-conscious enough to avoid using that version
whenever possible.  I decided the only reasonable solution would be to find a
way to run Password Composer locally on my iPhone.&lt;/p&gt;

&lt;p&gt;I first considered writing a full-blown native iPhone application.  I know a
bit of Objective-C and have experimented with the iPhone SDK, but, additional
learning opportunities aside, this approach felt like overkill.&lt;/p&gt;

&lt;p&gt;I then discovered the option of writing an iPhone-enhanced offline web
application.  That would let me reuse Password Composer's existing static web
form without having to work through the iPhone SDK.  I found the early release
of Jonathan Stark's &lt;a href=&quot;http://building-iphone-apps.labs.oreilly.com/&quot;&gt;Building iPhone Applications with HTML, CSS, and
JavaScript&lt;/a&gt; and set out to adapt Password Composer to the iPhone.&lt;/p&gt;

&lt;h2&gt;Basic Application&lt;/h2&gt;

&lt;p&gt;The basic application started as a single HTML file containing a form and some
JavaScript.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Password Composer&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Password Composer JavaScript&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Password Composer&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Master Key:&lt;span class=&quot;nt&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;password&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;masterpwd1&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;onkeyup=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;onchange=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Domain:&lt;span class=&quot;nt&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;domain1&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;onkeyup=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;onchange=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Password:&lt;span class=&quot;nt&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;td&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;genpwd1&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;onkeyup=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;onchange=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mpwd_generate()&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The JavaScript and form were copied directly from Password Composer's &lt;a href=&quot;http://www.xs4all.nl/~jlpoutre/BoT/Javascript/PasswordComposer/password_composer_form.html&quot;&gt;public
web-based interface&lt;/a&gt; and worked just fine in Mobile Safari.&lt;/p&gt;

&lt;h2&gt;Styling the Application&lt;/h2&gt;

&lt;p&gt;Next, I set about styling the look and feel of the page to more closely
resemble an iPhone application.  I started by adding a stylesheet file.  I
could have used inline CSS, and maybe I'll merge the styles back into the main
page at some point in the future, but using a separate file keeps things more
manageable for the time being.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;css&quot;&gt;    &lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#ddd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#222&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Helvetica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
        &lt;span class=&quot;k&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;14px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webkit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linear&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;#ccc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;#aaa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#ccc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;border-bottom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#666&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#222&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;bold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;center&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;text-shadow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#ddd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#FFFFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#999999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#222222&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;15px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;12px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webkit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;td&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;14px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Most of these styles are influenced by examples from &lt;a href=&quot;http://building-iphone-apps.labs.oreilly.com/&quot;&gt;Jonathan Stark's
book&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Viewport Definition&lt;/h3&gt;

&lt;p&gt;The next change is the addition of a &lt;code&gt;viewport&lt;/code&gt; meta tag:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;user-scalable=no, width=device-width&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This &lt;code&gt;viewport&lt;/code&gt; definition convinces Mobile Safari not to rescale the HTML
content as though it were a &quot;normal&quot; 980px-wide web page.&lt;/p&gt;

&lt;h3&gt;Input Field Types&lt;/h3&gt;

&lt;p&gt;I was also interested in configuring the form's &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; fields to pop up the
most appropriate type of on-screen keyboard on the iPhone.  &lt;em&gt;Master Key&lt;/em&gt; was
already being recognized as a password field (&lt;code&gt;type=password&lt;/code&gt;), but I wanted
the &lt;em&gt;Domain&lt;/em&gt; field to use the iPhone's special URL keyboard.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.bennadel.com/blog/1721-Default-To-The-Numeric-Email-And-URL-Keyboards-On-The-iPhone.htm&quot;&gt;A little research&lt;/a&gt; indicated that Mobile Safari recognizes a small
subset of the HTML5 input types, including the &lt;code&gt;url&lt;/code&gt; type.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;domain1&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Custom Icon&lt;/h2&gt;

&lt;p&gt;Because I want Password Composer to feel like a natural, first-class iPhone
application, it deserves to get a real icon.  This icon is used when a link to
the application is saved to the user's home screen.  Home screen icons are
57×57 pixel PNG images.&lt;/p&gt;

&lt;p&gt;There are two ways for a web application to specify its home screen icon:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provide a file named &lt;code&gt;apple-touch-icon.png&lt;/code&gt; in the site's root.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;&amp;lt;link rel=&quot;apple-touch-icon&quot; href=&quot;icon.png&quot; /&amp;gt;&lt;/code&gt; tag to the page's
&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; block.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I chose the second approach because I wasn't planning on using an entire
domain to serve the Password Composer application.  It also feels like better
encapsulation for a single-page web application.&lt;/p&gt;

&lt;h2&gt;Offline Application Cache&lt;/h2&gt;

&lt;p&gt;The last bit of work adds support for the iPhone's offline application cache.
This cache allows the files used by a web-based applications to be stored
locally on the iPhone so that they can still be accessed when the phone
doesn't have an active network connection.  This &quot;offline mode&quot; is described
quite well in Stark's book: &lt;a href=&quot;http://building-iphone-apps.labs.oreilly.com/ch06.html&quot;&gt;Chapter 6: Going Offline&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Briefly, all that's required is the creation of a &quot;manifest&quot; file, &lt;a href=&quot;http://www.w3.org/TR/offline-webapps/&quot;&gt;as
specified by HTML5&lt;/a&gt;.  My manifest file is named &lt;code&gt;pwdcomposer.manifest&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CACHE MANIFEST
index.html
iphone.css
icon.png
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The manifest lists all of the files used by the web application.  Manifest
files can be much more involved than this example.  They can specify fallback
images for use when network-based files are inaccessible, for example.  But
for my current purposes, the simple manifest above works great.&lt;/p&gt;

&lt;p&gt;Manifest files must be served using the &lt;code&gt;text/cache-manifest&lt;/code&gt; MIME type.
For Apache-like web servers, this can be configured using a directive like:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apacheconf&quot;&gt;    &lt;span class=&quot;nb&quot;&gt;AddType&lt;/span&gt; text/cache-manifest .manifest
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Lastly, the web page needs to specify its associated manifest file using the
&lt;code&gt;manifest&lt;/code&gt; attribute of the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;manifest=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;pwdcomposer.manifest&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Deployment&lt;/h2&gt;

&lt;p&gt;All that is left to do is deploy the application.  Simply serve up the source
files using a web server, and iPhone users can choose to bookmark the
application's link just like they would for any other web page.  The offline
application caching system will work automatically.  When the iPhone is
connected to a network, Mobile Safari will attempt to fetch the original
manifest file to check for updates, but the application will otherwise be
running entirely from the cache, essentially making it a local iPhone
application.&lt;/p&gt;

&lt;p&gt;My version is deployed here:
&lt;a href=&quot;http://www.indelible.org/pwdcomposer/&quot;&gt;http://www.indelible.org/pwdcomposer/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/jparise/pwdcomposer&quot;&gt;complete source code&lt;/a&gt; is available on &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>

