Creating an iPhone app without Xcode
The limitations of life without Xcode
It really depends on what level of pain and what compromises you want to make. Essentially there is no iOS development for the AppStore without a Mac and Xcode.
Some problems and examples without Xcode
- Codesigning
codesign
- AppStore upload
- Libraries
UIKit
- Toolchain
clang
This isn't to say the problems can't be overcome to some extent, but it starts to push you out of the AppStore and into the world of jailbreaks. So if you still want to develop for the device, simulator and AppStore proper there is a lot you can do without Xcode projects.
Choice of debugger and IDE
You can use vi
or AppCode. Any text editor will do. You'll still want to install Xcode on your computer for the purposes of having the compiler toolchain and the necessary libraries. Really no getting around that. Then to debug you can use lldb
at the command-line. Installing and managing apps can be handled via ios-deploy.
A Hello World of Sorts - Untitled.app
Github Project
I'm going to build a (extremely) basic app for iPhone Simulator. The basic idiom of an app is a folder with the .app
extension containing an Info.plist
and a binary compiled for the target. The Info.plist
contains the display name, bundle identifier and binary name.
Makefile
Building the app is probably the hardest part. The Makefile is unnecessary, but it helps keep you sane.
default: main
.PHONY: clean
clean:
rm main
SYSROOT:=$(shell xcrun --sdk iphonesimulator --show-sdk-path)
main: main.m
clang -isysroot $(SYSROOT) -framework Foundation -framework UIKit -lobjc -o Untitled.app/$@ $<
Untitled.app folder and Info.plist
Create a folder called Untitled.app
and add an Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Untitled</string>
<key>CFBundleExecutable</key>
<string>main</string>
<key>CFBundleIdentifier</key>
<string>com.cameronpalmer.Untitled</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Untitled</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
main.m
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(id)options {
NSLog(@"%s", __PRETTY_FUNCTION__);
CGRect mainScreenBounds = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:mainScreenBounds];
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor whiteColor];
viewController.view.frame = mainScreenBounds;
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char *argv[]) {
NSLog(@"%s", __PRETTY_FUNCTION__);
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
Build and install it on the simulator
# Build
make
# Boot
xcrun simctl boot <UUID_OF_DESIRED_SIMULATOR>
# Install
xcrun simctl install <UUID_OF_BOOTED_SIMULATOR> ./Untitled.app
# Open Simulator app
XCODE_PATH=$( xcode-select --print-path )
open "${XCODE_PATH}/Applications/Simulator.app"
Now just launch the app and you'll get a white box in the simulator.
All wrong...Xcode simply builds a binary plist of the nibs and allows you to call them as objects...you can do the same thing using GCC alone...
- Create a main.m, RootControlViewer.h, RootControlViewer.m, and AppNameApplication.h
- delegate...
- Create a makefile...
- include the necessary compiler flags, destinations to the frameworks and needed include files...
And from the shell enter "make" and you have application.app generated...
Place them in a payload folder...
- zip and rename zip to IPA...
- then use the sign command to sign the package...
I've been working on an XCODE clone for windows, Mac, and Linux... :-) all controls are generated in pure code (no nibs) and I've already completed the interface builder and can create working installable apps...am currently writing an "interpreter" to be used so that the syntax will be more "BASIC" like and when you press build..all code is converted to obj-c...built using gcc...and ready for deployment :-)