How to write iPhone applications
using Java
Arno Puder
San Francisco State University
Outline:
1. Introduction to Objective-C
2. Cross-Compiling Java applications
3. Running the toolchain
Java for the iPhone
y iPhone applications are based on Objective-C and
Cocao.
y Sun Microsystems would like to ports its JVM to the
iPhone.
y Apple’s iPhone SDK prohibits the development of certain
applications (e.g., VoIP).
Java4iPhone
y There have been questions about whether Apple's
iPhone SDK agreement would allow a JVM on the
iPhone.
Slide 2
© A. Puder
History of Objective-C
y Early 1980s: Objective-C language was designed by Brad J. Cox:
– Object-oriented extension of C. Inspired by Smalltalk.
– Strict superset of C.
y 1988: NeXT Software licensed the Objective-C language and
developed its libraries and a development environment called
NEXTSTEP.
y 1992: FSF adds Objective-C support to GNU compiler suite.
Java4iPhone
y 1994: NeXT Computer and Sun Microsystems released a
standardized specification of the NEXTSTEP system called
OPENSTEP.
y The Free Software Foundation's implementation of OPENSTEP is
called GNUStep.
y 1996: Apple acquires NeXT Software and the
NEXTSTEP/OPENSTEP environment became the basis for the
next major release of Apple's operating system, OS X. Apple's
version of this development environment is called Cocoa.
Slide 3
© A. Puder
@interface
#import <Foundation/NSObject.h>
@interface Fraction: NSObject {
int numerator;
int denominator;
Java4iPhone
}
-(void) print;
-(void) setNumerator: (int) d;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end
Slide 4
© A. Puder
@implementation
#import "Fraction.h“
#import <stdio.h>
@implementation Fraction
-(void) print
{ printf("%i/%i", numerator,
denominator); }
Java4iPhone
-(void) setNumerator: (int) n
{ numerator = n; }
-(void) setDenominator: (int) d
{ denominator = d; }
-(int) denominator
{ return denominator; }
-(int) numerator
{ return numerator; }
@end
Slide 5
© A. Puder
Creating and Using Objects
int main(int argc, const char *argv[])
{
// create a new instance Fraction
Fraction *frac = [[Fraction alloc] init];
// set the values
[frac setNumerator: 1];
Java4iPhone
[frac setDenominator: 3];
// print it
printf("The fraction is: ");
[frac print];
printf("\n");
// free memory [frac release];
return 0;
}
Slide 6
© A. Puder
Multiple Parameters
@interface
...
-(void) setNumerator: (int) n andDenominator: (int) d;
...
@implementation
...
-(void) setNumerator: (int) n andDenominator: (int) d
Java4iPhone
{
numerator = n; denominator = d;
}
...
Invocation
Fraction *frac = [[Fraction alloc] init];
[frac setNumerator: 1 andDenominator: 5];
setNumber:andDenominator: is called a selector. Slide 7
© A. Puder
Reference Counting
Class inheriting from NSObject have reference counting.
Fraction *frac = [[Fraction alloc] init];
printf(“Retain count: %i\n", [frac retainCount]);
[frac retain]; // 2
[frac retain]; // 3
Java4iPhone
printf(“Retain count: %i\n", [frac retainCount]);
[frac release]; // 2
printf(“Retain count: %i\n", [frac retainCount]);
[frac release]; // 1
[frac release]; // 0. Object will be deleted
Slide 8
© A. Puder
Dynamic Invocations
y Method invocations are bound at runtime:
id obj = …;
[obj someMethod];
y id is a generic object type (similar to java.lang.Object)
y obj may or may not implement someMethod. If not, a
runtime error occurs.
Java4iPhone
y Dynamic invocations are heavily used in the delegate pattern
(e.g., UITable)
Slide 9
© A. Puder
Objective-C “Hello World”
@interface helloWorld : UIApplication
-(void) applicationDidFinishLaunching: (NSNotification) n;
@end
@implementation helloWorld
-(void) applicationDidFinishLaunching: (NSNotification) n
{
CGRect rect = [UIHardware fullScreenApplicationContentRect];
UIWindow* window = [[UIWindow alloc] initWithContentRect: rect];
Java4iPhone
[window orderFront: self];
[window makeKey: self];
[window _setHidden: false];
rect.origin.x = rect.origin.y = 0;
UIView* mainView = [[UIView alloc] initWithFrame: rect];
[window setContentView: mainView];
UITextLabel *_title = [[UITextLabel alloc] initWithFrame: rect];
[_title setText: @"Hello World!"];
[_title setCentersHorizontally: true];
[mainView addSubview: _title];
}
@end
Slide 10
© A. Puder
Java “Hello World”
import org.xmlvm.iphone.*;
public class HelloWorld extends UIApplication
{
public void applicationDidFinishLaunching(NSNotification n)
{
CGRect rect = UIHardware.fullScreenApplicationContentRect();
UIWindow window = new UIWindow(rect);
window.orderFront(this);
Java4iPhone
window.makeKey(this);
window._setHidden(false);
rect.origin.x = rect.origin.y = 0;
UIView mainView = new UIView(rect);
window.setContentView(mainView);
UITextLabel _title = new UITextLabel(rect);
_title.setText("Hello World!");
_title.setCentersHorizontally(true);
mainView.addSubview(_title);
}
}
Slide 11
© A. Puder
Challenges
y Design goal: if possible, Java API mimics 1:1 the
Objective-C API.
y Objective-C challenges:
– Namespaces, method overloading: use name-mangling.
– Garbage collection: use Objective-C reference counting.
– No multiple inheritance: use Objective-C dynamic
invocations.
Java4iPhone
– No static member variables: use global variables.
y Cocoa challenges:
– Makes use of C-functions (e.g., CGColorCreate)
– Uses value types (e.g., CGRect)
– Uses pointers for output parameters (e.g.,
NSURLConnection)
– Makes heavy use of delegation (e.g., data source for
UITable)
Slide 12
© A. Puder
Example: Creating XMLVM
// Java
class Calc {
int x;
void add(int y)
{
x += y;
}
}
Java4iPhone
Calc.java Calc.class
javac
BCEL/JDOM
Calc.xml
Slide 13
© A. Puder
Example: XMLVM of Class Calc
<?xml version="1.0" encoding="UTF-8"?>
<xmlvm xmlns:jvm="http://xmlvm.org/jvm">
<class name="Calc">
<field name="x" type="int"/>
<method name="add" stack="3" locals="2">
<signature>
<return type="void"/>
<parameter type="int"/>
</signature>
Java4iPhone
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
</code>
</method>
</class>
</xmlvm>
Slide 14
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
locals[0]: this
locals[1]: 31 (y)
Slide 15
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
this
locals[0]: this
locals[1]: 31 (y)
Slide 16
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
this
locals[0]: this this
locals[1]: 31 (y)
Slide 17
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc"
<jvm:getfield class-type="Calc" type="int"
type="int" field="x"/>
field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
this
locals[0]: this 11
locals[1]: 31 (y)
Slide 18
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
this
locals[0]: this 11
31
locals[1]: 31 (y)
Slide 19
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 11
this
locals[0]: this 42
locals[1]: 31 (y)
Slide 20
© A. Puder
Example: Executing XMLVM
<code>
<jvm:load type="Calc" index="0"/>
<jvm:dup/>
<jvm:getfield class-type="Calc" type="int" field="x"/>
<jvm:load type="int" index="1"/>
<jvm:iadd/>
<jvm:putfield class-type="Calc" type="int" field="x"/>
<jvm:return/>
Java4iPhone
</code>
Stack:
x: 42
locals[0]: this
locals[1]: 31 (y)
Slide 21
© A. Puder
XMLVM to Other Languages
y Since the Java VM is a simple, stack-based machine,
XMLVM can easily be mapped to other languages.
y These translations are done using XSLT.
y Mappings exist for JavaScript and Objective-C.
y The XSLT excerpt below demonstrates the translation of
<jvm:iadd/> (Integer add) to JavaScript.
Java4iPhone
<!-- iadd -->
<xsl:template match=“jvm:iadd">
<xsl:text>
__op2 = __stack[--__sp]; // Pop operand 1
__op1 = __stack[--__sp]; // Pop operand 2
__stack[__sp++] = __op1 + __op2; // Push sum
</xsl:text>
</xsl:template>
Slide 22
© A. Puder
“Hello World” in XMLVM
<vm:xmlvm ...>
<vm:class name="HelloWorld" package="org.xmlvm.test.iphone“
extends="org.xmlvm.iphone.UIApplication">
<vm:method name="applicationDidFinishLaunching“
stack="4" locals="6">
<vm:signature>
<vm:return type="void" />
<vm:parameter type="org.xmlvm.iphone.NSNotification" />
Java4iPhone
</vm:signature>
<vm:code language="ByteCode">
<!-- ... -->
<jvm:var name="rect" id="2" type="org.xmlvm.iphone.CGRect" />
<jvm:invokestatic class-type="org.xmlvm.iphone.UIHardware“
method="fullScreenApplicationContentRect">
<vm:signature>
<vm:return type="org.xmlvm.iphone.CGRect" />
</vm:signature>
</jvm:invokestatic>
<jvm:astore type="java.lang.Object" index="2" />
Slide 23
© A. Puder
“Hello World” in Objective-C
@interface org_xmlvm_test_iphone_HelloWorld :
org_xmlvm_iphone_UIApplication
-(void) applicationDidFinishLaunching___org_xmlvm_iphone_NSNotification
:(org_xmlvm_iphone_NSNotification*)n1;
@end
-(void) applicationDidFinishLaunching___org_xmlvm_iphone_NSNotification
:(org_xmlvm_iphone_NSNotification*)n1
{
Java4iPhone
XMLVMElem _stack[4];
XMLVMElem _locals[6];
int _sp = 0;
XMLVMElem _op1, _op2, _op3;
_op1.o = [org_xmlvm_iphone_UIHardware
fullScreenApplicationContentRect];
_stack[_sp++].o = _op1.o;
_op1.o = _stack[--_sp].o;
[_op1.o retain];
[_locals[2].o release];
_locals[2].o = _op1.o;
...
Slide 24
© A. Puder
Outlook
y Still lots to do:
– Complete Java-to-Objective-C mapping.
– Support for all iPhone UI elements.
y iPhone UI for other phones:
– iPhone simulator mimics the iPhone UI.
– The simulator is completely written in Java.
Java4iPhone
– Idea: why not port these Java classes to other cell phones
that support Java?
– Benefit: iPhone-like UI on different cell phones!
Slide 25
© A. Puder
Installing the Toolchain
y Prerequisites for running the iPhone simulator:
– Java 5 or 6
– Eclipse
y Prerequisites for cross-compiling to the iPhone:
– Jail-broken iPhone/iPod Touch:
http://www.ziphone.org/
Java4iPhone
– iPhone development toolchain:
http://code.google.com/p/iphone-dev/wiki/Building
y XMLVM Cross-Compiler and iPhone simulator available
from SourceForge:
http://sourceforge.net/cvs/?group_id=152977
Use anonymous CVS to checkout module ‘xmlvm’.
Slide 26
© A. Puder
Running the Simulator
y Simulator automatically launched when a Java-based
iPhone application is executed.
y Currently there are four demos:
– org.xmlvm.test.iphone.HelloWorld
– org.xmlvm.test.iphone.Android
– org.xmlvm.test.iphone.ifireworks.Main
Java4iPhone
– org.xmlvm.test.iphone.todo.Main
y All these applications are in source folder
src/test/iphone
y The implementation of the iPhone simulator is in source
folder src/xmlvm2objc/compat-lib/java
Slide 27
© A. Puder
Cross-Compiling “Hello World” to Objective-C
y The cross-compiler is in source folder src/xmlvm class
org.xmlvm.Main
y To generate the XMLVM for “Hello World” use the following
command line options (under Eclipse):
--console
${workspace_loc:xmlvm}/bin/org/xmlvm/test/iphone/
HelloWorld.class
y To cross-compile the XMLVM to Objective-C use:
Java4iPhone
--console --objc
${workspace_loc:xmlvm}/bin/org/xmlvm/test/iphone/
HelloWorld.class
y To write the Objective-C source code to a file, use:
--out=tmp --objc
${workspace_loc:xmlvm}/bin/org/xmlvm/test/iphone/
HelloWorld.class
y The previous command will generate two files:
– ${workspace_loc:xmlvm}/tmp/HelloWorld.h
– ${workspace_loc:xmlvm}/tmp/HelloWorld.m
Slide 28
© A. Puder
Info.plist
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN“
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>HelloWorld</string>
<key>CFBundleIdentifier</key>
Java4iPhone
<string>org.puder.HelloWorld</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>
Slide 29
© A. Puder
Makefile 1/3
PRODUCT_NAME=HelloWorld
SOURCES=\
HelloWorld.m \
../bin/XMLVMCompatLib.m
SRCROOT=.
BUILT_PRODUCTS_DIR=build
CONFIGURATION_TEMP_DIR=obj
Java4iPhone
INFOPLIST_FILE=Info.plist
CC=arm-apple-darwin-gcc
CFLAGS=-g -O2 -Wall -I. -I../bin
LD=$(CC)
LDFLAGS=-lobjc -ObjC -framework CoreFoundation \
-framework Foundation -framework CoreGraphics \
-framework GraphicsServices \
-framework UIKit -framework LayerKit
Slide 30
© A. Puder
Makefile 2/3
WRAPPER_NAME=$(PRODUCT_NAME).app
EXECUTABLE_NAME=$(PRODUCT_NAME)
SOURCES_ABS=$(addprefix $(SRCROOT)/,$(SOURCES))
INFOPLIST_ABS=$(addprefix $(SRCROOT)/,$(INFOPLIST_FILE))
OBJECTS=\
$(patsubst %.c,%.o,$(filter %.c,$(SOURCES))) \
$(patsubst %.cc,%.o,$(filter %.cc,$(SOURCES))) \
$(patsubst %.cpp,%.o,$(filter %.cpp,$(SOURCES))) \
Java4iPhone
$(patsubst %.m,%.o,$(filter %.m,$(SOURCES))) \
$(patsubst %.mm,%.o,$(filter %.mm,$(SOURCES)))
OBJECTS_ABS=$(addprefix $(CONFIGURATION_TEMP_DIR)/,$(OBJECTS))
APP_ABS=$(BUILT_PRODUCTS_DIR)/$(WRAPPER_NAME)
PRODUCT_ABS=$(APP_ABS)/$(EXECUTABLE_NAME)
all: $(PRODUCT_ABS)
Slide 31
© A. Puder
Makefile 3/3
$(PRODUCT_ABS): $(APP_ABS) $(OBJECTS_ABS)
$(LD) $(LDFLAGS) -o $(PRODUCT_ABS) $(OBJECTS_ABS)
$(APP_ABS): $(INFOPLIST_ABS)
mkdir -p $(APP_ABS)
cp $(INFOPLIST_ABS) $(APP_ABS)/
cp $(SRCROOT)/$(RESOURCES)/*.png $(APP_ABS)/
Java4iPhone
$(CONFIGURATION_TEMP_DIR)/%.o: $(SRCROOT)/%.m
mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
deploy:
cd build; scp -r $(WRAPPER_NAME) \
root@192.168.178.26:/Applications
clean:
rm -rf $(CONFIGURATION_TEMP_DIR)
rm -rf $(BUILT_PRODUCTS_DIR)
rm -f *~
Slide 32
© A. Puder
Compile and run “Hello World”
y Type “make” in ${workspace_loc:xmlvm}/tmp
y Type “make deploy”
y On the iPhone, type “killall SpringBoard”
y The previous command can be accomplished by either
ssh-ing into the iPhone, or by using a terminal application
on the iPhone.
Java4iPhone
y Restarting the SpringBoard is necessary only once so
that it picks up the new “Hello World” application.
Slide 33
© A. Puder