3. Module
development is so
2010
tiConf.eu, valencia, 24/02/2013
4. Why Bother?
• To leverage native features
★ Underlying OS
★ 3rd party libraries
• Performance
★ To optimize the User Experience
tiConf.eu, valencia, 24/02/2013 4
19. Terminology
module
object
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();
he
cts of t
Obje A PI a
re
nium S
Tita in the J
cted pp
inje nt at a
ro nme
envi p
s tartu
tiConf.eu, valencia, 24/02/2013 14
34. iOS Prerequisites
• Same as for Ti app development on iOS:
★ Titanium SDK.
★ Xcode
tiConf.eu, valencia, 24/02/2013 19
35. Android Prerequisites
• 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)
★ gperf must be installed and in your system PATH.
★ [Eclipse]
tiConf.eu, valencia, 24/02/2013 20
36. Create (cli)
$ alias ti='~/Library/Application Support/Titanium/mobilesdk/osx/3.0.0.GA/
titanium.py'
OL
SCHO
OLD
tiConf.eu, valencia, 24/02/2013 21
37. 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
OL
SCHO
OLD
tiConf.eu, valencia, 24/02/2013 21
38. 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
OL
SCHO
OLD
tiConf.eu, valencia, 24/02/2013 21
64. Return Values
• Single Value (NSString, NSNumber, …)
• Collections (NSArray)
★ Converted into a JS Array object
• Dictionary (NSDictionary)
★ Converted into a JS object
★ key->value ===> property->value
• Proxy (TiProxy)
tiConf.eu, valencia, 24/02/2013 38
65. Return Values
• Single Value (NSString, NSNumber, …)
• Collections (NSArray)
★ Converted into a JS Array object
• Dictionary (NSDictionary)
★ Converted into a JS object TS
BJEC
★ key->value ===> property->value DO
SE
EA
EL
OR
• Proxy (TiProxy) UR
NA
UT
RET
tiConf.eu, valencia, 24/02/2013 38
76. Properties: Setter/Getter
- (void) setPropertyName:(id)args {
// set property and do stuff
}
- (id) propertyName {
// do something and
return value;
}
tiConf.eu, valencia, 24/02/2013 48
77. Properties: Setter/Getter
@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;
}
}
tiConf.eu, valencia, 24/02/2013 49
78. Constants
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);
}
tiConf.eu, valencia, 24/02/2013 50
79. Constants
https://github.com/omorandi/TiSMSDialog/blob/master/Classes/ComOmorandiSMSDialogProxy.m
//create the accessor methods for the SENT, CANCELLED and FAILED
constants
MAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);
MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);
MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);
tiConf.eu, valencia, 24/02/2013 51
80. Constants
https://github.com/omorandi/TiSMSDialog/blob/master/Classes/ComOmorandiSMSDialogProxy.m
//create the accessor methods for the SENT, CANCELLED and FAILED
constants
MAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);
MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);
MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);
TiBase.h
#define MAKE_SYSTEM_PROP(name,map)
-(NSNumber*)name
{
return [NSNumber numberWithInt:map];
}
tiConf.eu, valencia, 24/02/2013 51
81. Constants
https://github.com/omorandi/TiSMSDialog/blob/master/Classes/ComOmorandiSMSDialogProxy.m
//create the accessor methods for the SENT, CANCELLED and FAILED
constants
MAKE_SYSTEM_PROP(SENT,MessageComposeResultSent);
MAKE_SYSTEM_PROP(CANCELLED,MessageComposeResultCancelled);
MAKE_SYSTEM_PROP(FAILED,MessageComposeResultFailed);
TiBase.h
#define MAKE_SYSTEM_PROP(name,map)
-(NSNumber*)name
{
return [NSNumber numberWithInt:map];
}
@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;
}
tiConf.eu, valencia, 24/02/2013 51
82. Proxy Objects
var smsModule = require('ti.ios.sms');
//create the smsDialog object
var smsDialog = smsModule.createSMSDialog({
recipients: ['+123456789'],
messageBody: 'hello'
});
smsDialog.open();
tiConf.eu, valencia, 24/02/2013 52
83. Creating a Proxy
TiIosSmsSMSDialogProxy.h
@interface TiIosSmsSMSDialogProxy: TiProxy<MFMessageComposeViewControllerDelegate>
@end
TiIosSmsSMSDialogProxy.m
@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
tiConf.eu, valencia, 24/02/2013 53
84. Proxy Objects
var smsModule = require('ti.android.sms');
//create the sms object
var sms = smsModule.createSms({
recipient: '+123456789',
messageBody: 'hello'
});
sms.send();
tiConf.eu, valencia, 24/02/2013 54
85. Creating a Proxy
@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
}
}
tiConf.eu, valencia, 24/02/2013 55
86. Events
Notify a change of state, or an asynchronous event
// create the Module object
var tibarcode = require('ti.barcode');
var scanner = tibarcode.createScanner();
// success event listener
scanner.addEventListener('success', function(e) {
var code = e.barcode;
var type = e.type;
alert('Found code: ' + code + ' type: ' + type);
});
tiConf.eu, valencia, 24/02/2013 56
88. Events
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);
}
}
}
tiConf.eu, valencia, 24/02/2013 58
89. Callbacks
Notify the result of an asynchronous action
// let's not freeze on huge xml data
xml2json.convertAsync(xmlDoc, function(data) {
Ti.API.info("JSON object: " + JSON.stringify(data.json));
});
tiConf.eu, valencia, 24/02/2013 59
90. Callbacks
-(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];
});
}
tiConf.eu, valencia, 24/02/2013 60
91. Callbacks
@Kroll.method
public 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();
}
tiConf.eu, valencia, 24/02/2013 61
92. ViewProxy
Manages the
Holds the state
native view
of a view
hierarchy
Methods
Native Views
ViewProxy
Hierarchy
Properties
View
(get/set)
Events
tiConf.eu, valencia, 24/02/2013 62
93. ViewProxy
Manages the
Holds the state
native view
of a view
hierarchy
Methods
Native Views
ViewProxy
Hierarchy
Properties
View
(get/set)
Events
JS THREAD
tiConf.eu, valencia, 24/02/2013 62
94. ViewProxy
Manages the
Holds the state
native view
of a view
hierarchy
Methods
Native Views
ViewProxy
Hierarchy
Properties
View
(get/set)
Events
JS THREAD UI THREAD
tiConf.eu, valencia, 24/02/2013 62
95. ViewProxy
Manages the
Holds the state
native view
of a view
hierarchy
Methods
Native Views
ViewProxy
Hierarchy
Properties
View
(get/set)
Events
JS THREAD UI THREAD
Mostly async
tiConf.eu, valencia, 24/02/2013 62
101. Implementation
MessagesView
TiSmoothMessagesView.h
@interface TiSmoothMessagesView : TiUIView
{
MessagesViewController *viewController;
}
@end
TiSmoothMessagesView.m
@implementation TiSmoothMessagesView
-(void)initializeState called by Titanium at view creation
{
[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
called by Titanium for notifying a
{ change in frame size
[TiUtils setView: viewController.tableView positionRect:bounds];
}
@end
tiConf.eu, valencia, 24/02/2013 65
102. module.xcconfig
//
// 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
build &
package
Module Package
(.zip)
app bundle
tiConf.eu, valencia, 24/02/2013 66
103. module.xcconfig
//
// 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
build &
package
Module Package
(.zip)
app bundle
tiConf.eu, valencia, 24/02/2013 66
108. Debug Logs
@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");
}
}
tiConf.eu, valencia, 24/02/2013 71