Extending Appcelerator Titanium Mobile through Native Modules
Upcoming SlideShare
Loading in...5
×
 

Extending Appcelerator Titanium Mobile through Native Modules

on

  • 18,314 views

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

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

Statistics

Views

Total Views
18,314
Views on SlideShare
17,590
Embed Views
724

Actions

Likes
16
Downloads
267
Comments
3

12 Embeds 724

http://www.whymca.org 292
http://fyhao.com 212
http://titaniumninja.com 176
http://www.fyhao.com 11
http://fb.qxinnet.com 10
http://bbs.qxinnet.com 10
http://paper.li 5
http://localhost 4
http://web.qxinnet.com 1
http://twitter.com 1
http://www.techgig.com 1
http://www.verious.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Hi, I haven't been notified about these comments, so sorry for replying only now...
    Wrt the project setup, I also tried your solution, though with more complex applications, from time to time you need Titanium to recreate the main project, so you end up re-creating references, etc. Now I use a command line script that basically performs the same operations (i.e. build&install the module and launch the main project).
    Wrt documentation & best practices: as you point out docs are pretty much inexistent and unfortunately the best 'documentation' I've found is the Ti SDK source code. Digging through the code can be quite time consuming, but it gives you also many hints on how things should be done. I don't know if what you find in this presentation can be considered 'best practice'. Actually this is 'my' way to develop titanium modules.
    Recently I started blogging at http://titaniumninja.com where I report my experiences with titanium in general, and with module development and SDK hacking in particular.
    Thanks for the comments,

    Olivier
    Are you sure you want to
    Your message goes here
    Processing…
  • Also, is this best practice documented anywhere besides your slides? I've had a hard time finding helpful information beyond what's listed in the Module Developer Guide. Thanks.
    Are you sure you want to
    Your message goes here
    Processing…
  • Olivier, thanks for posting this. I'm curious about the test app configuration shown on slides 55 & 56. I'm trying to set my test project up so that I can modify Objective-C code in my module, then hit Build & Run on my test project, and have it automatically compile and link against my latest module changes. To make this work, I added a 'Build & Install' target to my module project, which is dependent on my main module target. The 'Build & Install' target copies & unzips my module into /Library/Application Support/Titanium. Then I added 'Build & Install' as a dependency on all my test app targets. Does this make sense, and do you have a better solution for this?
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Extending Appcelerator Titanium Mobile through Native Modules Extending Appcelerator Titanium Mobile through Native Modules Presentation Transcript

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