OSX Sandbox: Launch a different executable based on OS version - macos

I have an application in the Mac App Store. I'm trying to support users going back to Snow Leopard but this is becoming increasingly difficult.
Recently I've hit a roadblock due to the iTunesLibrary.framework, this framework must be linked to the main executable and yet doing so will always trigger a crash on load when running in Snow Leopard.
To workaround this problem, I want to compile a version of my app that doesn't use features and frameworks from newer versions of OSX. The problem is, how can I launch the compatibility build automatically?
I'm considering trying to make the main executable point to a shell script, but I don't really like that idea. I've also thought of the main executable being a helper that simply launches the full app and then exits. I expect this would work, but I worry about it getting approved by Apple. Finally, I'm wondering if the app bundle format itself can support this kind of setup, maybe via an advanced used of CFBundleExecutable that I'm unaware of.
Has anyone been down this road, what would you suggest?

Try weak linking the frameworks, more information about Weak Linking and Apple Frameworks here. Then also check in your code for the OS version or - (BOOL)respondsToSelector:(SEL)aSelector of any NSObject to determine what you can call and what not.
To have Snow Leopard as Base SDK you'll need an old Xcode and will have troubles submitting to Mac App Store.

Related

confusion of how to make osx app backward compatible & how to test them

after reading the apple SDK guide
https://developer.apple.com/library/mac/#documentation/developertools/conceptual/cross_development/Overview/overview.html
I'm still confused of how to make the mac app backward compatible & how to test them properly
I have an app, I run it and tested it on Mountain Lion 10.8 without any problem, however I want to make this app backward compatible so that other users can run it on a mac 10.6 - 10.7 machine.
I have an apple developer id and I can download the old versions of 10.7 and 10.6, but the problem is, I have a 2011 macbook air which is currently running 10.8, and that's the only apple machine that I have. Can I test the 10.7 and 10.6 by using vmware or parallels?
in my project settings, I set the target deployment to 10.6 (as I want 10.6 users to run my app), but should I set my SDK to 10.8 or 10.7? if I set the SDK to 10.8 but having the target deployment set to 10.6, if I fix all the xcode warnings will it run successfully on 10.6??
from the SDK drop down, I can only set to 10.8 or 10.7, but 10.6 is missing, how do I fix that?
thanks in advance
I develop on a 10.8 box and support back to 10.5. Just a couple of months ago we dropped 10.4 PPC support, and I'm still cleaning out some of the 10.2-specific code. This may get a little rant-y, but I've been doing old versions for a long time. I have some opinions on the matter.
No matter what Apple says in their docs, if you want to support 10.6, then build with the 10.6 SDK. Do not rely on distribution target.
I have had this discussion with the Xcode engineers, and while they hold to Apple's party line that you should always build with the latest SDK, they also acknowledge that it's generally insane to do so. If you build against the 10.8 SDK and mark your deployment target at 10.6, you will get no warnings for using methods that do not exist on 10.6. The only way you will discover that you've used a nonexistent method is that it might give you strange bugs when run on 10.6. That's insane.
Remember, OS X doesn't crash when you send an unknown selector. It just aborts the current runloop. So the bugs are even harder to track down then on iOS, where it crashes the app.
Sure, you can do weak linking. Talk about dangerous.... Yes, there are a few times this is useful, but the compiler gives you no warning if you don't do it correctly. If I'm going to do weak linking like this, I go the other way, linking against the old SDK and copying the new function's prototype into my implementation. That way I have documentation of every function I think I'm going to weak-link.
Download the old SDKs and symlink them into your Xcode distribution.
Guard them jealously. Apple will try to delete them every time you upgrade Xcode. Make your own copies and stick them in /SDKs or somewhere else away from Xcode. I provide a script called fix-xcode to manage the symlinks automatically. Am I bitter at Apple for their relentless insistance on deleting my old SDKs? Yes, I am.
You can run 10.6 Server in a VM legally. You can run 10.7+ Desktop in a VM legally. These are good ways to test your code.
Or you can do what I do and have a small pile of old MacBooks each with two or three partitions on them that you reboot all the time.
Now that 10.7 comes from App Store, it's a little harder to make VMs. My strong recommendation is to snapshot your image immediately after install, and make a clean backup copy of it. You'll want to be able to clone that image from time to time when you need to get back to a "raw" machine.
Get in the habit of squirreling away SDKs as they come out. 10.8 will be old some day. You might as well make a copy now while it's easy.
Whether you support individual dot-releases or not, it can be very helpful to keep around the upgrade packages for individual dot releases. When you encounter customers running non-current releases, it's nice to be able to check whether an "unreproducible" bug in fact is easily reproducible on their specific version. Whether this is worth it or not depends heavily on your product and customers. It was a life-saver for me when 10.4.11 made major changes to WebKit during a dot release...
Invest in a small NAS or a big external USB drive (though I've had trouble with those failing when used extensively, so I prefer a RAID). You'll need the space. You want to hold onto lots of VMs and lots of SDKs and sometimes even old versions of Xcode.
Adding to Rob Napier's great in-depth answer:
To use an old SDK, put the SDK (or a symlink) to it here:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
With XCode 7.3 or later, you need you to open this file and change "MinimumSDKVersion" (otherwise XCode will refuse to use the old SDK):
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist
You can install multiple versions of Mac OS on a single machine, booting between each.
The SDK should be the latest (10.8).
See 2.
One alternative to 1 that I've considered (I am in the same boat) is to create a Snow Leopard Hackintosh using an old PC and just installing Lion and Mountain Lion on my MBP.
You need to do these settings :
1.Set the Base SDK to Current version of Mac (ex. 10.7)
2.Set the Deployment SDK to older version (ex.1.4)

How do I add Leopard and Snow Leopard support to a Lion Cocoa App?

I have developed a Cocoa App on Lion and now I would like to add compatibility with Leopard and Snow Leopard.
I tried to set the development target to 10.5 but it still has crash problems on Leopard and Snow Leopard.
I tried also to open the project with old versions of Xcode, but I get hundreds of compile errors (I guess it's because I can't compile the program with the old Mac OS SDK)
Do you have any advice about solving the retro-compatibility problems of Cocoa Apps?
I think it's generally not a very good idea to develop for the latest OS then try to support older OSes at the last minute. If you've used any APIs that were introduced in an OS later than the oldest you're trying to support, you'll have to rewrite code to avoid using those APIs. It's generally not worth the trouble.
That said, there's no secret to supporting older OSes. You just need to make sure that you only use APIs (classes, methods, functions) that are available on the oldest OS you're trying to support. You'll notice when looking at the documentation that for each method, under "Availability", it will tell you which versions of the OS include that method. Something like:
Availability
Available in Mac OS X v10.6 and later.
Assuming you don't use any APIs not available on an OS version you're targeting, all you need to do is set the deployment target to the lowest OS you're targeting, and build. You will of course also want to test thoroughly on each OS version you're supporting.
Your question would be easier to answer in more detail if you elaborated on the "crash problems" you're seeing on Leopard and Snow Leopard.
First, install the 10.5 SDK on your Mac. This may not be necessary, but do it anyway. You can find instructions on the Internet. Keep in mind that compiling with the 10.5 SDK will ensure compatibility, but you won't be able to use newer OS X features unless you load them dynamically.
Second, go into your .xib files and on the File Properties tab (first notch in the Inspector pane) disable auto layout and set the deployment target to 10.5.

Applescript Universal application

Is there a way for me to create an Applescript as a run only application that would work on 10.5 and above?
I am running Lion. Whenever I save my script as a run only application it does not work with 10.5 and gives me a "does not work with this architecture" error.
The weird thing is that I saved it once and successfully launched it on the 10.5 machine but when I went to edit it and re-save it did not work anymore.
Thx
You can't and Apple's documentation isn't clear. My experience, based on a lot of trial and error, has been that when saving an Applescript as an application, that it has to be saved in the target environment, just as though you were targeting a specific OS when compiling for Xcode. In the past, I have had to make separate apps for 10.6 and 10.7 as well as PowerPC and Intel with the exact same code inside.

Xcode built app on 10.6 wont run on 10.5.8

I am new here and new in Xcode world.
I made a simple app with Xcode 3.2 on Snow Leopard.
The resulting built app works on snow leopard, however it will not even start on leopard (10.5.8) - I get message "You cannot use this version of application with this version of Mac OS X". Is it normal?
Or is there a way to make app that will work both on Snow Leopard and Leopard? Please advise, as I have no way to find out myself
Thanks for any input
You need to change the deployment target in your Build Settings. You should set it to the lowest version of OS X that you're willing to provide support for. You should set your base SDK to the latest available public SDK.
If you do this, you must ensure that you only use new 10.6-only APIs after doing runtime checks for their existence. To do this, you can use functions like NSClassFromString and respondsToSelector:.
Any Frameworks or libraries that are new to 10.6 should be weak-linked. This will prevent the app from trying to load those frameworks on 10.5 and thus cause the program to crash when it doesn't find the frameworks.
All explained in the SDK Compatibility Guide from Apple (Requires (free) login).

How to avoid XCode framework weak-linking problems?

I'm building an application that takes advantage of Mac OS X 10.6-only technologies, but without giving up backwards compatibility to 10.5 Leopard.
The way I do this is by setting the 10.6 SDK as the base SDK, weak-linking all frameworks and setting the deployment target to 10.5 as described in:
http://developer.apple.com/mac/library/DOCUMENTATION/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
This works fine; before making a call that is Snow Leopard-only I need to check that the selector or indeed the class actually exist. Or I can just check the OS version before making the call.
The problem is that this is incredibly fragile. If I make a single call that is 10.6 only I blow Leopard-compatibility. So using even the normal code code completion feature can be dangerous.
My question: is there any way of checking which calls are not defined on 10.5 before doing a release build? Some kind of static analysis, or even just a trick (a target set the other SDK?) would do.
I obviously should test on a Leopard machine before releasing anything, but even so I can't possibly go through all paths of the program before every release.
Any advice would be appreciated.
Best regards,
Frank
You could change the target SDK to 10.5. The compiler will then output warning: definition for '-snowLeopardOnlyMethod:' not found messages.

Resources