Good news! After almost 2 weeks of trials and tribulations, we’ve finally figured out the magic combination to make Titanium work across iPhone OS 4 (every beta version to date) plus older iPhone OS 3 devices. While this *should have* been very easy, some major changes to the XCode toolchain, gcc, ABI compatibility and lots of other things made this very, very complicated. What would normally have been a simple recompile with backwards compatible APIs like normal, iPhone OS 4 is a big change. Not only in terms of cool new functionality like multi-tasking, but also at its core.
For your applications to be compatible across the various combination of operating system versions and the anticipated upcoming iPhone OS 4 release, you’ll need to follow a few of simple steps (below) and republish your application update to iTunes. I’m going to do my best to clearly explain what needs to be done and what doesn’t need to be done – but if this isn’t clear or I don’t do the best job, feel welcome to ask questions and we’ll do our best to help everyone out.
First, you do not need to upgrade to the latest release of Titanium (as long as you’re on 1.0+). While we recommend being on the latest release, we’ve taken great pains to ensure that you can run Titanium applications across different versions of the SDK. In fact, we’re going to recommend that you do not upgrade your application if it’s not on the latest already unless you have the time and energy to re-test your app thoroughly.
Second, the fix is going to be a simple drop-in onto the SDK(s) you used for your app(s). So, if you have 3 apps and each app uses a different version of our SDK, you’ll want to drop the fix into all 3 versions and re-test and re-publish all 3 of your apps. Get it?
Third, you’ll want to re-publish your application update(s) to iTunes (after testing, please!) as soon as you can. It takes time to get through the app approval process as you already know and we want to make sure you have plenty of time to get through the queue. Nobody knows when the iPhone 4 release will be made generally available, but in case that it’s at WWDC in June, the sooner you release, the better.
Fourth, you do not need to be on iPhone 4 SDK to apply this fix. This fix works across all known 3.1+ versions (including iPhone 4 beta 1-4) that are out. In fact, please don’t attempt to push your application using iPhone 4 as Apple has not yet approved the release of applications on the iPhone 4 SDK.
Forth, we suggest making this patch for both iPhone and iPad applications.
So — how to apply the patch? Good news is that it’s a simple download, uncompress and copy.
1. Download the patched library. You can download directly from http://bit.ly/bGZSvq. Once downloaded, save this file off somewhere you can navigate to in console.
2. Uncompress the downloaded file. Run the following command from console: gunzip libTiCore-7.a.gz. This should create a file named libTiCore.a. NOTE: If you’re using Safari, Safari will automatically uncompress this file after download for you. If that’s the case, you’ll see the file already in your Downloads directory uncompressed.
3. The main SDK folder on OSX is either under /Library/Application Support/Titanium/mobilesdk/osx or ~/Library/Application Support/Titanium/mobilesdk/osx depending on your permissions when you installed Titanium. You’ll need to locate the version(s) of your SDK that your application uses from the Edit Project screen on Titanium Developer. Let’s assume you’re going to patch the 1.2.0 version of Titanium. You would copy the libTiCore.a file into the following directory: /Library/Application Support/Titanium/mobilesdk/osx/1.2.0/iphone. For 1.3.0, it would be /Library/Application Support/Titanium/mobilesdk/osx/1.3.0/iphone and so forth. You’ll probably want to make a backup of the existing libTiCore.a file in that directory. I’d suggest renaming it to something like libTiCore.a.orig.
At this point, you simply need to re-test your application both on Simulator and on Device. Assuming that works well, you can now build for distribution and submit to iTunes.
If you run into any problems or have questions, please comment on this thread for everyone’s benefit. We’ll monitor this post closely and try and provide timely help as necessary to everyone.
It’s worth noting, that this patch does not give you any iPhone 4 functionality. The upcoming 1.4.0 release of Titanium has the official 4.0 API support. It’s under development right now and we’re hoping to release it within the next 4 weeks (if not sooner).
Optional Techno Babble
For the intellectually inquisitive, what happened and how did we solve it?
First, it appears that iPhone OS 4 introduced some issues that as best we can tell are probably LLVM or GCC related problems. There’s a particular function that is used to create a set of pages in memory. This function effectively takes an address pointer, a block size for the page and several optional parameters for the memory access privileges, etc and returns a result code. This function prior to 4.0 worked great, as documented. The same function, when compiled on 4.0 worked great on a 4.0 device. However, when calling this function on a 3.2 built application on a 4.0 device, it returns an error code and an invalid address location. So, we had a catch-22. We could make it work on either 3.x or 4.0 both not both at the same time. After many various attempts to figure out why the same code produced 2 different results across 2 different SDKs, and coming up with all sorts of various ideas on how to work around it – we finally were able to trick the compiler into generating code that seemed to work on all scenarios. Everything looked great until we then tested under the Release build (during development, we generally test under the debugger in Debug build). Our fixes were being graciously optimized by GCC and removed, effectively removing our fix. Arg! OK, fine, we were able to force the compiler after some trickery into not optimize our fix.
Second, between iPhone OS 4 beta 2 and beta 3, Apple moved to a new ABI interface change which effectively changes the way symbols are handled by the GCC compiler. The original Objective C runtime, dating back to the NextStep era, had a
flaw in it special issue, called the Fragile Base Class problem. Apple fixed this, but this new runtime is incompatible with the old runtime. So on the Mac, the 32-bit intel runtime is the old one for backwards compatibility, but the 64 bit intel and iPhone runtimes are the new one. With 4.0b3, Apple switched the simulator from the old runtime to the new one. So, symbols like NSObject and NSString (built-in Cocoa classes) no longer produced the same internal symbol names when building a library. If you built on the newer beta, the same symbol when produced by GCC produced a different symbol name. When then linking that library into an application built prior to 4.0, of course the linker couldn’t resolve the core Cocoa symbols. Luckily, this was a slightly easier fix. We were able to port a few of the Cocoa functions that were problematic to use the Core Foundation equivalents, which produced the correct symbols names both both 3.x and 4.0.
With the combination of all this fixes, we’re able to build a library which supports i386, x64, armv6 and armv7 and works on 3.x, 4.0 and the various versions of the current beta.
And aren’t you glad you’re not having to do all of this crazy work yourself?