How to reuse iOS code for your OS X app
iHeartRadio for Mac was just released in Mac App Store.
We’ve made this product from scratch in two months(-ish). I hate to blow my own trumpet but it was quite quick work. The key is reusing iOS code in the OS X app. I’m going to share how we did it in this post.
Step 1: Know availability of frameworks on OS X
The first step is to understand which frameworks are avilable on OS X. For example, we can use Foundation on OS X while UIKit is not available at all.
I wrote a simple web page to see which of Apple’s frameworks are available both on iOS and OS X.
You also need to know which pods are available on OS X if you’re using Cocoapods. For example, our iOS app is highly dependent upon AFNetworking and SDWebImage, however SDWebImage doesn’t support OS X(yet).
You can check availability in the pod spec file. If you see both ios.deplyoment_target and osx.deployment_target, that pod is available on both iOS and OS X.
s.ios.deployment_target = ‘6.0’
s.osx.deployment_target = '10.8’
If these frameworks required to produce your app’s core value can be used on OS X, it might be worth to consider making OS X app from your iOS code and go ahead to the second step. In our case, the most important framework is AVFoundation. And it is fully available on OS X.
Step 2: Create private pod(s)
Now you know the core part of your iOS app can be used on OS X. The next step is to separate that part of code and create a pod.
In our case, we created a private pod as we didn’t want to expose our code to public. If you’re not familier with private pods, check out the official manual.
This step was not so easy since there were many dependencies on our core components. After an intensive fight to kill these dependencies, we finally made a shared pod described by the following diagram.
The diagram is way cleaner than the actual figure, though. The real world can’t be as neat as engineers think.
Step 3: Hack :)
As I mentioned above, the real world is always tough for engineers. Let me show you a more realistic diagram of the pod we created. Actually there are a bunch of “Helper” interfaces in our shared code, and they depend on UIKit, which is unavailable on OS X. Also there are additional dependencies to Facebook-iOS-SDK and GooglePlus from our account management interface.
And I have to say even this diagram is still way cleaner than real life :P
Unfortunately these undesirable dependencies were too tight to break without having risks to break our existing main iOS app. I was about to give up, but I wanted to release Mac app to see Mac App Store’s potential. So I decided to do a dirty hack.
Here is what I did:
// compat is to make our iOS code compatible with OS X.
// This file is supposed to be imported from all existing interfaces, which includes an undesirable dependency.
@interface FBRequest : NSObject
+ (FBRequest *)requestForMyFriends;
+ (FBRequest *)requestForMe;
- (FBRequestConnection *)startWithCompletionHandler:(FBRequestHandler)handler;
@interface FBSessionTokenCachingStrategy : NSObject
@interface FBRequestConnection : NSObject
So basically I gave up breaking some dependencies the proper way and defined all missing interfaces with empty implementations instead. To protect our engineering teams’ reputation, I have to say this hack is not allowed to be merged into master branch, of course.
This idea is from Chameleon library which is an open source project to port iOS frameworks into OS X. I decided not to use it in this case, however, its pretty cool and you definitely should check it out.
Once this hack step is done, your pod should be reusable from OS X. Now you have only to make a beautiful Mac app.
Check frameworks’ availability to see if your core component is reusable from OS X
Create a pod for your app’s core component
If the real world is tough for you as well, you always have an option to hack
Are you interested in building apps like this? Take a look at our openings.