I had to figure out a few things to get an Openframeworks 008 application ready for submission to the Mac App Store. Below are some of my findings.
Remove Quicktime and QTKit
Apple no longer supports the Quicktime API. So remove all of the ofQuicktime and ofQTKit files from the source files in the video folder of the OpenFrameworks XCode project. Remove the QTKit and Quicktime frameworks from the Openframeworks project and your Xcode project inside the frameworks folder. Make sure the libraries are not present in the Build Phases > Link Binary with Libraries.
If you need a video player, kronick’s addon that uses AVFoundation, is a good solution. I haven’t tried to find a solution for grabbing video using AVFoundation, so do your research if you plan to use it in your application.
Support Retina displays
As of this writing, OF does not support retina displays on osx. But Theo offered up a fix for GLFW to support Hidpi. So make sure to use GLFW for the windowing. Don’t forget to set ‘High Resolution Capable’ to YES.
Add some preprocessor macros for convenience
I think it’s useful to know if you are in release mode or debug mode, so I add some preprocessor macros in the build settings of the project. I usually use OF_DEBUG and OF_RELEASE respectively. This usually comes in hand at some point during the dev process. Like only showing debug GUIs #ifdef OF_DEBUG. I’ll go over some more uses a little later.
(only focus on OF_DEBUG + set OF_RELEASE for Release)
Sandboxing your App
Your app must be sandboxed to be eligible for submission to the app store. So make sure to select it in the capabilities section when you are ready to test in Release mode. (Note: if you do not change the default data path in OF and your app is sandboxed, it will crash. See ‘Change the data folder location to resources in the app’).
Limited file write access
I haven’t had issues loading files inside the app resources, but you are not able to write to the app resources folder!
According to the docs, Apple only allows you to write files to:
- ~/Library/Application Support/”app-identifier”
- ~/Library/”app-identifier”
- ~/Library/Caches/”app-identifier”
- ~/Pictures/”app-identifier”
- ~/Music/”app-identifier”
- ~/Movies/”app-identifier”
So, you can either save your files to one of those locations or use NSUserDefaults for saving preferences or other simple data. I like saving the window position and shape when the user closes the app and loading it on launch so it appears in the same place. I made a lil class that helps out with this that could be easily expanded.
// // UserDefaultsManager.h // iTunesVisualizerBullet // // Created by Nick Hardeman on 4/8/14. // #pragma once #include <CoreFoundation/CoreFoundation.h> #define UD_B_LaunchAtStartup @"UD_B_LaunchAtStartup" #define UD_WINDOW_X @"UD_WINDOW_X" #define UD_WINDOW_Y @"UD_WINDOW_Y" #define UD_WINDOW_W @"UD_WINDOW_W" #define UD_WINDOW_H @"UD_WINDOW_H" class UserDefaultsManager { public: static NSDictionary * defaultValues() { static NSDictionary *dict = nil; if (!dict) { dict = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithBool:YES], UD_B_LaunchAtStartup, [NSNumber numberWithInteger:10], UD_WINDOW_X, [NSNumber numberWithInteger:10], UD_WINDOW_Y, [NSNumber numberWithInteger:1400], UD_WINDOW_W, [NSNumber numberWithInteger:900], UD_WINDOW_H, nil]; } return dict; } static void registerDefaults() { [[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues()]; [[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:defaultValues()]; } // save method // static bool sync() { return [[NSUserDefaults standardUserDefaults] synchronize]; } static bool getBool( NSString* aKey ) { return [[NSUserDefaults standardUserDefaults] boolForKey:aKey]; } static void setBool( NSString* aKey, BOOL aBool ) { [[NSUserDefaults standardUserDefaults] setBool:aBool forKey:aKey]; } static int getInt( NSString* aKey ) { return [[NSUserDefaults standardUserDefaults] integerForKey:aKey]; } static void setInt( NSString* aKey, int aInt ) { [[NSUserDefaults standardUserDefaults] setInteger:aInt forKey:aKey]; } }; |
Change the data folder location to resources
Add a run script build phase ( Editor > Add Build Phase > Add Run Script Build Phase ) and put in the following snippet to copy over all of the files into the app resources folder:
mkdir -p "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/"; cp -R bin/data/ "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources"; |
Use the macro (OF_RELEASE) that we defined before to use the files from inside the app and not the data folder. This just makes it easier to edit the files and now the application can run without the data folder.
#ifdef OF_RELEASE ofSetDataPathRoot("../Resources/"); #endif |
Testing the Installation Process
Following these instructions on the apple developer website, it was relatively easy to test the installation process. After selecting Product > Archive and Validate in the Organizer, I got this message because of a setting in the OF Xcode project.
As explained here in the ios apple docs, The Skip Install option should be set to YES for the OF project and NO for the application.
May 11, 2015 at 1:23 am
Do you think one could prepare an exported Processing sketch to the Mac App Store as well?
September 18, 2015 at 11:10 am
Hi! I am new in “Open Frameworks”. How i know if i’m using the GLFW for the windowing ?
September 18, 2015 at 12:24 pm
Hi Pablo,
There are different ways to check based on what version of OF you are using.
Do you know what version you are using?
November 30, 2015 at 3:58 pm
Hi nick!
Thx for your answer.
I´m using OF 0.8.4.
The kronick’s addon that uses AVFoundation it dosen´t work for me!
Did you try this?
Thx