Extending Titanium with native iOS and Android modules

110
tiConf.eu, valencia, 24/02/2013 Native iOS & Android Modules Extending Titanium

description

This is the presentation used for the workshop on Titanium module development held at tiConf 2013 in Valencia

Transcript of Extending Titanium with native iOS and Android modules

Page 1: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Native iOS & Android Modules

Extending Titanium

Page 2: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Olivier MorandiSoftware en!ineer

http://[email protected]@olivier_morandihttps://github.com/omorandi

2

Page 3: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Module development is so

2010

Page 4: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Why Bother?

• To levera!e native features★ Underlyin! OS★ 3rd party libraries

• Performance★ To optimize the User Experience

4

Page 5: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Learnin! Resources

Page 7: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 7

Page 8: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Titanium Mobile SDK★ https://!ithub.com/appcelerator/

titanium_mobile

• Example modules from Appcelerator★ https://!ithub.com/appcelerator/

titanium_modules

8

Source code

Page 9: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Follow these guys

• Aaron K. Saunders: https://!ithub.com/aaronksaunders

• Ben Bahrenbur!: https://!ithub.com/benbahrenbur!

• Christian Sullivan: https://!ithub.com/euforic

• David Bankier: https://!ithub.com/dbankier

• Jordi Domenec: https://!ithub.com/iamyellow

• Marcel Pociot: https://!ithub.com/mpociot

• Matt Apperson: https://!ithub.com/mattapperson

• Paul Mietz E!li: https://!ithub.com/pe!li

• Ruben Fonseca: https://!ithub.com/rubenfonseca

• Russ Frank: https://!ithub.com/russfrank

9

Page 10: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Inside Titanium(A bit of architecture)

Page 11: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 11

Titanium cli (node.js) + python scripts

Page 12: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 12

Runtime (iOS)

Titanium Modules

(API)

JS APP

Parser

Interpreter

IOS SDK

Bytecode!en

Java

Scrip

tCor

e

objective-cC++

KRO

LL B

RIDG

E

Page 13: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 12

Runtime (iOS)

Titanium Modules

(API)

JS APP

Parser

Interpreter

IOS SDK

Bytecode!en

Java

Scrip

tCor

e

NO JIT

objective-cC++

KRO

LL B

RIDG

E

Page 14: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Titanium Modules

(API)

JS APP

Parser

Native Code

Android SDK

Native Code!en

KRO

LL B

RIDG

E

13

Runtime (Android)

JavaC++

V8

OPT

Page 15: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Titanium Modules

(API)

JS APP

Parser

Native Code

Android SDK

Native Code!en

KRO

LL B

RIDG

E

13

Runtime (Android)

JavaC++

V8

OPT

Page 16: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Titanium Modules

(API)

JS APP

Parser

Native Code

Android SDK

Native Code!en

KRO

LL B

RIDG

E

13

Runtime (Android)

JavaC++

V8

OPT

Page 17: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

Page 18: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

moduleobject

Page 19: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

moduleobject

Objects of t

he

Titanium API are

injected in th

e JS

environment at

app

startup

Page 20: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

factorymethod

Page 21: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

creation properties

Page 22: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

proxyobject

Page 23: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

view proxyobject

Page 24: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();

proxy property

Page 25: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Terminology

14

var win1 = Titanium.UI.createWindow({ title:'Hello World', backgroundColor:'white'});

var label1 = Titanium.UI.createLabel({ color:'black', textAlign:'center', width: 100});

label1.text = 'howdy?';win1.add(label1);

win1.open();proxy

method

Page 26: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxies & Modules

Proxy

ViewProxy ViewModule

extends

has a

creates

15

mana!es

Native View TypeiOS UIView

Android View

extends

Page 27: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxies & Modules

Proxy

ViewProxy ViewModule

extends

has a

creates

15

mana!es

Native View TypeiOS UIView

Android View

State:properties

Actions: methods

Events:addEventListener(), fireEvent()

Interface

extends

Page 28: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxies & Modules

Proxy

ViewProxy ViewModule

extends

has a

creates

15

mana!es

Native View TypeiOS UIView

Android View

State:properties

Actions: methods

Events:addEventListener(), fireEvent()

Interface

Methods for the inte!ration within the application lifecycle•startup() (iOS)•shutdown() (iOS)•onAppCreate() (Android)

extends

Page 29: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxies & Modules

Proxy

ViewProxy ViewModule

extends

has a

creates

15

mana!es

Native View TypeiOS UIView

Android View

State:properties

Actions: methods

Events:addEventListener(), fireEvent()

Interface

Additional members for the inte!ration within the UI layout system:•add()•remove()•height•width•backgroundColor•...

Methods for the inte!ration within the application lifecycle•startup() (iOS)•shutdown() (iOS)•onAppCreate() (Android)

extends

Page 30: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Let’s create a module

Page 31: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Create

• Develop

• Build

• Deploy

• Debu!

17

Page 32: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Create

• Develop

• Build

• Deploy

• Debu!

17

Page 33: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Module Development

Page 34: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Same as for Ti app development on iOS:★ Titanium SDK.★ Xcode

19

iOS Prerequisites

Page 35: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Same as for Ti app development on Android:

★ Titanium SDK.

★ Android SDK (+ ANDROID_SDK environment variable)

• Additionally:

★ Android NDK (+ ANDROID_NDK environment variable)

★ Ant 1.7.1 (available in PATH)

★ !perf must be installed and in your system PATH.

★ [Eclipse]

20

Android Prerequisites

Page 36: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 21

Create (cli)$ alias ti='~/Library/Application\ Support/Titanium/mobilesdk/osx/3.0.0.GA/ titanium.py'

OLD SCHOOL

Page 37: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 21

Create (cli)$ alias ti='~/Library/Application\ Support/Titanium/mobilesdk/osx/3.0.0.GA/ titanium.py'

$ ti create --type=module --id=ti.conf.sample --name=ticonfsample --platform=iphone --dir=./ios

OLD SCHOOL

Page 38: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 21

Create (cli)$ alias ti='~/Library/Application\ Support/Titanium/mobilesdk/osx/3.0.0.GA/ titanium.py'

$ ti create --type=module --id=ti.conf.sample --name=ticonfsample --platform=iphone --dir=./ios

$ ti create --type=module--id=ti.conf.sample --name=ticonfsample --platform=android --dir=./android

OLD SCHOOL

Page 39: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 22

Page 40: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 22

Page 41: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 22

Page 42: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 22

Page 43: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Create (Ti Studio)

23

Page 44: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Create (Ti Studio)

24

Page 45: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Create (Ti Studio)

25

Page 46: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Module Boilerplate

26

Page 47: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Module Boilerplate

27

Page 48: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 28

Build & Install (cli)

$ ./build.py$ unzip -uo ti.conf.sample-iphone-0.1.zip -d ~/Library/Application\ Support/Titanium/

Page 49: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 28

Build & Install (cli)

$ ./build.py$ unzip -uo ti.conf.sample-iphone-0.1.zip -d ~/Library/Application\ Support/Titanium/

$ ant$ unzip -uo dist/ti.conf.sample-android-0.1.zip -d ~/Library/Application\ Support/Titanium/

Page 50: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Build (Ti Studio)

29

Page 51: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Build & Install (Ti Studio)

30

Page 52: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Deploy

31

var ticonfsample = require('ti.conf.sample');

Ti.API.info(ticonfsample.example());

Ti.API.info("module exampleProp is => " + ticonfsample.exampleProp);ticonfsample.exampleProp = "This is a test value";

<?xml version="1.0" encoding="UTF-8"?><ti:app xmlns:ti="http://ti.appcelerator.org"> <id>com.omorandi.ticonftest</id> <!-- ... -->

<modules> <module platform="iphone">ti.conf.sample</module> <module platform="android">ti.conf.sample</module> </modules></ti:app>

app.js

tiapp.xml

Page 53: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

• Methods

• Passin! ar!uments

• Returnin! values

• Exceptions

• Usin! properties

• Proxies

• Events

• Callbacks

• ViewProxies

32

Agenda

Page 54: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy/Module Methods

33

-(id)methodName:(id)args{ NSString result = @"Hello World”;

//do something

return result;}

return value

Page 55: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy/Module Methods

33

-(id)methodName:(id)args{ NSString result = @"Hello World”;

//do something

return result;}

return value

-(void)methodName:(id)args{ //do something}

no return value

Page 56: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy/Module Methods

33

-(id)methodName:(id)args{ NSString result = @"Hello World”;

//do something

return result;}

return value

-(void)methodName:(id)args{ //do something}

no return value

@Kroll.methodpublic String methodName(){

String result = "Hello world"; //do something

return result;}

return valueno ar!s

Page 57: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy/Module Methods

33

-(id)methodName:(id)args{ NSString result = @"Hello World”;

//do something

return result;}

return value

-(void)methodName:(id)args{ //do something}

no return value

@Kroll.methodpublic String methodName(){

String result = "Hello world"; //do something

return result;}

return valueno ar!s

@Kroll.methodpublic void methodName(String value){ //do something}

no return value

Page 58: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Example: xml2json module

34

Expected API

var xml2json = require('ti.xml2json');

var json = xml2json.convert(xmlDoc);

https://!ithub.com/omorandi/TiXml2Json

Page 59: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

35

@implementation TiXml2jsonModule

-(NSDictionary) convertXml:(NSString)xmlString{ NSDictionary *jsObj;

//do conversion stuff

return jsObj;}

-(id)convert:(id)args{ ENSURE_SINGLE_ARG(args, NSString); return [self convertXml:args];}

@end

Page 60: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

35

@implementation TiXml2jsonModule

-(NSDictionary) convertXml:(NSString)xmlString{ NSDictionary *jsObj;

//do conversion stuff

return jsObj;}

-(id)convert:(id)args{ ENSURE_SINGLE_ARG(args, NSString); return [self convertXml:args];}

@end

NSArray of ar!uments

Page 61: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

35

@implementation TiXml2jsonModule

-(NSDictionary) convertXml:(NSString)xmlString{ NSDictionary *jsObj;

//do conversion stuff

return jsObj;}

-(id)convert:(id)args{ ENSURE_SINGLE_ARG(args, NSString); return [self convertXml:args];}

@end

NSArray of ar!uments#define ENSURE_SINGLE_ARG(x,t)\{ \ x = (t*)[x objectAtIndex:0]; \} \

TiBase.h

Page 62: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Utility Macros

36

#define ENSURE_CLASS(x,t)#define ENSURE_CLASS_OR_NIL(x,t)#define ENSURE_TYPE(x,t)#define ENSURE_TYPE_OR_NIL(x,t)#define ENSURE_ARG_COUNT(x,c)#define ENSURE_SINGLE_ARG(x,t)#define ENSURE_SINGLE_ARG_OR_NIL(x,t)#define ENSURE_DICT(x)#define ENSURE_ARRAY(x)#define ENSURE_STRING(x)#define THROW_INVALID_ARG(m)

...

TiBase.h

Page 63: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Types

37

NSStringNSDictionaryNSArrayNSNumberNSDateNSNullTiProxy

Supported Directly

#import "TiUtils.h"

CGFloat f = [TiUtils floatValue:arg];NSInteger f = [TiUtils intValue:arg];

NSString *value = [TiUtils stringValue:arg];

TiColor *bgcolor = [TiUtils colorValue:arg];UIColor *backgroundColor = [bgcolor color];

Conversion Utilities

Page 64: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Return Values

• Sin!le Value (NSStrin!, NSNumber, …)

• Collections (NSArray)★ Converted into a JS Array object

• Dictionary (NSDictionary)★ Converted into a JS object★ key->value ===> property->value

• Proxy (TiProxy)

38

Page 65: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Return Values

• Sin!le Value (NSStrin!, NSNumber, …)

• Collections (NSArray)★ Converted into a JS Array object

• Dictionary (NSDictionary)★ Converted into a JS object★ key->value ===> property->value

• Proxy (TiProxy)

38

RETURN AUTORELEASED OBJECTS

Page 66: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

xml2json Android

39

import org.appcelerator.kroll.KrollDict;

@Kroll.module(name="Tixml2json", id="ti.xml2json")public class Tixml2jsonModule extends KrollModule{

@Kroll.methodpublic KrollDict convert(String xml)

{ KrollDict json = null;

//do conversion stuff

return json; }

}

Page 67: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

xml2json Android

39

import org.appcelerator.kroll.KrollDict;

@Kroll.module(name="Tixml2json", id="ti.xml2json")public class Tixml2jsonModule extends KrollModule{

@Kroll.methodpublic KrollDict convert(String xml)

{ KrollDict json = null;

//do conversion stuff

return json; }

}

public class KrollDict extends HashMap<String, Object>

KrollDict.java

Page 68: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Types

40

StringintfloatdoublebooleanObject[]HashMap<String, Object>TiProxy

import org.appcelerator.titanium.util.TiConvert;

int val = TiConvert.toInt(obj);float val = TiConvert.toFloat(obj);double val = TiConvert.toDouble(obj);boolean val = TiConvert.toBoolean(obj);int color = TiConvert.toColor(str);...

Supported Directly Conversion Utilities

http://builds.appcelerator.com.s3.amazonaws.com/module-apidoc/2.0.0/android/or!/appcelerator/titanium/util/TiConvert.html

Page 69: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Return Values

• Sin!le Value (Strin!, Inte!er, …)

• Collections (Object[])★ Converted into a JS Array object

• Dictionary (HashMap<Strin!, Object>)★ Converted into a JS object★ key->value ===> property->value

• Proxy (TiProxy)

41

Page 70: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Polymorphic Methods

42

-(id)convert:(id)args{ ENSURE_ARG_COUNT(args, 1);

id arg = [args objectAtIndex:0]; if ([arg isKindOfClass:[NSString class]]) { return [self convertFromString:arg]; } else if ([arg isKindOfClass:[TiBlob class]]) { return [self convertFromData:arg]; } else { [self throwException:@"Expected blob or string argument"

subreason:nil location:CODELOCATION]; }}

Page 71: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Polymorphic Methods

43

public KrollDict convertFromString(String xml);public KrollDict convertFromBlob(TiBlob blob) @Kroll.methodpublic String convert(Object arg) {

if (arg instanceof String) { return "string"; } if (arg instanceof TiBlob) { return "blob"; } throw new IllegalArgumentException("Invalid argument type,

expected blob or string");}

Page 72: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Varargs

44

-(void) varArgsMethod:(id)args{ for (int i = 0; i < [args count]; i++) { id arg = [args objectAtIndex:i]; // do something with arg }}

Page 73: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Varargs

45

@Kroll.methodpublic void varArgsMethod(Object[] args) {

for (int i = 0; i < args.length; i++) { Object arg = args[i];

// do something with arg }}

Page 74: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Properties

46

module.propertyName = "HELLO";

Ti.API.info("Property: " + module.propertyName);

set

!et

Page 75: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Properties

47

@interface TiMyModule: TiModule

@property (nonatomic, readwrite, retain) NSString* propertyName;

@end

@implementation TiMyModule: TiModule

@synthesize propertyName;

@end

TiMyModule.h

TiMyModule.m

Page 76: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Properties: Setter/Getter

48

- (void) setPropertyName:(id)args { // set property and do stuff}

- (id) propertyName { // do something and return value;}

Page 77: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Properties: Setter/Getter

49

@Kroll.module(name="My", id="ti.my")public class MyModule extends KrollModule{

private String propertyName; @Kroll.getProperty @Kroll.method public String getPropertyName() { return propertyName; } @Kroll.setProperty @Kroll.method public void setPropertyName(String value) { propertyName = value; }}

Page 78: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Constants

50

var smsModule = require('ti.ios.sms');

function sendCallback(e){ switch (e.result) {

case sms.SENT: result = 'SENT'; break; case sms.FAILED: result = 'FAILED'; break; case sms.CANCELLED: result = 'CANCELLED'; break; } Ti.API.info("Property: " + module.propertyName);}

Page 79: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Constants

51

//create the accessor methods for the SENT, CANCELLED and FAILED constantsMAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);

https://!ithub.com/omorandi/TiSMSDialo!/blob/master/Classes/ComOmorandiSMSDialo!Proxy.m

Page 80: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Constants

51

//create the accessor methods for the SENT, CANCELLED and FAILED constantsMAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);

https://!ithub.com/omorandi/TiSMSDialo!/blob/master/Classes/ComOmorandiSMSDialo!Proxy.m

#define MAKE_SYSTEM_PROP(name,map) \-(NSNumber*)name \{\return [NSNumber numberWithInt:map];\}\

TiBase.h

Page 81: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Constants

51

//create the accessor methods for the SENT, CANCELLED and FAILED constantsMAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);

https://!ithub.com/omorandi/TiSMSDialo!/blob/master/Classes/ComOmorandiSMSDialo!Proxy.m

#define MAKE_SYSTEM_PROP(name,map) \-(NSNumber*)name \{\return [NSNumber numberWithInt:map];\}\

TiBase.h

@Kroll.module(name="Sms", id="ti.android.sms")public class SmsModule extends KrollModule{ @Kroll.constant public static final int SENT = 0; @Kroll.constant public static final int CANCELLED = -1; @Kroll.constant public static final int FAILED = -2;}

Page 82: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy Objects

52

var smsModule = require('ti.ios.sms');

//create the smsDialog objectvar smsDialog = smsModule.createSMSDialog({ recipients: ['+123456789'], messageBody: 'hello'});

smsDialog.open();

Page 83: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Creating a Proxy

53

@interface TiIosSmsSMSDialogProxy: TiProxy<MFMessageComposeViewControllerDelegate>

@end

@implementation TiIosSmsSMSDialogProxy

- (void)open:(id)args{

// retrieve properties (either set on creation, or later)

NSArray * recipients = [self valueForUndefinedKey:@"recipients"];NSString * messageBody= [TiUtils stringValue:[self valueForUndefinedKey:@"messageBody"]];

// do stuff

}

@end

TiIosSmsSMSDialo!Proxy.h

TiIosSmsSMSDialo!Proxy.m

Page 84: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Proxy Objects

54

var smsModule = require('ti.android.sms');

//create the sms objectvar sms = smsModule.createSms({ recipient: '+123456789', messageBody: 'hello'});

sms.send();

Page 85: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Creating a Proxy

55

@Kroll.proxy(creatableInModule=SmsModule.class)public class SmsProxy extends KrollProxy{ private String messageBody = null; private String recipient = null;

// Constructor public SmsProxy() { super(); }

// Handle creation options @Override public void handleCreationDict(KrollDict options) { super.handleCreationDict(options); if (options.containsKey("messageBody")) { messageBody = (String)options.get("messageBody"); } if (options.containsKey("recipient")) { recipient = (String)options.get("recipient"); } }

@Kroll.method public void send() {

// send the message}

}

Page 86: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Events

56

// create the Module objectvar tibarcode = require('ti.barcode');

var scanner = tibarcode.createScanner();

// success event listenerscanner.addEventListener('success', function(e) { var code = e.barcode; var type = e.type; alert('Found code: ' + code + ' type: ' + type);});

Notify a chan!e of state, or an asynchronous event

Page 87: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Events

57

@implementation TiBarcodeScannerProxy

// Scanner Delegate

- (void) imagePickerController: (UIImagePickerController*)reader didFinishPickingMediaWithCode:(NSString*)code andType:(NSString*)type

{ if ([self _hasListeners:@"success"]){ NSDictionary *results = [NSDictionary dictionaryWithObjectsAndKeys: code, @"code", type, @"type", nil];

[self fireEvent:@"success" withObject:results]; }}

@end

Page 88: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Events

58

public class ScannerProxy extends KrollProxy{

void onScannerResult(String code, String type) {

if (hasListeners("success")) { KrollDict event = new KrollDict(); event.put("code", code); event.put("type", type); fireEvent("success", event); } }}

Page 89: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Callbacks

59

// let's not freeze on huge xml dataxml2json.convertAsync(xmlDoc, function(data) { Ti.API.info("JSON object: " + JSON.stringify(data.json));});

Notify the result of an asynchronous action

Page 90: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Callbacks

60

-(void)convertAsync:(id)args{ ENSURE_ARG_COUNT(args, 2); id xml = [args objectAtIndex:0]; KrollCallback *cb = [args objectAtIndex:1]; ENSURE_TYPE(cb, KrollCallback); //pass just the first (string|blob) arg to convertXml() dispatch_async(dispatchQueue, ^(void) { id result = [self convertXml:xml]; NSDictionary *cbArgs = [NSDictionary dictionaryWithObject:result forKey:@"json"]; [self _fireEventToListener:@"success" withObject:cbArgs listener:cb

thisObject:nil]; });}

Page 91: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Callbacks

61

@Kroll.methodpublic KrollDict convertAsync(String xml, final KrollFunction callback){

new Thread() { @Override public void run() { KrollDict json = null;

//do conversion stuff

KrollDict data = new KrollDict(); event.put("json", json); callback.call(getKrollObject(), data); } }.start();}

Page 92: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

ViewProxy

62

View

Prox

y

View

Nativ

e Vi

ews

Hier

arch

y

Methods

Properties (!et/set)

Events

Holds the state of a view

Mana!es the native view hierarchy

Page 93: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

ViewProxy

62

View

Prox

y

View

Nativ

e Vi

ews

Hier

arch

y

Methods

Properties (!et/set)

Events

Holds the state of a view

Mana!es the native view hierarchy

JS THREAD

Page 94: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

ViewProxy

62

View

Prox

y

View

Nativ

e Vi

ews

Hier

arch

y

Methods

Properties (!et/set)

Events

Holds the state of a view

Mana!es the native view hierarchy

JS THREAD UI THREAD

Page 95: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

ViewProxy

62

View

Prox

y

View

Nativ

e Vi

ews

Hier

arch

y

Methods

Properties (!et/set)

Events

Holds the state of a view

Mana!es the native view hierarchy

JS THREAD UI THREAD

Mostly async

Page 96: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Super-Smooth TableView

63

• API• createMessagesView(properties);• setMessages([]messages);• insert(message);• addEventListener(‘click’, callback);

Page 97: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

64

@implementation TiSmoothMessagesViewProxy

@synthesize msgs;

//other methods

-(void) insert:(id)args{ ENSURE_SINGLE_ARG(args, NSDictionary); [self.msgs insertMessageOnTop:[self messageFromDictionary:(NSDictionary*)args]];

[self makeViewPerformSelector:@selector(addMessage:) withObject:args createIfNeeded:YES waitUntilDone:NO];

}

@end

Messa!esViewProxy

@interface TiSmoothMessagesViewProxy : TiViewProxy

@property (nonatomic, retain) MessagesCollection *msgs; //model

@end

TiSmoothMessa!esViewProxy.h

TiSmoothMessa!esViewProxy.m

Page 98: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

64

@implementation TiSmoothMessagesViewProxy

@synthesize msgs;

//other methods

-(void) insert:(id)args{ ENSURE_SINGLE_ARG(args, NSDictionary); [self.msgs insertMessageOnTop:[self messageFromDictionary:(NSDictionary*)args]];

[self makeViewPerformSelector:@selector(addMessage:) withObject:args createIfNeeded:YES waitUntilDone:NO];

}

@end

Messa!esViewProxy

@interface TiSmoothMessagesViewProxy : TiViewProxy

@property (nonatomic, retain) MessagesCollection *msgs; //model

@end

TiSmoothMessa!esViewProxy.h

TiSmoothMessa!esViewProxy.m

create the view and call addMessa!e on the UI thread

Page 99: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

65

@implementation TiSmoothMessagesView

-(void)initializeState{ [super initializeState]; viewController = [[InboxViewController alloc] initWithStyle:UITableViewStylePlain];

UITableView *tableView = viewController.tableView; [self addSubview:tableView];}

-(void)addMessage:(InboxMessage*)message{ ENSURE_UI_THREAD(addMessage, message); [viewController addMessageOnTop:message];}

-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds{ [TiUtils setView: viewController.tableView positionRect:bounds];}

@end

Messa!esView

@interface TiSmoothMessagesView : TiUIView {

MessagesViewController *viewController;}

@end

TiSmoothMessa!esView.h

TiSmoothMessa!esView.m

Page 100: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

65

@implementation TiSmoothMessagesView

-(void)initializeState{ [super initializeState]; viewController = [[InboxViewController alloc] initWithStyle:UITableViewStylePlain];

UITableView *tableView = viewController.tableView; [self addSubview:tableView];}

-(void)addMessage:(InboxMessage*)message{ ENSURE_UI_THREAD(addMessage, message); [viewController addMessageOnTop:message];}

-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds{ [TiUtils setView: viewController.tableView positionRect:bounds];}

@end

Messa!esView

@interface TiSmoothMessagesView : TiUIView {

MessagesViewController *viewController;}

@end

TiSmoothMessa!esView.h

TiSmoothMessa!esView.m

called by Titanium at view creation

Page 101: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Implementation

65

@implementation TiSmoothMessagesView

-(void)initializeState{ [super initializeState]; viewController = [[InboxViewController alloc] initWithStyle:UITableViewStylePlain];

UITableView *tableView = viewController.tableView; [self addSubview:tableView];}

-(void)addMessage:(InboxMessage*)message{ ENSURE_UI_THREAD(addMessage, message); [viewController addMessageOnTop:message];}

-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds{ [TiUtils setView: viewController.tableView positionRect:bounds];}

@end

Messa!esView

@interface TiSmoothMessagesView : TiUIView {

MessagesViewController *viewController;}

@end

TiSmoothMessa!esView.h

TiSmoothMessa!esView.m

called by Titanium at view creation

called by Titanium for notifyin! a chan!e in frame size

Page 102: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 66

//// PLACE ANY BUILD DEFINITIONS IN THIS FILE AND THEY WILL BE // PICKED UP DURING THE APP BUILD FOR YOUR MODULE//

OTHER_LDFLAGS=$(inherited) -framework AVFoundation -framework CoreMedia -framework CoreVideo -framework QuartzCore /usr/lib/libiconv.dylib

module.xcconfi!

Module Packa!e(.zip)

build & packa!e

app bundle

Page 103: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 66

//// PLACE ANY BUILD DEFINITIONS IN THIS FILE AND THEY WILL BE // PICKED UP DURING THE APP BUILD FOR YOUR MODULE//

OTHER_LDFLAGS=$(inherited) -framework AVFoundation -framework CoreMedia -framework CoreVideo -framework QuartzCore /usr/lib/libiconv.dylib

module.xcconfi!

Module Packa!e(.zip)

build & packa!e

app bundle

Page 104: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013 67

<?xml version="1.0" encoding="UTF-8"?><ti:module xmlns:ti="http://ti.appcelerator.org" xmlns:android="http://schemas.android.com/apk/res/android"> <iphone> </iphone> <android xmlns:android="http://schemas.android.com/apk/res/android"> <manifest> <uses-permission android:name="android.permission.SEND_SMS" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application> <activity android:name="ti.conf.sample.MyCustomActivity"> </activity> </application> </manifest> </android> <mobileweb> </mobileweb></ti:module>

timodule.xml

Module Packa!e(.zip)

build & packa!e AndroidManifest.xml

app.apk

Page 105: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Debu!!in!

Page 106: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Create a debug build

69

$ sed s/Release/Debug/ build.py > build_debug.py

168: rc = os.system("xcodebuild -sdk iphoneos -configuration Debug")171: rc = os.system("xcodebuild -sdk iphonesimulator -configuration Debug")

build_debu!.py

168: rc = os.system("xcodebuild -sdk iphoneos -configuration Release")171: rc = os.system("xcodebuild -sdk iphonesimulator -configuration Release")

build.py

Page 107: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Debugging

70

Page 108: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Debug Logs

71

@Kroll.module(name="Ticonfsample", id="ti.conf.sample")public class TiconfsampleModule extends KrollModule{

// Tag for debug log messages private static final String LCAT = "TiconfsampleModule";

// tells if debug logging has been enabled in the Titanium application private static final boolean DBG = TiConfig.LOGD;

@Kroll.method public void doSomething() { Log.d(LCAT, "doing something"); }}

Page 109: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Android DDMS

72

Page 110: Extending Titanium with native iOS and Android modules

tiConf.eu, valencia, 24/02/2013

Thank you!