How do you conditionally include a framework in an Xcode project? - objective-c

Is it possible to have a single Xcode project (and ideally a single target) that will conditionally include frameworks when built against a certain version of OS X / Xcode but not include those frameworks when built against another version?
I'd like to begin adding support for El Capitan to an application I'm working on but some of the support I have in mind requires linking against frameworks that are not present in Yosemite. Is there a way to configure an Xcode project so that the same project can be built under 10.11 / Xcode 7 with the frameworks but also built under 10.10 / Xcode 6 without the frameworks (and without throwing an error)?
I'm aware of how to check for the existence of a class or method at runtime, but it's not clear to me how I control the framework linking without creating a second Xcode project, a second source control branch or always building against Xcode 7 (none of which I want to do, yet).

The "other version" would essentially be another target — it's setup this way to do precisely what you're asking about. A basic example would be just a matter of right-clicking on your original target and selecting duplicate from the current targets; then make whatever changes to linking frameworks within the Build Phases section.
Targets
In Build Phases you'll notice I've linked three frameworks to my
original target:
After right-clicking on the original target and creating a duplicate
I'm able to link it differently:
The duplicate version of MyApp uses the same classes and headers as the original with the exception of those that require the excluded frameworks. It's also possible to import different frameworks, change things such as the Deployment Target (e.g. build for different versions of OS X), or perhaps which SDK each might use, etc.
Once you're more familiar with the standard build process you can then create custom build scripts to handle specialized tasks like keeping the target names the same or even creating installer packages — anything is possible.

Related

Xcode: How to have shared code (i.e. framework) between main project and plugin bundle

In my project I had two targets, 1) The main application which loads 2) a bundle of plugins. I have started to have objects which need to be available in both targets, so naively tried to compile them separately in each target (producing warnings about having different implementations: Class X is implemented in both Y and Z. One of the two will be used. Which one is undefined.)
To solve this I decided to create a framework, so I added a framework, but I don't know how to make it so that a) both the main app and bundle access the framework (via the compiled framework, and not just through the headers in the project), and so the framework is compiled when I run the project.
If you know how to do this, thanks!
Here are the steps I followed:
Create a new framework in the project , copy all the shared code over.
In the main header of the framework, include the headers of all the shared code.
Build the framework to test it builds (e.g. select the scheme of the framework and click play)
Go to the Build Phases of both the Application and the Plugin Bundle and add the framework to ‘target dependencies’ and ‘Link binary with libraries’
To include the frameworks stuff in code in the app and bundle, just use the main header, and use <> rather than “" e.g if your framework was called Foo use #import
When it comes to deploying, there might have to be some fiddling with where the framework gets installed, currently it gets put alongside the app itself, rather than inside, but I will probably fix that later :)

Properly embedding custom frameworks into a project in Xcode 5

It's getting quite frustrating with Xcode 5 here. All I'm trying to achieve is embedding some custom Cocoa frameworks into my project and create two versions of the app, one for the Mac App Store and one for a custom Online Store (so that when building for the MAS there'll be a folder called Debug (MAS) so I can distinguish it from the other version).
I embedded three frameworks into the project (only god knows why only one project can have another one embedded at a time, to hell with this limitation) and added their products in the "Link binary with libraries" and "copy frameworks" build phase. The finished built products are at the default location in the Library.
Now here's the thing - every time I'm using custom build configuration files other than "Debug" and "Release", the frameworks are NOT copied to the custom build folders but instead just go into "Debug" and "Release" regardless of any build options of the main app. Also, the frameworks are always built using "Debug" and are no longer connected to the current build mode (test, archive, etc.). To cut a long story short, this is a huge mess with file paths and obviously a lot of bugs concerning custom frameworks and custom build configurations.
Now my question is - there has to be an official or working way of maintaining an Xcode project that is both distributed over the MAS and a custom online store (two versions) and has at least one custom framework embedded. How do all other developers have solved this problem, I feel like I'm doing something fundamentally wrong and if I do, sorry for putting the blame on Xcode but something's for sure: Xcode's path management with external components is a chaos and the cause for unlimited mailing list and forum posts...
The answer is to create separate targets for the MAS & non-MAS app. You can add additional targets to build the custom frameworks and make the different targets dependent on each other (as necessary). Once this is all setup (properly) then building any of the targets will build any dependent targets (with the same build flags). And AFAIK there's nothing preventing an Xcode project from including multiple sub-projects so I haven't a clue why you believe this to be the case.

Xcode: how to build a static library project correctly?

This question will be easy for Xcode pros but for a MonoTouch developer it seems to be impossible to resolve. :-)
I'm using Xcode 4.5 and I want to target iOS 5.1 and above and iOS Simulator 5.1 and above.
I have a a library project here and it is coming with a prebuilt binary named "DemoLib" (no extension and it is 11MB in size). The library is a fat lib for Simulator and iOS 5.1+.
I can use that library without any problem.
However if I try to build the library myself, I end up with a "DemoLib.a" file (notice the extension and the size of 30MB). How can I get the same build result? What is a .a file compared to the file without extension?
I tried to build the project "for running", and "for archiving" in Xcode. Both results in the same 30MB .a file.
I was expecting some dropdown in Xcode where one could select "DEBUG" or "RELEASE" build and the latter one would create the smaller lib.
Of course I could never tell without seeing the framework's project file. Having said that, there is an excellent guide to creating and compiling iOS frameworks here: https://github.com/jverkoey/iOS-Framework
Using the above guide, you should be able to recreate your framework's project from scratch, add the files you have to it, and properly compile it.
Hope this helps! :)
Did it come with a Makefile? Create a new target, set the build settings of the target to what's in the Makefile, then set your project to depend on that new target.
A file with the .a is a static library, which means it depends on nothing external and all the code it needs is compiled inside it. I think no extension generally implies dynamic library, which means it'll depend on some dependencies being present on your system to link against. Maybe that's why the .a is so much bigger. I think Xcode will build static by default because iOS does not allow the use of dynamic libraries.
The dropdown for what to build is in your scheme. Command+shift+< to view your scheme. Within the scheme you can edit which environment each method of building will use.

Cocos2d Targeting iPhone/iPad/Mac

I recently did some research on making a cocos2d app for iPhone/iPad AND Mac. I have done the iPhone/iPad route but have never done it with a Mac target. It appears that some people have added it as a target but mentioned that it is finicky and others have suggested making a separate Cocos2d Mac project that uses the same files. Any wisdom to impart here?
I believe it is absolutely crucial to have both iOS and Mac targets in the same project. Otherwise you'll spend too much time keeping one platform in synch with the other, until eventually you either manage to create a good (but still time-consuming) workflow - or end up neglecting one of the two platforms.
Ideally the code base should make as little use as possible of compiler macros. You'll want to compile both iOS and Mac code even if it's not being used for one platform. So having some classes or methods that are #ifdef'ed to Mac, others to iOS, will more often than not lead to compile errors when you switch targets. That means wrapper classes, so that you can write the same code regardless of the platform, are essential.
Right now, Cocos2D doesn't offer you to create iOS & Mac targets in the same Xcode project. The way to get there isn't immediately obvious either, because each target requires its own build settings for: Base SDK, SDK Root, Deployment Target, Architectures and possibly Compiler version. It gets worse if you also want to use 3rd party libraries (Box2D, Chipmunk, etc) because in some cases you'll be forced to create iOS and Mac specific targets for those libraries as well - if only to ensure that the library is built with the same compiler as the project's target, otherwise you can run into the strangest build or runtime issues.
I've had issues getting these platform specific targets to work within a single Xcode project without Xcode complaining or otherwise misbehaving. I haven't tried it with Xcode 4.1 and 4.2. By that time I had created .xcconfig files to host the build settings. The .xcconfig files may or may not be necessary with the more recent Xcode versions but they definitely make managing multiple platform-specific targets easier.
Long story short, the best and easiest way to do cross-platform development with cocos2d-iphone is by using Kobold2D.
Most of the 15 template projects have an iOS and Mac target in each project, you just need to select the corresponding scheme, then hit build & run. The most commonly needed platform-specific code (processing user input) is wrapped in a platform-agnostic, simple to use wrapper class KKInput.
Disclaimer: I'm the developer of Kobold2D. There's a slim chance that I may be biased. You should try Kobold2D anyway. :)

How do I use a new framework I have built?

I have had some issues with the AWS IOS SDK framekit, since it was not built to work with OSX apps. I found a modified version of the SDK that Brad Larson created.
The directory structure looks something like:
AWSiOSSDK.framework/
src/
--Amazon.Runtime/
--Amazon.S3/
..
--AWSCocoa/
----AWSCocoa_Prefix.pch
----AWSCocoa.xcodeproj
----etc
--include/
So if I go into the xcode project, and build AWSCocoa it compiles. But when I look at the timestamp on the AWSiOSSDK.framework, it hasn't changed. So I don't know what compiling this AWSCocoa gets me, or where I can find the files it creates. So assuming that building AWSCocoa.xcodeproj is supposed to build a new version of the framework compatible with OSX development, where do I find and link what I've built?
The AWSiOSSDK.framework bundle is a precompiled framework, probably left over from my earlier experiments in making a Mac version of this (since you can't use frameworks like this with iOS, only static libraries). Ignore that.
If you are using Xcode 4, your built framework will be created somewhere in your ~/Library/Developer/Xcode/DerivedData/ directory. To find where it lies, go to your project navigator in Xcode 4, expand the Products group, right click on AWSCocoa.framework, and select Show in Finder. This is no different from any other third-party framework you would compile.
Nominally, you'll want to add this framework as a target dependency in your application so that it is built alongside that. You'll also have to make sure that the framework is copied into the appropriate location within your application bundle so that it can be used by your application at runtime.