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.
xcodebuild?