Archive for the ‘Software development’ Category.

Application integration using the iPhone SDK

Recently the successful iPhone applications Trein and iNap realized a tight integration, in that you can activate iNap directly from Trein. How to create the integration on the side of the ‘receiving’ application, iNap in this case, is described in the iPhone SDK example ‘Launch Me’.

When integrating applications, you typically want to pass data from one to the other, in this post I’ll describe how the incoming parameters can easily be extracted in the receiving application.

The receiving application will register itself in the OS (for details see the ‘Launch Me’ example), and the result is that it can be activated from another application or from a hyperlink in a webpage. An example of a url that activates another application is:


myapp://myapp?latitude=51.3&longitude=5.2&title=middle of nowhere

In the receiving application the method - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url will be called on the application delegate object, and in this method you need to extract the parameters from the URL. The following code shows how to do that with minimal code. Like Apple’s example, it does a lot of checking to prevent undesired usage, in this case the url parameters must meet the exact specifications (i.e. no missing parameters, no extra parameters) otherwise the request will be ignored.


- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
  // You should be extremely careful when handling URL requests.
  // You must take steps to validate the URL before handling it.
  // If any of the validations fails, bail out returning NO.
  if (!url) {
    // The URL is nil. There's nothing more to do.
    return NO;
  }

  // Split the url into two sections, one section with the base url and one with the parameters.
  NSArray *urlSections = [[url absoluteString] componentsSeparatedByCharactersInSet:
              [NSCharacterSet characterSetWithCharactersInString:@"?"]];

  // Check that you actually got a base section and a parameter section.
  if ([urlSections count] != 2) {
    return NO;
  }

  // Check that the base part of the url is what you expect it to be.
  if (![[urlSections objectAtIndex:0] isEqualToString:@"myapp://myapp"]) {
    return NO;
  }

  // Split up the parameter section into a parameter Array.
  NSArray *parameterArray = [[urlSections objectAtIndex:1] componentsSeparatedByCharactersInSet:
              [NSCharacterSet characterSetWithCharactersInString:@"&="]];
  NSEnumerator *parameterEnum = [parameterArray objectEnumerator];
  NSString *parameter, *value;
  // The parameters values that we are expecting.
  NSString *latitude = nil, *longitude = nil, *title = nil;

  // Run through the array of parameters.
  while (parameter = [parameterEnum nextObject]) {
    // Get the value that goes with this parameter, and if it is missing break.
    if ((value = [parameterEnum nextObject]) == nil)
      break;

    // Check the parameter value against the parameters that you support/expect,
    // and assign the matching value to the right variable.
    if ([parameter isEqualToString:@"latitude"])
      latitude = value;
    else if ([parameter isEqualToString:@"longitude"])
      longitude = value;
    else if ([parameter isEqualToString:@"title"])
      title = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    else {
      // An unexpected parameter was passed, bail out.
      latitude = nil;
      longitude = nil;
      title = nil;
      break;
    }
  }

  // Check if we got all parameters (in this case all are mandatory), if not bail out.
  if (latitude == nil || longitude == nil || title == nil) {
    return NO;
  }

  // Use the parameters to do your thing.
  CLLocation *location = [[[CLLocation alloc]
                               initWithLatitude:[latitude doubleValue]
                               longitude:[longitude doubleValue]] autorelease];
  [someObject activateDestination:title location:location];

  return YES;
}

Performance improvements for MPoD

Like Snow Leopard, the next release of MPoD will focus on performance rather then on functionality. Allthough the startup performance was improved a lot in version 1.1, it still takes a long time before the lists of artists, albums and songs are available. For my own 10.000 song library it takes about 15-20 seconds.

By using a locally cached sqlite3 database in combination with lazy loading, the loading now takes about 3 seconds, which is really a massive improvement. In the coming week additional testing will be done, and I hope that this release can be available in the AppStore in 2 weeks from now.

New iPhone app: iNap

_inapgrad.pngUnder the flag of moop.me I’ve recently been cooperating with some guys on a new iPhone application named iNap. This uses the location services on the iPhone 3G to alert you during your travel when you are approaching your destination.

This handy application is available from in the AppStore now.

RitMeester v1.0 released

It took some time, but finally version 1.0 of RitMeester has been released. In the Netherlands, when you have a lease-car the tax authorities will add up to 25% of the car value to your gross salary. If you use your car for personal travel less than 500 kilometers per year, you can get a ‘Verklaring geen privé gebruik’ from the tax authorities. Condition is that you maintain detail records of all car travel.

RitMeester is the first Mac based program that helps you to keep a detailed and consistent administration, with minimum effort. All details required by the tax authorities are stored, and you’re only a few clicks away from creating a printed version of your administration when needed.

RitMeester is available in Dutch only, and can now be downloaded as a trial version. Once you are convinced of the benefits it provides you, you can upgrade to the full version for €17.50.