Sunday, July 12, 2009

How to build a single iPhone application support both 2.x and 3.0 at the same time

I asked Apple Technical Support on how to build an iPhone application that runs on iPhone OS 2.x and yet uses iPhone OS 3.0 features if they are available.

They replied with a solution called weak linking

What is weak linking as quoted from http://devworld.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html

When a symbol in a framework is defined as weakly linked, the symbol does not have to be present at runtime for a process to continue running. The static linker identifies a weakly linked symbol as such in any code module that references the symbol. The dynamic linker uses this same information at runtime to determine whether a process can continue running. If a weakly linked symbol is not present in the framework, the code module can continue to run as long as it does not reference the symbol. However, if the symbol is present, the code can use it normally.

Here's the basic steps:

1. Use the latest tools with the latest SDK.

2. In your project, set the IPHONEOS_DEPLOYMENT_TARGET build setting to the oldest OS you want to support (say iPhone OS 2.0). And use GCC 4.2




3. If you use frameworks that are not present on that older OS, set the frameworks to be weak imported. Do this using the Linked Libraries list in the General tab of the target info window.




if you use Makefile to build the app add this in linker flag
  LDFLAGS += -weak_framework MessageUI

and add this key in Info.plist

  <key>MinimumOSVersion</key>
  <string>2.0</string>



This is how to test whether framework is available or not


#import <MessageUI/MessageUI.h>
#include <dlfcn.h>

    if ( dlsym(RTLD_DEFAULT, "MFMailComposeErrorDomain") != NULL ) {
        NSLog(@"%@", @"MessageUI framework is available");
        NSLog(@"MFMailComposeErrorDomain = %@", MFMailComposeErrorDomain);
    } else {
        NSLog(@"%@", @"MessageUI framework is not available");
    }



4. For places where you use C-style imports that aren't present on older systems, check whether the import is present before using it.

5. If you use Objective-C methods that aren't present on older systems, use -respondsToSelector: to verify that the methods are present before calling them.


if ( [[UIApplication sharedApplication] respondsToSelector:@selector(canOpenURL:)] ) {
  if ( [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel:996-1010"]] ) {
    NSLog(@"%@", @"tel URL is supported");
  } else {
    NSLog(@"%@", @"tel URL is not supported");
  }
} else {
  NSLog(@"%@", @"-canOpenURL: not available");
}


6. If you use Objective-C classes that aren't present on older systems, you can't just use the class directly. For example:

obj = [[NSUndoManager alloc] init];

will cause your application to fail to launch on iPhone OS 2.x, even if you weak link to the framework. Rather, you have to do the following:


NSUndoManager undoManager;
Class cls;
cls = NSClassFromString(@"NSUndoManager");
  if (cls != nil) {
    undoManager = [[[cls alloc] init] autorelease];
    NSLog(@"%@", @"NSUndoManager is available");

    // This tests whether we have access to NSUndoManager's selectors.

    [undoManager beginUndoGrouping];
    [undoManager endUndoGrouping];
  } else {
    NSLog(@"%@", @"NSUndoManager not available");
  }
  undoManager = nil;


7. Test, test, test!

Updated:
There is sample source code for the Mail Composer in Developer site
http://developer.apple.com/iphone/library/samplecode/MailComposer/index.html



2 comments:

Anonymous said...

>> check whether the import is present before using it.

How to do that check, please?

Offshore software development company said...

Thanks for sharing this article on Software development. It was very nice.

Looking for more..................Please continue.