Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Extending Appcelerator Titanium Mobile through Native Modules

Presentation used for the speech I gave at the WHYMCA 2011 - Italian Mobile Developer Conference, held in Milan (IT) on may 20th 2011

Extending Appcelerator Titanium Mobile through Native Modules

  1. 1. ExtendingTitanium Mobile through Native Modules<br />Olivier Morandi<br />
  2. 2. # whoami<br />Olivier Morandi<br />Freelance mobile developer & software engineer<br />olivier.morandi@gmail.com<br />@olivier_morandi<br />https://github.com/omorandi<br />
  3. 3. Titanium Mobile<br />A set oftoolsfordevelopingcross-platform mobile applications in JavaScript<br />iOS (iPhone/iPod/iPad) <br />Android<br />Blackberry(through a commercial subscription)<br />http://www.appcelerator.com<br />https://github.com/appcelerator/titanium_mobile<br />
  4. 4. Anatomyof a project<br />Project directory<br />build/<br />android/<br />iphone/<br />Resources/<br />app.js<br />manifest<br />tiapp.xml<br />Buildfolders, per platform<br />Resourcefiles: JS code, images, sounds, SqliteDBs, etc.<br />Project files<br />
  5. 5. manifest<br />#appname: whymca<br />#publisher: olivier<br />#url: http://www.whymca.org<br />#image: appicon.png<br />#appid: com.whymca.test<br />#desc: undefined<br />#type: mobile<br />#guid: 746e9cb4-49f6-4afe-af0b-5de9f0116f65<br />
  6. 6. tiapp.xml<br /><?xml version="1.0" encoding="UTF-8" standalone="no"?><br /><ti:appxmlns:ti="http://ti.appcelerator.org"><br /> <deployment-targets><br /> <target device="iphone">true</target><br /> <target device="ipad">false</target><br /> <target device="android">true</target><br /> </deployment-targets><br /> <id>com.whymca.test</id><br /> <name>whymca</name><br /> <version>1.0</version><br /> <publisher>olivier</publisher><br /> <url>http://www.whymca.org</url><br /> <description>notspecified</description><br /> <copyright>2011 byolivier</copyright><br /> <icon>appicon.png</icon><br /> <persistent-wifi>false</persistent-wifi><br /> <prerendered-icon>false</prerendered-icon><br /> <statusbar-style>default</statusbar-style><br /> <statusbar-hidden>false</statusbar-hidden><br /> <fullscreen>false</fullscreen><br /> <navbar-hidden>false</navbar-hidden><br /> <analytics>false</analytics><br /> <guid>746e9cb4-49f6-4afe-af0b-5de9f0116f65</guid><br /><iphone><br /><orientationsdevice="iphone"><br /><orientation>Ti.UI.PORTRAIT</orientation><br /></orientations><br /><orientationsdevice="ipad"><br /><orientation>Ti.UI.PORTRAIT</orientation><br /><orientation>Ti.UI.UPSIDE_PORTRAIT</orientation><br /><orientation>Ti.UI.LANDSCAPE_LEFT</orientation><br /><orientation>Ti.UI.LANDSCAPE_RIGHT</orientation><br /></orientations><br /></iphone><br /><androidxmlns:android="http://schemas.android.com/apk/res/android"><br /></android><br /><modules><br /></modules><br /></ti:app><br />
  7. 7. app.js (1)<br />varwin = Titanium.UI.createWindow({ <br />title:'Hello',<br />backgroundColor:'#fff'<br />});<br />var label1 = Titanium.UI.createLabel({<br />color:'#333',<br />text:’Hello World!',<br />textAlign: 'center',<br />font: {fontSize: 30, fontWeight: 'bold'}<br />});<br />win.add(label1);<br />
  8. 8. app.js (2)<br />varbt = Titanium.UI.createButton({<br />title: 'Click me', <br />width: 100,<br />height: 40,<br />bottom: 40<br />})<br />bt.addEventListener('click', function(e) {<br />label1.text = 'WHYMCA ROCKS!';<br />});<br />win.add(bt);<br />win.open();<br />
  9. 9. UI widgetscreated in JS are mapped on the native componentsof the target platform<br />
  10. 10. Appdistribution<br />The productreadyfordistributionisactually a native app<br />JS Code<br />Partiallycompiled and optimized<br />Packed in binary format into the bundle<br />Resources<br />Copiedinto the bundle<br />
  11. 11. Developmenttoolchain<br />Ti Studio (IDE)<br />Ti Developer (toolchain GUI)<br />Ti SDK toolchain<br />(Pythonscripts)<br />Xcode/iOS SDK<br />Android SDK<br />Mac OSX<br />Windows<br />Linux<br />Mac OSX<br />
  12. 12. ApplicationStack<br />JavaScriptApplication Code<br />TitaniumJavaScript API<br />Android<br />Modules<br />iOS<br />Modules<br />JS Interpreter<br />JS Interpreter<br />TitaniumFramework<br />Runtime<br />Runtime<br />Android SDK<br />iOS SDK<br />
  13. 13. Ti JavaScript API<br />UI<br />Titanium.UI <br />Titanium.UI.Android <br />Titanium.UI.Clipboard <br />Titanium.UI.iOS <br />Titanium.UI.iPad <br />Titanium.UI.iPhone<br />Titanium.Map<br />Sensors<br />Titanium.Accelerometer<br />Titanium.Geolocation<br />Titanium.Gesture<br />Networking<br />Titanium.Network <br />Titanium.XML<br />Titanium.Facebook<br />Titanium.Yahoo<br />Titanium.Analytics<br />Device integration<br />Titanium.Platform<br />Titanium.Contacts <br />Titanium.Media <br />Titanium.Android <br />Titanium.Android.Calendar <br />Titanium.Android.NotificationManager<br />Titanium.App.iOS <br />Titanium.App.Android <br />Data Persistence<br />Titanium.Database <br />Titanium.Filesystem<br />Titanium.App.Properties <br />i18n<br />Titanium.Locale <br />Utilities/helpers<br />Titanium <br />Titanium.App <br />Titanium.API <br />Titanium.Utils<br />http://developer.appcelerator.com/apidoc/mobile<br />
  14. 14. Extending the API:why?<br />Accessingspecific OS features<br />Leveragingexisting native libraries<br />Optimizingcriticalportionsof the app<br />Extending/amelioratingportionsof the Titanium Mobile framework<br />
  15. 15. Extending the API:how?<br />Creating a forkofTitanium Mobile’ssource code on github<br />Unflexibleapproach<br />You put yourhands in the heartof the framework<br />Maintaining a separate branch can betedious and costly<br />There are situationswherethisis the cheaperapproach<br />E.g. whenneedingtoextend the functionalityofcoremodulesof the framework (networking, maps, ecc.) <br />
  16. 16. Extending the API:how?<br />Creatingone or more native modulesthrought the TitaniumModule SDK<br />Great flexibility<br />Easy todistributeas<br />Open Source<br />Binarypackages<br />AppceleratorTi+PlusMarketplace (?)<br />
  17. 17. Moduli nativi– some examples<br />Androidbarcode scanner (Zxingwrapper)<br />https://github.com/mwaylabs/titanium-barcode<br />iOSZipFile(create/decompress zip files)<br />https://github.com/TermiT/ZipFile<br />iOSTiStoreKit (in apppurchase)<br />https://github.com/masuidrive/TiStoreKit<br />iOSTiSMSDialog (in app sms sending)<br />https://github.com/omorandi/TiSMSDialog<br />AppceleratorTitaniummodules(sample modules)<br />https://github.com/appcelerator/titanium_modules<br />
  18. 18. Titanium JS Interface<br />varbt = Titanium.UI.createButton({<br />title: 'Click me', <br />width: 100,<br />height: 40,<br />bottom: 40<br />});<br />bt.addEventListener('click', function(e) {<br />label1.text = 'WHYMCA ROCKS!';<br />});<br />
  19. 19. Titanium JS Interface<br />Module<br />Titanium.UI<br />Object<br />Titanium.UI.Button<br />ObjectFactory<br />Titanium.UI.createButton()<br />Propertygetters/setters - methods<br />Button.title<br />Button.width<br />Button.animate()<br />Ecc.<br />Eventhandling<br />Button.addEventListener()<br />
  20. 20. ModuleArchitecture<br />Object<br />Objectproperty/method<br />Namespace<br />Titanium.UI<br />Titanium.UI.Button<br />Titanium.UI.Button.width<br />JavaScript<br />Module<br />Proxy<br />setters/getters<br />Methods<br />Events<br />setters/getters<br />Methods<br />Events<br />Internal State<br />Internal State<br />Titanium<br />abstraction<br />Implementation<br />Factory<br />Proxy Class<br />ModuleClass<br />
  21. 21. The pathtomoduledevelopment<br />Define the functionality you need to be exposed and how they’ll be invoked from JavaScript code  define the API of the module<br />Create a project with the toolsof the Module SDK<br />Implement the API<br />Build-Test-Debug<br />
  22. 22. Case Study–iOS SMS module<br />The Titanium API providesemailsendingfunctionalitythrough the Ti.UI.EmailDialogcomponent, butnothingforsending SMS messages<br />On iOSthisfeatureisavailablesinceversion 4.0 of the OS through the MFMessageComposeViewControllerclass<br />
  23. 23. MFMessageComposeViewController<br />
  24. 24. Case Study–iOS SMS module<br />Implement a native modulecapableofexposing the featuresof the MFMessageComposeViewControllerclassthrough a JavaScript API:<br />Check the availabilityof the component (notpresent in iOSversions < 4.0)<br />Programmatically set recipients and message body<br />Set UI properties (e.g. navbar color)<br />Notify the callerabout the resultof the sendoperation<br />
  25. 25. Resources<br />Module SDK Docs<br />Android<br />http://wiki.appcelerator.org/display/guides/Module+Developer+Guide+for+Android<br />iOS<br />http://wiki.appcelerator.org/display/guides/Module+Developer+Guide+for+iOS<br />Titanium Mobile source code<br />https://github.com/appcelerator/titanium_mobile<br />Code ofothermodulesreleasedas open source<br />
  26. 26. 1.Defining the API<br />Object<br />SMSDialog<br />Properties<br />recipients<br />messageBody<br />barColor<br />Methods<br />isSupported()<br />open()<br />
  27. 27. Example code<br />varsmsDialog = module.createSMSDialog();<br />if(smsDialog.isSupported()) <br />{<br />smsDialog.recipients = [’+14151234567'];<br />smsDialog.messageBody = 'Test messagefrom me';<br />smsDialog.barColor = ’red';<br />smsDialog.addEventListener('complete', function(e){<br />Ti.API.info('Result: ' + e.resultMessage);<br /> });<br />smsDialog.open({animated: true});<br />}<br />
  28. 28. Result<br />
  29. 29. 2.Creating the project<br /># titanium create <br />--platform=iphone <br />--type=module <br />--dir=~/<br />--name=SMSDialog <br />--id=com.whymca.smsdialog<br />
  30. 30. titanium (alias)<br />Mac OS X<br />alias titanium="/Library/Application Support/Titanium/mobilesdk/osx/1.7.0/titanium.py"<br />Linux<br />alias titanium="$HOME/Library/Application Support/Titanium/mobilesdk/osx/1.7.0/titanium.py"<br />Windows XP<br />PATH=C:Documents and SettingsAll UsersApplication DataTitaniummobilesdkwin321.7.0<br />Windows Vista/7<br />PATH=C:ProgramDataTitaniummobilesdkwin321.7.0<br />
  31. 31. Xcode project generated<br />assets/ <br />Classes/<br />ComWhymcaSmsdialogModule.h<br />ComWhymcaSmsdialogModule.m<br />ComWhymcaSmsdialogModuleAssets.h<br />ComWhymcaSmsdialogModuleAssets.m<br />example/<br />app.js<br />build.py<br />ComWhymcaSmsdialog_Prefix.pch <br />manifest<br />module.xcconfig<br />smsdialog.xcodeproj<br />titanium.xcconfig<br />Assetfilestobedistributedwith the module<br />Implementationfiles<br />Tobefilledwithour code<br />Sample programfortestingmoduleinvocations<br />Script for building and packaging the module<br />Metadataformanaging the module in Titanium<br />Include/linkingdirectivesused at integration-time<br />Include/linkingdirectivesused at build-time<br />
  32. 32. 3.Implementation<br />The generated project alreadycontains the classthatimplements the module:<br />ComWhymcaSmsdialogModule<br />The classnameis a CamelCasetranspositionof the moduleidchosenwhencreating the project<br />In JSitwillbeinstantiatedas<br />varmodule = require(‘com.whymca.smsdialog’);<br />
  33. 33. Implementing the proxy<br />The SMSDialogobjectwedefined, mustbeimplementedas a proxy<br />The nameof the classmustfollow a convention similartothatusedfor the modulename, in the form:<br /><moduleID><proxyName>Proxy<br />i.e.<br />ComWhymcaSmsdialogSMSDialogProxy<br />
  34. 34. SMSDialogProxyclass<br />Mustbe a subclassof the TiProxyclass<br />Itshouldexposeproperties and methodsthatwewanttomakeavailabletoJavaScript code<br />
  35. 35. Objectcreation and initialization<br />varsmsDialog = module.createSMSDialog();<br />smsDialog.recipients = [’+391234567'];<br />smsDialog.messageBody = 'Test message';<br />//or<br />varsmsDialog = module.createSMSDialog({<br />recipients: [’+391234567’],<br />messageBody: 'Test message’<br />});<br />
  36. 36. Creation<br />Objectcreationiscompletelymanagedby the framework<br />The JS construct<br />module.create<ProxyName>()<br />ismapped on code thatinstantiateanobjectof the correctclassthanksto the naming convention used<br />
  37. 37. Initialization<br />The object can beinitializedeitherpassing a dictionaryofpropertyvaluesto the factorymethod, eithersetting single propertyvalues in a second moment through dot notation<br />In either case, if the proxydoesn’texplicitlyprovidegetter/setter methodsforthoseproperties, they are automaticallyinserted in the dynpropsdictionaryof the proxyobject<br />
  38. 38. Initialization<br />It’salwayspossibletoretrievepropertyvaluespresent in the dynpropsdictionarywith the message<br />[self valueForUndefinedKey:@"messageBody"]<br />
  39. 39. Conversion utilities<br />The frameworkprovides the TiUtilsclass, whichcontainsmethodsforsimplifying the conversionofvaluescomingform JS code:<br />NSString * messageBody = [TiUtilsstringValue:[self valueForUndefinedKey:@"messageBody"]];<br />UIColor * barColor = [[TiUtilscolorValue:[self valueForUndefinedKey:@"barColor"]] _color];<br /> BOOL animated = [TiUtilsboolValue:@"animated" properties:argsdef:YES];<br />
  40. 40. Methods<br />They are exposedtoJavaScriptbysimplydeclaringthem in the @interfacesectionof the proxyclass<br />Theymustbedeclared in oneof the followingforms:<br />-(id)methodName:(id)args<br />-(void)methodName:(id)args<br />
  41. 41. Example<br />@interfaceComWhymcaSmsdialogSMSDialogProxy: TiProxy <MFMessageComposeViewControllerDelegate> <br />- (id)isSupported:(id)args;<br />- (void)open:(id)args;<br />@end<br />
  42. 42. Methodarguments<br />The listofargumentspassed in JavaScriptto a methodispassedas a NSArrayobject in the argsparameter<br />The frameworkprovides some Cmacrosfor the caseswhere a single argumentisexpected:<br />ENSURE_SINGLE_ITEM(args,type)<br />ENSURE_SINGLE_ARG_OR_NIL(args, type)<br />
  43. 43. PassingJavaScriptdictionaryObjects<br />JS:<br />smsDialog.open({animated: true});<br />OBJ-C:<br />- (void)open:(id)args {<br /> ENSURE_SINGLE_ARG_OR_NIL(args, NSDictionary);<br /> //args ora è un NSDictionary<br /> BOOL animated = [TiUtilsboolValue:@"animated" properties:argsdef:YES];<br />//[…]<br />
  44. 44. Returnvalues<br />The types<br />NSString <br />NSDictionary <br />NSArray <br />NSNumber <br />NSDate <br />NSNull<br /> don’tneedtobeconverted<br />Numerictypesmustbewrapped in a NSNumberobject<br />It’spossibletoreturnproxyobjects (thoughtheymustbeautoreleasedifallocatedbyourmethod)<br />return [[[TiColor alloc] initWithColor:colorname:@"#fff"] autorelease];<br />
  45. 45. Executing a method in the UI thread<br />There are caseswhere a methodshouldbeexecuted in the UI thread (e.g. wheninteractingwithuser interface objects)<br />In suchcaseswe can use the macro<br />ENSURE_UI_THREAD(method,args)<br />for forcing the executionof the methodon the UI thread<br />
  46. 46. Events<br />The simplest way a proxyhastointeractwith JS code isthroughevents<br />In JS weregisteranevent-listenerfunction on a specificeventmanagedby the proxy<br />Example<br />JS:<br />smsDialog.addEventListener('complete', function(e){<br />Ti.API.info('Result: ' + e.resultMessage);<br /> });<br />
  47. 47. Events<br />OBJ-C:<br />-(void)_listenerAdded:(NSString*)typecount:(int)count<br />{<br />//type = @"complete"<br />}<br />-(void)_listenerRemoved:(NSString*)typecount:(int)count {<br />//type = @"complete" <br />}<br />
  48. 48. Events<br />OBJ-C:<br />NSDictionary*event = [NSDictionarydictionaryWithObjectsAndKeys:resultMessage, @"resultMessage", nil];<br />[self fireEvent:@"complete" withObject:event];<br />
  49. 49. 4. Build<br />We can build the project directlyfromXcode<br />Usefulforchecking out warning & syntaxerrormessages<br />
  50. 50. ⌘B<br />
  51. 51. 4. Build<br />Using the script<br /> # build.py<br />from the module project root directory<br />Itperforms a complete build and itpackages the modulelibrary + assets + metadata in a zip file<br />
  52. 52. Package<br />Name in the form<br />com.whymca.smsdialog-iphone-0.1.zip<br />Forbeinguseditmustbedecompressed in the directory<br />/Library/ApplicationSupport/Titanium/<br />
  53. 53. Simpletesting<br />Byexecuting the script<br /># titaniumrun<br /> in the project directory<br />Thiswill create a temporary project based on the app.js file from the exampledirectory<br />Not the best way fortesting the module<br />
  54. 54. Using the module in a Ti Mobile Project<br /><?xml version="1.0" encoding="UTF-8" standalone="no"?><br /><ti:appxmlns:ti="http://ti.appcelerator.org"><br /><!–-SNIP…--><br /><modules><br /> <moduleversion=“0.1” platform=“iphone”><br />com.whymca.smsdialog<br /> </module><br /></modules><br /></ti:app><br />tiapp.xml<br />
  55. 55. Testing/Debugging<br />Create a new Ti Mobile project with test code and a referenceto the module<br />Launch the app at leastonetimefrom Ti Studio/Developer<br />Open the Xcode project from the build/iphonedirectory found in the app project directory<br />IssueBuild&Debugfromthere<br />Set breakpoints in the module code, test, etc.<br />
  56. 56.
  57. 57. Thankyou!<br />Anyquestions?<br />You can findall the code usedforthispresentation on<br />https://github.com/omorandi/whymca-conf-2011<br />

×