Post on 23-Aug-2014
description
TICONF EU, AMSTERDAM, 29/06/2014
{native: “FTW”} !
Integrating native views in Titanium apps
Olivier Morandi
TICONF EU, AMSTERDAM, 29/06/2014
Olivier Morandi Software engineer !
http://titaniumninja.com!olivier.morandi@gmail.com @olivier_morandi https://github.com/omorandi
2
TICONF EU, AMSTERDAM, 29/06/2014 3
TICONF EU, AMSTERDAM, 29/06/2014
• Ti app development
• Native module development (iOS/Android)
• Optimisations
• R&D
4
TICONF EU, AMSTERDAM, 29/06/2014
This Talk
• How to create view-based native modules
• How to integrate third party libraries
5
TICONF EU, AMSTERDAM, 29/06/2014
Not in This Talk
• Basics of native module development ★ module creation ★ proxies, methods, properties, events,
callbacks
• Check out http://www.slideshare.net/omorandi/ticonf
6
TICONF EU, AMSTERDAM, 29/06/2014
Why Native Views• UX/Performance ★ Stock Ti UI components not suitable for
the specific UX requirements
• Integration of native UI components and libraries ★ Leverage existing solutions from the
Android and iOS OSS communities ★ Integrate third party SDKs
7
TICONF EU, AMSTERDAM, 29/06/2014
Ti.Next/Hyperloop
• Q: Are Ti.Current native modules still relevant?
• A: YES! ★ Ti.Next/Hyperloop is WIP ★ Active need in current Titanium projects ★ Maintaining legacy modules
8
TICONF EU, AMSTERDAM, 29/06/2014
Learning Resources
TICONF EU, AMSTERDAM, 29/06/2014
Official Appcelerator Guides
• http://docs.appcelerator.com/titanium/latest/#!/guide/Extending_Titanium_Mobile
• http://docs.appcelerator.com/titanium/latest/#!/guide/iOS_Module_Development_Guide
• http://docs.appcelerator.com/titanium/latest/#!/guide/Android_Module_Development_Guide
10
TICONF EU, AMSTERDAM, 29/06/2014 11
TICONF EU, AMSTERDAM, 29/06/2014
Source code
• Titanium Mobile SDK ★ https://github.com/appcelerator/
titanium_mobile
• Open source modules from Appcelerator ★ https://github.com/appcelerator/
titanium_modules
12
TICONF EU, AMSTERDAM, 29/06/2014
Follow these people (and more)• Aaron K. Saunders: https://github.com/aaronksaunders
• Adam Paxton: https://github.com/adampax/
• Ben Bahrenburg: https://github.com/benbahrenburg
• David Bankier: https://github.com/dbankier
• Jordi Domenec: https://github.com/iamyellow
• Mads Møller: https://github.com/viezel
• Marcel Pociot: https://github.com/mpociot
• Matt Apperson: https://github.com/mattapperson
• Paul Mietz Egli: https://github.com/pegli
• Ruben Fonseca: https://github.com/rubenfonseca
• Many more… find them on http://gitt.io/
13
TICONF EU, AMSTERDAM, 29/06/2014
Architecture Recap
TICONF EU, AMSTERDAM, 29/06/2014 15
Titanium cli (node.js)
TICONF EU, AMSTERDAM, 29/06/2014
Runtime (iOS)
16
Titanium Modules
(API)
JS APP
Parser
Interpreter
IOS SDK
Bytecode gen
Java
Scrip
tCor
e
objective-c C++
KRO
LL B
RIDG
E
TICONF EU, AMSTERDAM, 29/06/2014
Runtime (iOS)
16
Titanium Modules
(API)
JS APP
Parser
Interpreter
IOS SDK
Bytecode gen
Java
Scrip
tCor
e
NO JIT
objective-c C++
KRO
LL B
RIDG
E
TICONF EU, AMSTERDAM, 29/06/2014
Titanium Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code gen
KRO
LL B
RIDG
E
Runtime (Android)
17
Java C++
V8
OPT
TICONF EU, AMSTERDAM, 29/06/2014
Titanium Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code gen
KRO
LL B
RIDG
E
Runtime (Android)
17
Java C++
V8
OPT
TICONF EU, AMSTERDAM, 29/06/2014
Titanium Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code gen
KRO
LL B
RIDG
E
Runtime (Android)
17
Java C++
V8
OPT
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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();
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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();
module object
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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();
factory method
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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 object
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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 proxy object
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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
TICONF EU, AMSTERDAM, 29/06/2014
Terminology
18
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
TICONF EU, AMSTERDAM, 29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
Native View Type iOS UIView
Android View
extends
TICONF EU, AMSTERDAM, 29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
Native View Type iOS UIView
Android View
State: properties
Actions: methods
Events: addEventListener(), fireEvent()
Interface
extends
TICONF EU, AMSTERDAM, 29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
Native View Type iOS UIView
Android View
State: properties
Actions: methods
Events: addEventListener(), fireEvent()
Interface
Methods for the integration within the application lifecycle •startup() (iOS) •shutdown() (iOS) •onAppCreate() (Android)
extends
TICONF EU, AMSTERDAM, 29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
Native View Type iOS UIView
Android View
State: properties
Actions: methods
Events: addEventListener(), fireEvent()
Interface
Additional members for the integration within the UI layout system: •add() •remove() •height •width •backgroundColor •...
Methods for the integration within the application lifecycle •startup() (iOS) •shutdown() (iOS) •onAppCreate() (Android)
extends
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy
20
View
Prox
y
View
Nativ
e Vi
ews
Hier
arch
y
Methods
Properties (get/set)
Events
Holds the state of a view
Manages the native view hierarchy
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy
20
View
Prox
y
View
Nativ
e Vi
ews
Hier
arch
y
Methods
Properties (get/set)
Events
Holds the state of a view
Manages the native view hierarchy
JS THREAD
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy
20
View
Prox
y
View
Nativ
e Vi
ews
Hier
arch
y
Methods
Properties (get/set)
Events
Holds the state of a view
Manages the native view hierarchy
JS THREAD UI THREAD
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy
20
View
Prox
y
View
Nativ
e Vi
ews
Hier
arch
y
Methods
Properties (get/set)
Events
Holds the state of a view
Manages the native view hierarchy
JS THREAD UI THREAD
ASYNC
TICONF EU, AMSTERDAM, 29/06/2014
A Basic Native View
TICONF EU, AMSTERDAM, 29/06/2014 22
TICONF EU, AMSTERDAM, 29/06/2014
Usage Scenario
23
var win = Ti.UI.createWindow({ backgroundColor: 'white' }); !var ticonf = require('ti.conf'); !var basicView = ticonf.createBasicView({ width: 100, height: 100 }); !win.add(basicView); !win.open();
app.js
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy Class
24
#import "TiViewProxy.h" !@interface TiConfBasicViewProxy : TiViewProxy @end
TiConfBasicViewProxy.h
TiConfBasicViewProxy.m#import "TiConfBasicViewProxy.h" !@implementation TiConfBasicViewProxy !!@end
TICONF EU, AMSTERDAM, 29/06/2014
View Class
25
#import "TiUIView.h" !@interface TiConfBasicView : TiUIView { UIView *theView; } @end
TiConfBasicView.h
TiConfBasicView.m#import "TiConfBasicView.h" !@implementation TiConfBasicView !-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !@end
TICONF EU, AMSTERDAM, 29/06/2014 26
TICONF EU, AMSTERDAM, 29/06/2014 26
WTF: where’s my view?
TICONF EU, AMSTERDAM, 29/06/2014 26
WTF: where’s my view?
TiConfBasicView
TICONF EU, AMSTERDAM, 29/06/2014 26
WTF: where’s my view?
TiConfBasicView
theView
TICONF EU, AMSTERDAM, 29/06/2014
Managing the subview frame
27
TiConfBasicView.m#import "TiConfBasicView.h" !@implementation TiConfBasicView !!-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !@end
TICONF EU, AMSTERDAM, 29/06/2014
Managing the subview frame
27
TiConfBasicView.m#import "TiConfBasicView.h" !@implementation TiConfBasicView !!-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !@end
The Ti View frame is managed by the Ti layout system.
Bounds are not valid until the view takes part to an on-screen Ti view hierarchy
TICONF EU, AMSTERDAM, 29/06/2014
Managing the subview frame
27
TiConfBasicView.m#import "TiConfBasicView.h" !@implementation TiConfBasicView !!-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !@end
The Ti View frame is managed by the Ti layout system.
Bounds are not valid until the view takes part to an on-screen Ti view hierarchy
TICONF EU, AMSTERDAM, 29/06/2014
An alternative
28
TiConfBasicView.m-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !!!-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds { theView.frame = bounds; }
TICONF EU, AMSTERDAM, 29/06/2014
An alternative
28
TiConfBasicView.m-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; theView.backgroundColor = [UIColor redColor]; [self addSubview:theView]; } !!!-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds { theView.frame = bounds; }
called by -[TiUIView drawRect:]
TICONF EU, AMSTERDAM, 29/06/2014
ViewProxy Class
29
@Kroll.proxy(creatableInModule=AndroidModule.class) public class BasicViewProxy extends TiViewProxy { // Constructor public BasicViewProxy() { super(); } ! @Override public TiUIView createView(Activity activity) { TiUIView view = new BasicView(this); return view; } !}
BasicViewProxy.java
TICONF EU, AMSTERDAM, 29/06/2014
View Class
30
public class BasicView extends TiUIView { View theView; public BasicView(TiViewProxy proxy) { super(proxy); ! Activity context = proxy.getActivity(); theView = new View(context); theView.setBackgroundColor(Color.RED); getLayoutParams().autoFillsHeight = true; getLayoutParams().autoFillsWidth = true; setNativeView(theView); } !}
BasicView.java
TICONF EU, AMSTERDAM, 29/06/2014 31
TICONF EU, AMSTERDAM, 29/06/2014
Properties
• Properties belong to the ViewProxy object
• How do we make use of property values in View objects?
32
TICONF EU, AMSTERDAM, 29/06/2014
Setting a property
33
var basicView = ticonf.createBasicView({ color: "red" }); !//or !basicView.color = "red";
TICONF EU, AMSTERDAM, 29/06/2014
Property from the Proxy
34
!UIColor *color = [[TiUtils colorValue:[self.proxy valueForKey:@"color"]] color];
TiConfBasicView.m
Retrieving the property value from the ViewProxy when needed
TICONF EU, AMSTERDAM, 29/06/2014
Explicit Setter in the ViewProxy
35
-(void)setColor:(UIColor*)color { theView.backgroundColor = color; }
TiConfBasicView.m
-(void)setColor:(id)args { //expect 1 argument ENSURE_ARG_COUNT(args, 1); UIColor *color = [[TiUtils colorValue:args] color]; //dispatch to the view on UI thread //(create it if needed, don't wait for completion) [self makeViewPerformSelector:@selector(setColor:) withObject:color createIfNeeded:YES waitUntilDone:NO]; }
TiConfBasicViewProxy.m
TICONF EU, AMSTERDAM, 29/06/2014
Explicit Setter in the ViewProxy
35
-(void)setColor:(UIColor*)color { theView.backgroundColor = color; }
TiConfBasicView.m
-(void)setColor:(id)args { //expect 1 argument ENSURE_ARG_COUNT(args, 1); UIColor *color = [[TiUtils colorValue:args] color]; //dispatch to the view on UI thread //(create it if needed, don't wait for completion) [self makeViewPerformSelector:@selector(setColor:) withObject:color createIfNeeded:YES waitUntilDone:NO]; }
TiConfBasicViewProxy.m
JS THREAD
TICONF EU, AMSTERDAM, 29/06/2014
Explicit Setter in the ViewProxy
35
-(void)setColor:(UIColor*)color { theView.backgroundColor = color; }
TiConfBasicView.m
-(void)setColor:(id)args { //expect 1 argument ENSURE_ARG_COUNT(args, 1); UIColor *color = [[TiUtils colorValue:args] color]; //dispatch to the view on UI thread //(create it if needed, don't wait for completion) [self makeViewPerformSelector:@selector(setColor:) withObject:color createIfNeeded:YES waitUntilDone:NO]; }
TiConfBasicViewProxy.m
JS THREAD
UI THREAD
TICONF EU, AMSTERDAM, 29/06/2014
Implicit Setter in the View Class
36
-(void)setColor_:(id)arg { theView.backgroundColor = [[TiUtils colorValue:arg] color]; }
TiConfBasicView.m
TICONF EU, AMSTERDAM, 29/06/2014
Implicit Setter in the View Class
36
-(void)setColor_:(id)arg { theView.backgroundColor = [[TiUtils colorValue:arg] color]; }
TiConfBasicView.m
Automatically dispatched by the ViewProxy on the UI thread
TICONF EU, AMSTERDAM, 29/06/2014
Property from the Proxy
37
!int color = TiConvert.toColor((String) proxy.getProperty(“color"));
BasicView.java
TICONF EU, AMSTERDAM, 29/06/2014
Creation Properties
38
BasicView.java@Override public void processProperties(KrollDict props) { super.processProperties(props); if (props.containsKey("color")) { theView.setBackgroundColor(TiConvert.toColor(props.getString("color"))); } else if (…) { //do something else } }
TICONF EU, AMSTERDAM, 29/06/2014
Property Changed Listener
39
BasicView.java@Override public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy) { if (key.equals("color")) { theView.setBackgroundColor(TiConvert.toColor((String)newValue)); } else if () { //do something else } }
public abstract class TiUIView implements KrollProxyListener
titanium_mobile/android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java:73
TICONF EU, AMSTERDAM, 29/06/2014
Methods
• Exposed to JS by the ViewProxy object
• Dispatched to the View object
40
TICONF EU, AMSTERDAM, 29/06/2014
View Methods
41
basicView.makeRounded();
TICONF EU, AMSTERDAM, 29/06/2014 42
TICONF EU, AMSTERDAM, 29/06/2014
View Method
43
-(void)makeRounded { theView.layer.cornerRadius = 20; }
TiConfBasicView.m
-(void)makeRounded:(id)args { ENSURE_UI_THREAD(makeRounded, args); TiConfBasicView *thisView = (TiConfBasicView*)[self view]; [thisView makeRounded]; }
TiConfBasicViewProxy.m
TICONF EU, AMSTERDAM, 29/06/2014
View Method
43
-(void)makeRounded { theView.layer.cornerRadius = 20; }
TiConfBasicView.m
-(void)makeRounded:(id)args { ENSURE_UI_THREAD(makeRounded, args); TiConfBasicView *thisView = (TiConfBasicView*)[self view]; [thisView makeRounded]; }
TiConfBasicViewProxy.mJS
THREAD
TICONF EU, AMSTERDAM, 29/06/2014
View Method
43
-(void)makeRounded { theView.layer.cornerRadius = 20; }
TiConfBasicView.m
-(void)makeRounded:(id)args { ENSURE_UI_THREAD(makeRounded, args); TiConfBasicView *thisView = (TiConfBasicView*)[self view]; [thisView makeRounded]; }
TiConfBasicViewProxy.mJS
THREAD
UI THREAD
TICONF EU, AMSTERDAM, 29/06/2014
Dispatching via GCD
44
-(void)makeRounded { theView.layer.cornerRadius = 20; }
TiConfBasicView.m
-(void)makeRounded:(id)args { dispatch_async(dispatch_get_main_queue(), ^{ TiConfBasicView *thisView = (TiConfBasicView*)[self view]; [thisView makeRounded]; }); }
TiConfBasicViewProxy.m
TICONF EU, AMSTERDAM, 29/06/2014
View Method Dispatching
45
public void makeRounded() { GradientDrawable shape = new GradientDrawable(); shape.setColor(Color.RED); shape.setCornerRadius(50); theView.setBackgroundDrawable(shape); }
BasicView.java
@Kroll.method public void makeRounded() { TiMessenger.postOnMain(new Runnable() { ! @Override public void run() { BasicView view = (BasicView)getOrCreateView(); view.makeRounded(); } }); }
BasicViewProxy.java
TICONF EU, AMSTERDAM, 29/06/2014
View Method Dispatching
45
public void makeRounded() { GradientDrawable shape = new GradientDrawable(); shape.setColor(Color.RED); shape.setCornerRadius(50); theView.setBackgroundDrawable(shape); }
BasicView.java
@Kroll.method public void makeRounded() { TiMessenger.postOnMain(new Runnable() { ! @Override public void run() { BasicView view = (BasicView)getOrCreateView(); view.makeRounded(); } }); }
BasicViewProxy.java
JS THREAD
TICONF EU, AMSTERDAM, 29/06/2014
View Method Dispatching
45
public void makeRounded() { GradientDrawable shape = new GradientDrawable(); shape.setColor(Color.RED); shape.setCornerRadius(50); theView.setBackgroundDrawable(shape); }
BasicView.java
@Kroll.method public void makeRounded() { TiMessenger.postOnMain(new Runnable() { ! @Override public void run() { BasicView view = (BasicView)getOrCreateView(); view.makeRounded(); } }); }
BasicViewProxy.java
JS THREAD
UI THREAD
TICONF EU, AMSTERDAM, 29/06/2014
Message Dispatching
46
private static final int MSG_MAKE_ROUNDED = TiViewProxy.MSG_LAST_ID + 4001; protected static final int MSG_LAST_ID = MSG_MAKE_ROUNDED; !private void handleMakeRounded() { BasicView view = (BasicView)getOrCreateView(); view.makeRounded(); } @Override public boolean handleMessage(Message msg){ if (msg.what == MSG_MAKE_ROUNDED) { handleMakeRounded(); return true; } return super.handleMessage(msg); } @Kroll.method public void makeRounded() { if (TiApplication.isUIThread()) { handleMakeRounded(); } else { TiMessenger.sendBlockingMainMessage(getMainHandler().obtainMessage(MSG_MAKE_ROUNDED)); } }
BasicViewProxy.java
TICONF EU, AMSTERDAM, 29/06/2014
View Events
47
basicView.addEventListener('viewTapped', function() { alert('tapped'); });
TICONF EU, AMSTERDAM, 29/06/2014
Firing Events
48
-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; // other initialisation operations ! UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(basicViewTapped:)]; // Specify that the gesture must be a single tap tapRecognizer.numberOfTapsRequired = 1; // Add the tap gesture recognizer to the view [theView addGestureRecognizer:tapRecognizer]; } !- (void)basicViewTapped:(UITapGestureRecognizer *)recognizer { NSDictionary *event = @{@"color": @"red"}; [self.proxy fireEvent:@"viewTapped" withObject:event]; }
TiConfBasicView.m
TICONF EU, AMSTERDAM, 29/06/2014
Firing Events
48
-(void)initializeState { theView = [[UIView alloc] initWithFrame:self.bounds]; // other initialisation operations ! UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(basicViewTapped:)]; // Specify that the gesture must be a single tap tapRecognizer.numberOfTapsRequired = 1; // Add the tap gesture recognizer to the view [theView addGestureRecognizer:tapRecognizer]; } !- (void)basicViewTapped:(UITapGestureRecognizer *)recognizer { NSDictionary *event = @{@"color": @"red"}; [self.proxy fireEvent:@"viewTapped" withObject:event]; }
TiConfBasicView.m
TICONF EU, AMSTERDAM, 29/06/2014
Firing Events
49
public BasicView(final TiViewProxy proxy) { super(proxy); ! Activity context = proxy.getActivity(); theView = new View(context); ! //other initialisation operations View.OnTouchListener gestureListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { KrollDict event = new KrollDict(); event.put("color", "red"); proxy.fireEvent("viewTapped", event); return true; } }; theView.setOnTouchListener(gestureListener); ! setNativeView(theView); }
BasicView.java
TICONF EU, AMSTERDAM, 29/06/2014
Firing Events
49
public BasicView(final TiViewProxy proxy) { super(proxy); ! Activity context = proxy.getActivity(); theView = new View(context); ! //other initialisation operations View.OnTouchListener gestureListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { KrollDict event = new KrollDict(); event.put("color", "red"); proxy.fireEvent("viewTapped", event); return true; } }; theView.setOnTouchListener(gestureListener); ! setNativeView(theView); }
BasicView.java
TICONF EU, AMSTERDAM, 29/06/2014
Integrating Third Party Libraries
TICONF EU, AMSTERDAM, 29/06/2014
iOS Static Library
• Static library file (.a)
• Objective-c/C/C++ headers folder
51
TICONF EU, AMSTERDAM, 29/06/2014
iOS Static Library
52
TICONF EU, AMSTERDAM, 29/06/2014
iOS Static Library
52
includes (headers) folder
TICONF EU, AMSTERDAM, 29/06/2014
iOS Static Library
52
includes (headers) folder
static lib file (.a)
TICONF EU, AMSTERDAM, 29/06/2014
iOS Static Library
52
includes (headers) folder
static lib file (.a)ensure the lib is linked
with the module
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
• Framework bundle ★ Header files ★ Library ★ Resources
53
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
54
TITANIUM_SDK_VERSION = 3.2.3.GA !!TITANIUM_SDK = ~/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) /PATH/TO/YOUR/FRAMEWORK/HEADERS
titanium.xcconfig
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
54
TITANIUM_SDK_VERSION = 3.2.3.GA !!TITANIUM_SDK = ~/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) /PATH/TO/YOUR/FRAMEWORK/HEADERS
titanium.xcconfig
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
54
TITANIUM_SDK_VERSION = 3.2.3.GA !!TITANIUM_SDK = ~/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) /PATH/TO/YOUR/FRAMEWORK/HEADERS
titanium.xcconfig
Used ad module build time
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
55
!OTHER_LDFLAGS=$(inherited) -framework <FRAMEWORK> -F <PATH/TO/FRAMEWORK> !
For example: !OTHER_LDFLAGS=$(inherited) -framework ArcGIS -F $HOME/Library/SDKs/ArcGIS/iOS/
module.xcconfig
TICONF EU, AMSTERDAM, 29/06/2014
iOS Frameworks
55
!OTHER_LDFLAGS=$(inherited) -framework <FRAMEWORK> -F <PATH/TO/FRAMEWORK> !
For example: !OTHER_LDFLAGS=$(inherited) -framework ArcGIS -F $HOME/Library/SDKs/ArcGIS/iOS/
module.xcconfig
Used ad application build time
TICONF EU, AMSTERDAM, 29/06/2014
ARC vs. NON-ARC
• ARC = Automatic Reference Counting ★ Retain/Release handled automatically by
the Clang compiler
• Ti module template project is still NON-ARC
• You can use ARC code inside of a Ti module project
56
TICONF EU, AMSTERDAM, 29/06/2014
Enabling ARC for a specific file
57
TICONF EU, AMSTERDAM, 29/06/2014
Using external JARs
58
drag & drop the JAR in the lib folder of the module
project
TICONF EU, AMSTERDAM, 29/06/2014
Using external JARs
59
Add the external JAR to the project build
path
TICONF EU, AMSTERDAM, 29/06/2014
Integrating native libs (NDK)
60
Import the native shared libraries (.so), separated by target architecture in
the lib folder
TICONF EU, AMSTERDAM, 29/06/2014
Fix build.xml
61
<project name="android" default="dist"> <description> Ant build script for Titanium Android module android </description>! <property name="ti.module.root" location="${basedir}"/> <property file="build.properties" />! <import file="${titanium.platform}/../module/android/build.xml"/> <target name="post.jar"> <copy todir="${libs}"> <fileset dir="lib"> <include name="**/*.so"/> </fileset> </copy> </target></project>
build.xml
Copy the .so files from lib to libs before packaging
Paul Mietz Egli: http://developer.appcelerator.com/question/121573/how-do-i-use-so-library-in-module#answer-228134
TICONF EU, AMSTERDAM, 29/06/2014
Fix build.xml
61
<project name="android" default="dist"> <description> Ant build script for Titanium Android module android </description>! <property name="ti.module.root" location="${basedir}"/> <property file="build.properties" />! <import file="${titanium.platform}/../module/android/build.xml"/> <target name="post.jar"> <copy todir="${libs}"> <fileset dir="lib"> <include name="**/*.so"/> </fileset> </copy> </target></project>
build.xml
Copy the .so files from lib to libs before packaging
Paul Mietz Egli: http://developer.appcelerator.com/question/121573/how-do-i-use-so-library-in-module#answer-228134
TICONF EU, AMSTERDAM, 29/06/2014
Questions?