February 21, 2011

NSDateFormatter woes

NSDateFormatter has some really obscure behavior that I'm sure trips up a lot of people.  A case in point.  I have an app where a date is sent from the server in the format: "yyyy-MM-dd'T'HH:mm:ssZZ". You would expect that the following code would work just fine:

 
NSDateFormatter dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterFullStyle];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZ"];
 
but you would be wrong.  It appears that 
1) for certain locales (say Japan)
2) when the phone is set to 12 hour mode
 
The date formatter ignores the date format and inserts its own localized AM/PM string and date string parsing fail.  Now in Japan, the standard and thus majority of users use a 24 hour clock, so you will only get intermittent reports of errors/bugs which can be quite frustrating.
 
To fix this, instead of solely relying on setDateFormat, you need to set the locale.  In a rather obscure Q&A, Apple recommends "en_US_POSIX" (see: http://developer.apple.com/library/ios/#qa/qa2010/qa1480.html).  
 
NSDateFormatter dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[[NSLocale alloc]initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]];
[dateFormatter setTimeStyle:NSDateFormatterFullStyle];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZ"];
 
I'm sure there are many apps, particularly ones developed with only an English speaking user in mind that contain this bug. 
November 1, 2010

Updating Vosao from 0.2 to 0.7

I have been delaying updating the cms for this site for some time.  The site uses Vosao running on Google App Engine and apart from some slow performance at times, I have been very happy with it.  That said, for the longest time, I was using the 0.2 release which was fine until lately when I began having some minor data corruption problems.  The current version of Vosao 0.7 looks great, and I was really looking forward to the performance improvements that had been added over the past 5(!) versions not to mention tag clouds, rss feeds, and MediaWiki syntax support so I decided to update.

 
Vosao is pretty easy to work with, but I'm assuming that you understand how to use Subversion, Google App Engine, and a bit of Maven.  A couple of notes before beginning.  There is no direct upgrade path from version 0.2 to 0.7 or any other version.  This means that to update to the latest version of Vosao, you must run all of the upgrades in order.  It's a PITA, but as Vosao is still in Beta and this kind of issue should be expected.  Also,  because the update process requires you to clear your browser cookies for every update, the process goes smoother with 2 separate browsers, one for the Vosao admin console, and the other for the Google App Engine console.

 

version 0.2 to 0.3 (release notes)

  1. The upgrade to version 0.3 requires a full rebuild of the database, so first we need to backup all ofthe current site data.  In the Vosao admin console, export the full site.  Resources NOT in page/* and /theme/* will not be exported by the site export and must be backed up individually.
  2. Take the time to update your App Engine SDK
  3. Checkout tag 0.3 from the subversion repository
  4. Edit the make.sh file and change the app name  to match your app name (appname=****) .   At the same time, you may want to remove the -o flag (offline) and added -cpu (check plugin updates) to make sure that Maven downloads any new libraries automatically when run.  My final make.sh looked something like this:  mvn -cpu -Dmyapp install
  5. Make the same changes for /web/build.sh, and /web/make.sh
  6. The default scripts assume that your Google App Engine SDK is located in /opt/gae.  You may need to make a symbolic link to make /opt/gae point to your GAE SDK installation.
  7. Build the new version and use the run.sh script to test locally.
  8. When you are satisfied that everything is running properly, edit the update.sh script to add your GAE email address (-email=appengine_account@gmail.com")
  9. Run update.sh to upload version 0.3 to GAE
  10. When the upload has completed, in the GAE admin console, set version 0.3 as default.
  11. In your Vosao browser, clear all your cookies and access the setup url http://myapp/setup to finish the install.
  12. Now quickly log into the Vosao administration console and change the user settings to remove the default admin user.
  13. Finally import all of your content that you exported from your previous version and you should be good to go.
     

version 0.3 to 0.4 and beyond (release notes)

Updating any version after version 0.3 is much simpler that updating to 0.3 and involve a repetition of a subset of the previous steps

  1. Export and backup your current installation
  2. Check out next version tag from  subversion
  3. Alter the make.sh and update.sh files adding your app name and email address as above
  4. Run update.sh and upload the new version to GAE
  5. Switch the default version to the latest version
  6. Clear your cookies in the Vosao browser
  7. Access the update url http://myapp/update
  8. Confirm changes

Some notes:

  1. The plugin API often changes and if you are using any additional plugins, they will be disabled and need to be reinstalled after an update.
  2. After version 0.5 XSL is no longer supported.  If you have templates that use XSL, they will need to be changed to use Velocity.
  3. In some versions the update update.sh script contains a GAE rollback command.  This should not be a problem with an update, but you may wish to comment it out if you have no need to perform a rollback to delete any partially completed updates. (See http://code.google.com/appengine/docs/java/tools/uploadinganapp.html)
August 17, 2010

Resizing a UIWebView to fit with a fixed width

Formatting ScreenshotUIWebView is great for displaying hightly formated content, but sizing the frame correctly can be tough at times. Recently, I was using a UIWebView to display formated content and I needed to resize it display all of it's contents. The standard way to automatically resize a UIView to fit its contents is to call sizeToFit. Calling sizeToFit on the UIWebView in the -(void)webViewDidFinishLoad:(UIWebView *)webView UIWebViewDelegate method works nicely... almost.

My problem was that I wanted the width to be fixed and change only the height but sizeToFit automatically changes both, causing the content to run off the edge of the screen.

However, there is a neat little trick.

By calling the UIWebView's& stringByEvaluatingJavaScriptFromString method it is possible to interact with the content of the ;UIWebView. From there it is easy to get the content size and resize the UIWebView's frame accordingly.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
	CGFloat contentHeight = [[webView stringByEvaluatingJavaScriptFromString:
		@"document.documentElement.scrollHeight"] floatValue];
	webView.frame = CGRectMake(webView.frame.origin.x, webView.frame.origin.y, 
		webView.frame.size.width, contentHeight);
 
And away you go.
July 14, 2010

Web Based Ad Hoc App Distribution

Distributing apps Ad Hoc via mail is really easy, if you are only testing with a small team.  Send out the email, drag and drop in iTunes and your done.  No big deal.  Testing with over 30 devices is another matter entirely.  (Yes you need the provisioning profile, just drag and drop! No, No, in iTunes! etc etc).  Fortunately the latest XCode makes distributing via a web server, directly to the iPhone/iPad without messing about with iTunes.

First, you have to do all of the normal ad hoc distribution steps, namely:

  • Register the UIDs of the testing devices,
  • Create an ad hoc distribution profile,
  • Set the the proper code signing identity for your target build

Next, select “Build and Archive” from the XCode Build menu. In the Organizer, select the archived application build and click on the "Share Application" button.  In the popup dialog, select "Distribute for Enterprise".  In the next popup in the URL enter in the full url to your application's ipa file: http://www.veltema.jp/testing/MyApp.ipa

Once the build process is complete you will have 2 files to upload to your server: 

  • MyApp.ipa
  • MyApp.plist

It is also very convienent to keep a copy of the latest provisioning file on the server so that new testers can easily get everything they need directly from the webpage.

Finally create a web page to allow the download of your app:

 

  <ol>
  <li>
  <a href="/testing/MyApp_Ad_Hoc_Distribution_Profile.mobileprovision">
  Install MyApp Provisioning File</a></li>
  <br/></br>
  <li><a href="itms-services://?action=download-manifest&url=http://www.veltema.jp/testing/MyApp.plist">Install MyApp</a></li>
  </ol>
 

If everyone bookmarks the link on their devices, they can always download and install the latest version(s) for testing,