I know that this is not possible and Apple planned it this way to force the users to upgrade their devices. But I just want to know if there is some workaround or hacks in able to do this? The client insists that we should still support armv6 because of a still "large" percentage of the app users.
I know a command called lipo
to merge static libraries and I read somewhere that we can also use it to merge ipa files but I'm not sure how its exactly done. I did a couple of searching around already on google and this site, buts its hard to find a concrete answer.
Thanks for this useful script !
I successfully combined all infos from this entire post, the resulting complete script is below. This script requires having both Xcode 4.5.x and a previous Xcode version supporting armv6 (Xcode 4.4.1 for instance, installed in /Applications/Xcode 4.4.1.app)
The script does NOT require to compile first in xcode 4.4.x, you just have to launch your latest Xcode, select the Release configuration and build. (the Release-armv6 configuration should have been defined like mentioned in the original post from Mike).
It will produce a .app compatible with armv6 armv7 and armv7s
Thanks to Mike for the original script !
There is a another way as gcc-4.2 still supports armv6, which won't require you to close Xcode 4.5 an open a previous version (for compilation, but not for running app on a 4.2 device) :
Archs : $(ARCHS_STANDARD_32_BIT) armv6
Valid Architectures : armv6 armv7 armv7s
Then, if you build your project, you will see warnings :
Build Rule
for source files with names matching :*.[mc]
that will useLLVM GCC 4.2
It works for static libraries, but not for apps :
Compile your project and check that your app contains all archs :
Note that the dSYM file also contains all archs (useful for crash report symbolification) :
I've sucessfully installed and launched the app on an iOS 4.2 2gen iPod touch by opening xcode 4.4.1, then
Product
->Run without building
.libarclite_iphoneos.a
orlibclang_rt.ios.a
:The procedure used for crt1.3.1.o applies to these files too, and will fix the error allowing Xcode to successfully archive your project: you can use the path printed by ld to find the file and join the armv6 slice with lipo; just keep in mind that libclang_rt.ios.a in the previous versions of Xcode isn't located in
Xcode.app/[...]/usr/lib/clang/4.1
but inXcode.app/[...]/usr/lib/clang/4.0
.I've successfully archived the file, deployed it with an ad-hoc distribution profile, and tested on iPhone 3G (4.2.1) and iPhone 3GS (6.0).
Organizer
, there is the message : Devices of type “iPhone 3G” are not supported by this version of Xcode.But an
ls
in theDeviceSupport
shows :With no diffs in the 4.2 directory from Xcode 4.4.1.
The question is now : how Xcode detect is device is supported or not ?
Opening
/Applications/Xcode.app/Contents/Developer//Platforms/iPhoneOS.platform/Developer//Library/PrivateFrameworks/DTDeviceKitBase.framework/DTDeviceKitBase
withHex Fiend
(or another hex editor), and replacing ascii4.3
with4.2
make the error message disappear, and app installed on the device are listed (but device bullet in the device list is still red).Then we need to edit
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks//DTDeviceKit.framework/Versions/Current/DTDeviceKit
and replace :Expired.deviceArchitecture.iPhone1,1.iPhone1,2.iPod1,1.iPod2,1.iPod2,2.armv6
to :
Expired.deviceArchitecture.iPhone0,1.iPhone0,2.iPod0,1.iPod0,1.iPod0,2.armv5
Then we have an orange bullet in the Organizer (Xcode 4.5.1) :
The question is now : where Xcode Supported iOS Versions are defined ?
As there is a
4.2
directory in/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
, it should already be supported...Tried to copy
iPhoneOS4.2.sdk
from Xcode 4.4.1 to/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
, but it don't make device supported.So haven't found how to add 4.2 device support in Xcode 4.5. Any ideas ?
Conclusion : compiling for armv6/7/7s within Xcode 4.5 is possible. But it is not possible to start an app on a 4.2 armv6 device without starting Xcode 4.4.
Big update : it works with Xcode 4.5.2 !
Now the bullet is green in Xcode 4.5.2 :-) The device appear in the drop down list near the Run button. But when trying to run the app, got the message :
Simply add armv6 to the valid architectures :-)
Other note : the
Build Rule
for source files with names matching :*.[mc]
can useLLVM GCC 4.2
orApple LLVM compiler 4.1
, orDefault compiler
Apple has stopped accepting builds that support pre iOS5 devices and contain an iPhone 5 launch image. Here is the email for the last build I submitted that was build on Xcode 4.4.1
I've been able to do this successfully with my app that's in the App Store. It supports armv6, armv7, and armv7s and iOS versions from 4.2 to 6.0. I've verified that it runs on older devices (iPhone 3G, iPod touch 2g) all the way through the iPhone 5.
This method requires having both Xcode 4.5 and an older version of Xcode installed simultaneously. I'm still on 4.3.2 for my older version, but 4.4 should work as well.
I had screenshots for this answer, but Stack Overflow won't let me post them because I'm new. :(
Setup in Xcode 4.5
Add a new build configuration for your armv6 build. I duplicated the Release config and named it Release_armv6.
Set the Architectures and Valid Architectures for your build configurations. For all but Release_armv6, use the default. For Release_armv6, manually set it to armv6. http://i.stack.imgur.com/h8Mpl.png
If you're using iOS 6 features that Xcode 4.4 and below won't understand, you'll need to #ifdef these out for your armv6 build. In Build Settings under Other C Flags and Other C++ Flags I added -DARMV6_ONLY to my Release_armv6 config. Then wherever the code uses a new iOS 6 API, I do something like #ifndef ARMV6_ONLY / #endif as appropriate. http://i.stack.imgur.com/czF6J.png
Add a new scheme and set it to use the Release_armv6 build configuration in all cases.
Under Build Phases, add a Run Script Build Phase with the following script (set the Shell to /bin/csh). This is where the magic happens. Edit the Configuration section: Determine your full path to the Release_armv6 build and substitute it for ARMV6_EXECUTABLE_PATH. Also set MINIMUM_OS.
Build Process
When you're ready to create a release build, do it in the following order:
Close Xcode 4.5 and open Xcode 4.4 or below. Select your armv6 scheme and build it.
Close Xcode 4.4 or below and open Xcode 4.5. Select your Release scheme and build it.
That's pretty much it. Check the build output to verify that you got what you want - an executable with three architectures in it. The last output from the run script should tell you this.
If anyone has ideas to improve this, please feel free. I imagine you might be able to get fancy and call Xcode 4.4's "xcodebuild" command from within the build script, alleviating the need to switch between Xcode versions at all. But this works well enough for me. ;)
Caveats:
Just to be safe, you might want to edit your xib files in the older version of Xcode. So far it seems like 4.5 is backwards compatible, but you never know.
In fact, you might consider just doing most of your development, except for iOS 6-specific stuff, in the older Xcode. Depends on whatever's easiest for you.
I would like to share my experience with kenji's answer. I think it's the best one and the best way to build a universal app which runs on armv6 / armv7 / armv7s, from iOS3.1 to iOS7.
Just do exactly as kenji suggests. You may ignore the parts about archiving the product, mainly if you send your app to apple via Application Loader (zipped).
Few more advices :
When you build for "distribution" configuration, xcode will validate the product, and you will get two warnings :
Of course, because you actually build for armv6 and you set the deployment target to 3.1 or 4.2, for example !
So... just ignore these warnings.
After sending your app to itunes connect, you will receive a warning email from apple, saying that your app is not "Position Independent Executable". Of course again, it's because your target is lower than 4.3. Just ignore this warning.
At this date (2013 jul 03) I have successfully update an app to the appstore with this method, and it has passed validation. The app deployment target is iOS 3.1.2, and it supports armv6-armv7-armv7s.
I would like to say also that :
Thank to Mike for this useful tutorial and script. As mentioned by Piotr in comments, the script is failing if you run the archive command from Xcode since it use another build directory for archiving.
Here below is my modification to the script to enable it for both normal release build and archive specific build.
It assumes that the armv6 build is run before as per original instructions from Mike. It use bash syntax because it is easier for me to strip-out the common base build directory. So this implies translation of the original script to bash which is only a matter of replacing setenv by export and changing the if statements syntax.