Friday, July 02, 2010

Using SDK 3.1.3 with iPhone SDK 4

In iPhone SDK 4 Apple has removed all 3.x SDKs. I think that was not a very good idea to say the least. I can understand Apple wants developers to adopt the new features of iOS 4, but breaking zillions of Xcode projects is probably not a good way to win the hearts of those developers. Well, this is probably not Apple's goal anyway.

Sure there is a way to get your projects working again with the iPhone SDK 4, just set the Base SDK of your project to iOS 4:

Base SDK 4

and set the Deployment Target to iOS 3:

Deployment Target 3

This will get your projects compile and run again on both iOS 3 and 4. That's fine. Well, except when you want to make sure your project do not use any new iOS 4 only API.

The problem is, code like this will now compile without any warning or error:

[[NSUserDefaults standardUserDefaults] setURL:defaultURL forKey:@"DefaultURL"];

It's easier than you think to use a shiny new API without even noticing you are using something not available on iOS 3. This setURL:forKey: method is new in iOS 4 so this code will fail with an unrecognized selector exception when run on iOS 3. Unfortunately, the only way to catch this kind of oversight is to run it on an iOS 3 device. Or you can read the documentation of every single method and function you are calling to make sure it was not introduced in iOS 4. But this does not seem very reasonable, does it? The tools should help us detecting these problems at compile time, not runtime!

Here is how to get Xcode 3.2.3 and iPhone SDK 4 working with SDK 3.1.3.

  1. Log in to the iOS Dev Center
  2. Download the iPhone SDK 3.1.3 into ~/Downloads
  3. Run the install-iphone-sdk-3.1.3.sh script
  4. Quit and relaunch Xcode
  5. Duplicate your Debug configuration and rename it to SDK 3.1.3 Check
  6. Set the Base SDK of this new configuration to iPhone Simulator 3.1.3
  7. Add a User-Defined Setting GCC_OBJC_ABI_VERSION and set its value to 1 (one)
  8. Select GCC_OBJC_ABI_VERSION and choose Add Build Setting Condition from the gear pop-up button at the lower left of the window.
  9. Select Any iPhone Simulator and Any Architecture

There you go! By selecting the SDK 3.1.3 Check configuration, you get compile time check for misusing iOS 4 only APIs when targeting iOS 3.

Note that compiling with the iPhone Simulator 3.1.3 SDK and running in Xcode 3.2.3 simulator is not supported. What you get with this hack is just a compile time check of the APIs you are using. So do not expect to run your app on a 3.1.3 simulator.

23 comments:

Anonymous said...

Thanks for writing this up Cédric!

One thing to make it easier: the make a user defined setting and then the editing the project as text and replacing it part can be done entirely within the Xcode UI:

So "- Add a User-Defined Setting..." remains as you have it, but the next two steps might be:

- Select the user defined setting name in the left column, then select "Add Build Setting Condition" from the gear pop-up button at the lower left of the setting window.

- Select "Any iPhone Simulator", and "Any Architecture" (the default)

Adrian Kosmaczewski said...

Thanks Cedric! Brilliant information. Bookmarked, del.icio.us'd, tweeted, etc :)

Unknown said...

Instead of all that, why not just set the max allowed macro, like this:

-D__IPHONE_OS_VERSION_MAX_REQUIRED=30100

oo said...
This comment has been removed by the author.
oo said...

Cheers for that. If only Apple would be more helpful here.
You can't think of a hack to actually *run* in the iPhone 3.1.3 Simulator?

Anonymous said...

When I launch the iPhone 3.1.3 simulator from this 3.2.3 setup, I get an error from the simulator app stating it can't find the SDK with a "Switch SDK" button. If I pick the 3.1.3 SDK it still fails.

Nick said...

I have also noticed that (at least with Xcode 3.2.3) you may also have to updated Base SDK in the build settings of your target. Thanks for the hard work Cédric!

Cédric Luthi said...

@Don I think you probably meant __IPHONE_OS_VERSION_MAX_ALLOWED. The short answer is it doesn't work properly. The long answer deserves a full blog post.

Anonymous said...

Hi! This post would be extremely useful but unfortunately the download link is not working anymore. Does anybody know where I can download the SDK?

Cédric Luthi said...

@Anonymous Did you perform step 1, which is Log in to the iOS Dev Center?

Anonymous said...

Yes I was logged in but it was just another very stupid error ;) Thx for the fast response and thx again for the great work.

Anonymous said...

Hi,

I have the iphone 3.1.3 SDK installed for Leopard with XCode 3.1.5 (I still have the installer for that).
I'm trying to avoid doing another >3GB download.

Can I modify your script to pick up stuff from the Leopard installer, and use the 3.1.3 SDK on Snow Leopard w XCode 3.2.x?

I don't know if XCode 3.1/3.2 have different directory structures, or if the are other reasons to avoid trying this.

Any advice?

Jesse Clark said...

Thanks for this post. I was considering doing a side by side install of an older version of the iPhone SDK and Xcode just so I could get compile time notification when using new APIs.

Your approach allows me to do that with only on Xcode install.

Unknown said...
This comment has been removed by the author.
Unknown said...

Thanks! very useful!

Anonymous said...

This is really good - thank you.
However, I have not seen it mentioned that compilation produces many errors about synthesized ivars (I'm using Xcode 4.02 on 10.6.8). It seems to me these can/should be ignored in this exercise.

The real value is in the yellow warnings eg
warning: implicit declaration of function 'UI_USER_INTERFACE_IDIOM'

See also the following discussing the errors: http://stackoverflow.com/questions/1155267/iphone-simulator-build-errors-when-using-synthesized-instance-variables

Anonymous said...

Hi,
Thank you for your post Cedric.
I followed the steps you described, but got an error when running the sh file:
-bash: install-iphone-sdk-3.1.3.sh: command not found

Not related to this error, I mention that in the script I had changed the name of the 'dmg' file, as it is no longer the same... but I don't know what else to do. My OS is Snow Leopard.
Is it any way I can debug the script so that I can isolate the issue?

Thanks,
Bradut



Anonymous said...

Hi,
Thank you for your post Cedric.
I followed the steps you described, but got an error when running the sh file:
-bash: install-iphone-sdk-3.1.3.sh: command not found

Not related to this error, I mention that in the script I had changed the name of the 'dmg' file, as it is no longer the same... but I don't know what else to do. My OS is Snow Leopard.
Is it any way I can debug the script so that I can isolate the issue?

Thanks,
Bradut

Anonymous said...

Hi,
Thank you for your post Cedric.
I followed the steps you described, but got an error when running the sh file:
-bash: install-iphone-sdk-3.1.3.sh: command not found

Not related to this error, I mention that in the script I had changed the name of the 'dmg' file, as it is no longer the same... but I don't know what else to do. My OS is Snow Leopard.
Is it any way I can debug the script so that I can isolate the issue?

Thanks,
Bradut

Brad said...
This comment has been removed by the author.
Anonymous said...

Hi,
Thank you for your post Cedric.
I followed the steps you described, but got an error when running the sh file:
-bash: install-iphone-sdk-3.1.3.sh: command not found

Not related to this error, I mention that in the script I had changed the name of the 'dmg' file, as it is no longer the same... but I don't know what else to do. My OS is Snow Leopard.
Is it any way I can debug the script so that I can isolate the issue?

Thanks,
Bradut

Anonymous said...

Hi Again,

I resolved the issue: ...just learned that I had to use the command "sh myScrip.sh".

Apologize for multiple postings [didn't realize when captcha accepted me as a humanoid ;-)

Bradut

Safdar said...

Çok detaylı ile yazılan güzel. Ben sizin bilgi gerçekten takdir. Sizin ilham için teşekkür ederiz.