SlideShare a Scribd company logo
TICONFEU,AMSTERDAM,29/06/2014
{native: “FTW”}
!
Integrating native views in Titanium apps
Olivier Morandi
TICONFEU,AMSTERDAM,29/06/2014
Olivier Morandi
Software engineer
!
http://titaniumninja.com!
olivier.morandi@gmail.com
@olivier_morandi
https://github.com/omorandi
2
TICONFEU,AMSTERDAM,29/06/2014 3
TICONFEU,AMSTERDAM,29/06/2014
• Ti app development
• Native module development (iOS/Android)
• Optimisations
• R&D
4
TICONFEU,AMSTERDAM,29/06/2014
This Talk
• How to create view-based native modules
• How to integrate third party libraries
5
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Learning Resources
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014 11
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Architecture Recap
TICONFEU,AMSTERDAM,29/06/2014 15
Titanium cli (node.js)
TICONFEU,AMSTERDAM,29/06/2014
Runtime (iOS)
16
Titanium
Modules
(API)
JS APP
Parser
Interpreter
IOS SDK
Bytecode
gen
JavaScriptCore
objective-c
C++
KROLLBRIDGE
TICONFEU,AMSTERDAM,29/06/2014
Runtime (iOS)
16
Titanium
Modules
(API)
JS APP
Parser
Interpreter
IOS SDK
Bytecode
gen
JavaScriptCore
NO JIT
objective-c
C++
KROLLBRIDGE
TICONFEU,AMSTERDAM,29/06/2014
Titanium
Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code
gen
KROLLBRIDGE
Runtime (Android)
17
Java
C++
V8
OPT
TICONFEU,AMSTERDAM,29/06/2014
Titanium
Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code
gen
KROLLBRIDGE
Runtime (Android)
17
Java
C++
V8
OPT
TICONFEU,AMSTERDAM,29/06/2014
Titanium
Modules
(API)
JS APP
Parser
Native Code
Android SDK
Native Code
gen
KROLLBRIDGE
Runtime (Android)
17
Java
C++
V8
OPT
TICONFEU,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();
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
NativeView Type	

iOS UIView	

AndroidView
extends
TICONFEU,AMSTERDAM,29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
NativeView Type	

iOS UIView	

AndroidView
State:
properties
Actions:
methods
Events:
addEventListener(), fireEvent()
Interface
extends
TICONFEU,AMSTERDAM,29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
NativeView Type	

iOS UIView	

AndroidView
State:
properties
Actions:
methods
Events:
addEventListener(), fireEvent()
Interface
Methods for the integration within the
application lifecycle
•startup() (iOS)
•shutdown() (iOS)
•onAppCreate() (Android)
extends
TICONFEU,AMSTERDAM,29/06/2014
Proxies & Modules
Proxy
ViewProxy ViewModule
extends
has a
creates
19
manages
NativeView Type	

iOS UIView	

AndroidView
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
TICONFEU,AMSTERDAM,29/06/2014
ViewProxy
20
ViewProxy
View
NativeViews
Hierarchy
Methods
Properties
(get/set)
Events
Holds the state
of a view
Manages the
native view
hierarchy
TICONFEU,AMSTERDAM,29/06/2014
ViewProxy
20
ViewProxy
View
NativeViews
Hierarchy
Methods
Properties
(get/set)
Events
Holds the state
of a view
Manages the
native view
hierarchy
JS THREAD
TICONFEU,AMSTERDAM,29/06/2014
ViewProxy
20
ViewProxy
View
NativeViews
Hierarchy
Methods
Properties
(get/set)
Events
Holds the state
of a view
Manages the
native view
hierarchy
JS THREAD UI THREAD
TICONFEU,AMSTERDAM,29/06/2014
ViewProxy
20
ViewProxy
View
NativeViews
Hierarchy
Methods
Properties
(get/set)
Events
Holds the state
of a view
Manages the
native view
hierarchy
JS THREAD UI THREAD
ASYNC
TICONFEU,AMSTERDAM,29/06/2014
A Basic Native View
TICONFEU,AMSTERDAM,29/06/2014 22
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
ViewProxy Class
24
#import "TiViewProxy.h"
!
@interface TiConfBasicViewProxy : TiViewProxy
@end
TiConfBasicViewProxy.h
TiConfBasicViewProxy.m
#import "TiConfBasicViewProxy.h"
!
@implementation TiConfBasicViewProxy
!
!
@end
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014 26
TICONFEU,AMSTERDAM,29/06/2014 26
WTF: where’s my view?
TICONFEU,AMSTERDAM,29/06/2014 26
WTF: where’s my view?
TiConfBasicView
TICONFEU,AMSTERDAM,29/06/2014 26
WTF: where’s my view?
TiConfBasicView
theView
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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;
}
TICONFEU,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:]
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014 31
TICONFEU,AMSTERDAM,29/06/2014
Properties
• Properties belong to the ViewProxy object
• How do we make use of property values in
View objects?
32
TICONFEU,AMSTERDAM,29/06/2014
Setting a property
33
var basicView = ticonf.createBasicView({
color: "red"
});
!
//or
!
basicView.color = "red";
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Implicit Setter in the View Class
36
-(void)setColor_:(id)arg
{
theView.backgroundColor = [[TiUtils colorValue:arg] color];
}
TiConfBasicView.m
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Property from the Proxy
37
!
int color = TiConvert.toColor((String) proxy.getProperty(“color"));
BasicView.java
TICONFEU,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
}
}
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Methods
• Exposed to JS by the ViewProxy object
• Dispatched to the View object
40
TICONFEU,AMSTERDAM,29/06/2014
View Methods
41
basicView.makeRounded();
TICONFEU,AMSTERDAM,29/06/2014 42
TICONFEU,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
TICONFEU,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
JS
THREAD
TICONFEU,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
JS
THREAD
UI
THREAD
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
View Events
47
basicView.addEventListener('viewTapped', function() {
alert('tapped');
});
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Integrating Third
Party Libraries
TICONFEU,AMSTERDAM,29/06/2014
iOS Static Library
• Static library file (.a)
• Objective-c/C/C++ headers folder
51
TICONFEU,AMSTERDAM,29/06/2014
iOS Static Library
52
TICONFEU,AMSTERDAM,29/06/2014
iOS Static Library
52
includes (headers) folder
TICONFEU,AMSTERDAM,29/06/2014
iOS Static Library
52
includes (headers) folder
static lib file (.a)
TICONFEU,AMSTERDAM,29/06/2014
iOS Static Library
52
includes (headers) folder
static lib file (.a)
ensure the lib is linked
with the module
TICONFEU,AMSTERDAM,29/06/2014
iOS Frameworks
• Framework bundle
★ Header files
★ Library
★ Resources
53
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Enabling ARC for a specific file
57
TICONFEU,AMSTERDAM,29/06/2014
Using external JARs
58
drag & drop the JAR in the
lib folder of the module
project
TICONFEU,AMSTERDAM,29/06/2014
Using external JARs
59
Add the external JAR
to the project build
path
TICONFEU,AMSTERDAM,29/06/2014
Integrating native libs (NDK)
60
Import the native shared
libraries (.so), separated
by target architecture in
the lib folder
TICONFEU,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
TICONFEU,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
TICONFEU,AMSTERDAM,29/06/2014
Questions?

More Related Content

Native FTW: Integrating native views in Titanium apps