Extending Titanium with native iOS and Android modules

60,073 views

Published on

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

Published in: Technology
4 Comments
37 Likes
Statistics
Notes
  • Njce! Thanks for sharing
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello dear, My name is mariam nasrin, I know that this email will meet you in a good health and also surprisingly but God has his own way of bringing people together. Nice to Meet you I would appreciate if you can reply me back( mariamnasrin2@gmail.com ) So that i can explain you more about me. thank Yours mariam.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • thanks for sharing this, its pretty good
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • I'm looking for the source code of Android version of XML2JSON.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
60,073
On SlideShare
0
From Embeds
0
Number of Embeds
23,850
Actions
Shares
0
Downloads
378
Comments
4
Likes
37
Embeds 0
No embeds

No notes for slide

Extending Titanium with native iOS and Android modules

  1. Extending Titanium Native iOS & Android ModulestiConf.eu, valencia, 24/02/2013
  2. Olivier Morandi Software engineer http://titaniumninja.com olivier.morandi@gmail.com @olivier_morandi https://github.com/omoranditiConf.eu, valencia, 24/02/2013 2
  3. Module development is so 2010tiConf.eu, valencia, 24/02/2013
  4. Why Bother? • To leverage native features ★ Underlying OS ★ 3rd party libraries • Performance ★ To optimize the User ExperiencetiConf.eu, valencia, 24/02/2013 4
  5. Learning ResourcestiConf.eu, valencia, 24/02/2013
  6. 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_GuidetiConf.eu, valencia, 24/02/2013 6
  7. tiConf.eu, valencia, 24/02/2013 7
  8. Source code • Titanium Mobile SDK ★ https://github.com/appcelerator/ titanium_mobile • Example modules from Appcelerator ★ https://github.com/appcelerator/ titanium_modulestiConf.eu, valencia, 24/02/2013 8
  9. Follow these guys • Aaron K. Saunders: https://github.com/aaronksaunders • Ben Bahrenburg: https://github.com/benbahrenburg • Christian Sullivan: https://github.com/euforic • David Bankier: https://github.com/dbankier • Jordi Domenec: https://github.com/iamyellow • 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 • Russ Frank: https://github.com/russfranktiConf.eu, valencia, 24/02/2013 9
  10. Inside Titanium (A bit of architecture)tiConf.eu, valencia, 24/02/2013
  11. Titanium cli (node.js) + python scriptstiConf.eu, valencia, 24/02/2013 11
  12. Runtime (iOS) JS APP Parser KROLL BRIDGE JavaScriptCore Bytecode Titanium Modules objective-c gen (API) C++ Interpreter IOS SDKtiConf.eu, valencia, 24/02/2013 12
  13. Runtime (iOS) JS APP Parser KROLL BRIDGE JavaScriptCore Bytecode Titanium Modules objective-c gen (API) C++ O JIT N Interpreter IOS SDKtiConf.eu, valencia, 24/02/2013 12
  14. Runtime (Android) JS APP V8 Parser KROLL BRIDGE Native Code Titanium Modules Java gen OPT (API) C++ Native Code Android SDKtiConf.eu, valencia, 24/02/2013 13
  15. Runtime (Android) JS APP V8 Parser KROLL BRIDGE Native Code Titanium Modules Java gen OPT (API) C++ Native Code Android SDKtiConf.eu, valencia, 24/02/2013 13
  16. Runtime (Android) JS APP V8 Parser KROLL BRIDGE Native Code Titanium Modules Java gen OPT (API) C++ Native Code Android SDKtiConf.eu, valencia, 24/02/2013 13
  17. Terminology 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, valencia, 24/02/2013 14
  18. 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();tiConf.eu, valencia, 24/02/2013 14
  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 tartutiConf.eu, valencia, 24/02/2013 14
  20. Terminology factory method 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, valencia, 24/02/2013 14
  21. Terminology var win1 = Titanium.UI.createWindow({ title:Hello World, creation backgroundColor:white properties }); var label1 = Titanium.UI.createLabel({ color:black, textAlign:center, width: 100 }); label1.text = howdy?; win1.add(label1); win1.open();tiConf.eu, valencia, 24/02/2013 14
  22. Terminology proxy 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();tiConf.eu, valencia, 24/02/2013 14
  23. Terminology var win1 = Titanium.UI.createWindow({ title:Hello World, backgroundColor:white }); view proxy var label1 = Titanium.UI.createLabel({ object color:black, textAlign:center, width: 100 }); label1.text = howdy?; win1.add(label1); win1.open();tiConf.eu, valencia, 24/02/2013 14
  24. Terminology var win1 = Titanium.UI.createWindow({ title:Hello World, backgroundColor:white }); var label1 = Titanium.UI.createLabel({ color:black, textAlign:center, width: 100 }); proxy label1.text = howdy?; property win1.add(label1); win1.open();tiConf.eu, valencia, 24/02/2013 14
  25. Terminology 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); proxy win1.open(); methodtiConf.eu, valencia, 24/02/2013 14
  26. Proxies & Modules Native View Type Proxy iOS UIView Android View creates manages extends extends Module ViewProxy View has atiConf.eu, valencia, 24/02/2013 15
  27. Proxies & Modules Interface State: properties Actions: methods Events: addEventListener(), fireEvent() Native View Type Proxy iOS UIView Android View creates manages extends extends Module ViewProxy View has atiConf.eu, valencia, 24/02/2013 15
  28. Proxies & Modules Interface State: properties Actions: methods Events: addEventListener(), fireEvent() Native View Type Proxy iOS UIView Android View creates manages extends extends Module ViewProxy ViewMethods for the integration within theapplication lifecycle has a •startup() (iOS) •shutdown() (iOS) •onAppCreate() (Android)tiConf.eu, valencia, 24/02/2013 15
  29. Proxies & Modules Interface State: properties Actions: methods Events: addEventListener(), fireEvent() Native View Type Proxy iOS UIView Android View creates manages extends extends Module ViewProxy View Additional members for the integrationMethods for the integration within theapplication lifecycle within the UI layout system: •add() has a •startup() (iOS) •remove() •shutdown() (iOS) •height •onAppCreate() (Android) •width •backgroundColor •...tiConf.eu, valencia, 24/02/2013 15
  30. Let’s create a moduletiConf.eu, valencia, 24/02/2013
  31. • Create • Develop • Build • Deploy • DebugtiConf.eu, valencia, 24/02/2013 17
  32. • Create • Develop • Build • Deploy • DebugtiConf.eu, valencia, 24/02/2013 17
  33. Module DevelopmenttiConf.eu, valencia, 24/02/2013
  34. iOS Prerequisites • Same as for Ti app development on iOS: ★ Titanium SDK. ★ XcodetiConf.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 OLDtiConf.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 OLDtiConf.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 OLDtiConf.eu, valencia, 24/02/2013 21
  39. tiConf.eu, valencia, 24/02/2013 22
  40. tiConf.eu, valencia, 24/02/2013 22
  41. tiConf.eu, valencia, 24/02/2013 22
  42. tiConf.eu, valencia, 24/02/2013 22
  43. Create (Ti Studio)tiConf.eu, valencia, 24/02/2013 23
  44. Create (Ti Studio)tiConf.eu, valencia, 24/02/2013 24
  45. Create (Ti Studio)tiConf.eu, valencia, 24/02/2013 25
  46. Module BoilerplatetiConf.eu, valencia, 24/02/2013 26
  47. Module BoilerplatetiConf.eu, valencia, 24/02/2013 27
  48. Build & Install (cli) $ ./build.py $ unzip -uo ti.conf.sample-iphone-0.1.zip -d ~/Library/Application Support/ Titanium/tiConf.eu, valencia, 24/02/2013 28
  49. 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/tiConf.eu, valencia, 24/02/2013 28
  50. Build (Ti Studio)tiConf.eu, valencia, 24/02/2013 29
  51. Build & Install (Ti Studio)tiConf.eu, valencia, 24/02/2013 30
  52. Deploy tiapp.xml <?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 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";tiConf.eu, valencia, 24/02/2013 31
  53. Agenda • Methods • Events • Passing • Callbacks arguments • ViewProxies • Returning values • Exceptions • Using properties • ProxiestiConf.eu, valencia, 24/02/2013 32
  54. Proxy/Module Methods return value -(id)methodName:(id)args { NSString result = @"Hello World”; //do something return result; }tiConf.eu, valencia, 24/02/2013 33
  55. Proxy/Module Methods return value -(id)methodName:(id)args { NSString result = @"Hello World”; //do something return result; } no return value -(void)methodName:(id)args { //do something }tiConf.eu, valencia, 24/02/2013 33
  56. Proxy/Module Methods return value return value no args -(id)methodName:(id)args @Kroll.method { public String methodName() NSString result = @"Hello World”; { String result = "Hello world"; //do something //do something return result; } return result; } no return value -(void)methodName:(id)args { //do something }tiConf.eu, valencia, 24/02/2013 33
  57. Proxy/Module Methods return value return value no args -(id)methodName:(id)args @Kroll.method { public String methodName() NSString result = @"Hello World”; { String result = "Hello world"; //do something //do something return result; } return result; } no return value no return value @Kroll.method -(void)methodName:(id)args public void methodName(String value) { { //do something //do something } }tiConf.eu, valencia, 24/02/2013 33
  58. Example: xml2json module Expected API var xml2json = require(ti.xml2json); var json = xml2json.convert(xmlDoc); https://github.com/omorandi/TiXml2JsontiConf.eu, valencia, 24/02/2013 34
  59. Implementation @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]; } @endtiConf.eu, valencia, 24/02/2013 35
  60. Implementation @implementation TiXml2jsonModule -(NSDictionary) convertXml:(NSString)xmlString { NSDictionary *jsObj; //do conversion stuff return jsObj; } -(id)convert:(id)args NSArray of arguments { ENSURE_SINGLE_ARG(args, NSString); return [self convertXml:args]; } @endtiConf.eu, valencia, 24/02/2013 35
  61. Implementation @implementation TiXml2jsonModule -(NSDictionary) convertXml:(NSString)xmlString { NSDictionary *jsObj; //do conversion stuff return jsObj; } TiBase.h -(id)convert:(id)args NSArray of arguments #define ENSURE_SINGLE_ARG(x,t) { { ENSURE_SINGLE_ARG(args, NSString); x = (t*)[x objectAtIndex:0]; } return [self convertXml:args]; } @endtiConf.eu, valencia, 24/02/2013 35
  62. Utility Macros TiBase.h #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) ...tiConf.eu, valencia, 24/02/2013 36
  63. Types Supported Directly Conversion Utilities NSString NSDictionary #import "TiUtils.h" NSArray CGFloat f = [TiUtils floatValue:arg]; NSInteger f = [TiUtils intValue:arg]; NSNumber NSString *value = [TiUtils stringValue:arg]; NSDate TiColor *bgcolor = [TiUtils colorValue:arg]; NSNull UIColor *backgroundColor = [bgcolor color]; TiProxytiConf.eu, valencia, 24/02/2013 37
  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 RETtiConf.eu, valencia, 24/02/2013 38
  66. xml2json Android import org.appcelerator.kroll.KrollDict; @Kroll.module(name="Tixml2json", id="ti.xml2json") public class Tixml2jsonModule extends KrollModule { @Kroll.method public KrollDict convert(String xml) { KrollDict json = null; //do conversion stuff return json; } }tiConf.eu, valencia, 24/02/2013 39
  67. xml2json Android import org.appcelerator.kroll.KrollDict; @Kroll.module(name="Tixml2json", id="ti.xml2json") public class Tixml2jsonModule extends KrollModule { KrollDict.java @Kroll.method public class KrollDict extends HashMap<String, Object> public KrollDict convert(String xml) { KrollDict json = null; //do conversion stuff return json; } }tiConf.eu, valencia, 24/02/2013 39
  68. Types Supported Directly Conversion UtilitiesStringint import org.appcelerator.titanium.util.TiConvert;float int val = TiConvert.toInt(obj);double float val = TiConvert.toFloat(obj);boolean double val = TiConvert.toDouble(obj); boolean val = TiConvert.toBoolean(obj);Object[] int color = TiConvert.toColor(str);HashMap<String, Object> ...TiProxy http://builds.appcelerator.com.s3.amazonaws.com/module-apidoc/2.0.0/android/org/appcelerator/titanium/util/TiConvert.htmltiConf.eu, valencia, 24/02/2013 40
  69. Return Values • Single Value (String, Integer, …) • Collections (Object[]) ★ Converted into a JS Array object • Dictionary (HashMap<String, Object>) ★ Converted into a JS object ★ key->value ===> property->value • Proxy (TiProxy)tiConf.eu, valencia, 24/02/2013 41
  70. Polymorphic Methods -(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]; } }tiConf.eu, valencia, 24/02/2013 42
  71. Polymorphic Methods public KrollDict convertFromString(String xml); public KrollDict convertFromBlob(TiBlob blob) @Kroll.method public 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"); }tiConf.eu, valencia, 24/02/2013 43
  72. Varargs -(void) varArgsMethod:(id)args { for (int i = 0; i < [args count]; i++) { id arg = [args objectAtIndex:i]; // do something with arg } }tiConf.eu, valencia, 24/02/2013 44
  73. Varargs @Kroll.method public void varArgsMethod(Object[] args) { for (int i = 0; i < args.length; i++) { Object arg = args[i]; // do something with arg } }tiConf.eu, valencia, 24/02/2013 45
  74. Properties set module.propertyName = "HELLO"; get Ti.API.info("Property: " + module.propertyName);tiConf.eu, valencia, 24/02/2013 46
  75. Properties TiMyModule.h @interface TiMyModule: TiModule @property (nonatomic, readwrite, retain) NSString* propertyName; @end TiMyModule.m @implementation TiMyModule: TiModule @synthesize propertyName; @endtiConf.eu, valencia, 24/02/2013 47
  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 } @endtiConf.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
  87. Events @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]; } } @endtiConf.eu, valencia, 24/02/2013 57
  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 // lets 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) EventstiConf.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 THREADtiConf.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 THREADtiConf.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 asynctiConf.eu, valencia, 24/02/2013 62
  96. Super-Smooth TableView• API • createMessagesView(properties); • setMessages([]messages); • insert(message); • addEventListener(‘click’, callback);tiConf.eu, valencia, 24/02/2013 63
  97. Implementation MessagesViewProxy TiSmoothMessagesViewProxy.h @interface TiSmoothMessagesViewProxy : TiViewProxy @property (nonatomic, retain) MessagesCollection *msgs; //model @end TiSmoothMessagesViewProxy.m @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]; } @endtiConf.eu, valencia, 24/02/2013 64
  98. Implementation MessagesViewProxy TiSmoothMessagesViewProxy.h @interface TiSmoothMessagesViewProxy : TiViewProxy @property (nonatomic, retain) MessagesCollection *msgs; //model @end TiSmoothMessagesViewProxy.m @implementation TiSmoothMessagesViewProxy @synthesize msgs; //other methods -(void) insert:(id)args { ENSURE_SINGLE_ARG(args, NSDictionary); [self.msgs insertMessageOnTop:[self messageFromDictionary:(NSDictionary*)args]]; create the view and call addMessage on the UI thread [self makeViewPerformSelector:@selector(addMessage:) withObject:args createIfNeeded:YES waitUntilDone:NO]; } @endtiConf.eu, valencia, 24/02/2013 64
  99. Implementation MessagesView TiSmoothMessagesView.h @interface TiSmoothMessagesView : TiUIView { MessagesViewController *viewController; } @end TiSmoothMessagesView.m @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]; } @endtiConf.eu, valencia, 24/02/2013 65
  100. 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 { [TiUtils setView: viewController.tableView positionRect:bounds]; } @endtiConf.eu, valencia, 24/02/2013 65
  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]; } @endtiConf.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 bundletiConf.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 bundletiConf.eu, valencia, 24/02/2013 66
  104. timodule.xml <?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> build & package AndroidManifest.xml Module Package (.zip) app.apktiConf.eu, valencia, 24/02/2013 67
  105. DebuggingtiConf.eu, valencia, 24/02/2013
  106. Create a debug build $ sed s/Release/Debug/ build.py > build_debug.py build.py 168: rc = os.system("xcodebuild -sdk iphoneos -configuration Release") 171: rc = os.system("xcodebuild -sdk iphonesimulator -configuration Release") build_debug.py 168: rc = os.system("xcodebuild -sdk iphoneos -configuration Debug") 171: rc = os.system("xcodebuild -sdk iphonesimulator -configuration Debug")tiConf.eu, valencia, 24/02/2013 69
  107. DebuggingtiConf.eu, valencia, 24/02/2013 70
  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
  109. Android DDMStiConf.eu, valencia, 24/02/2013 72
  110. Thank you!tiConf.eu, valencia, 24/02/2013

×