Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Note

Target Audience: To build Modules for Android, you must have knowledge of the Android SDK. This guide assumes you have a good understanding of building applications using the native Android SDK.

Contents

Table of Contents
maxLevel5
minLevel2

Overview

Titanium provides the ability to extend the built-in functionality of the Titanium Mobile SDK through a series of optional extensions , called " modules". Modules let you write code in a platform's native language (on Java for Android, Java). Through a series of classes and attributescomponents, we can expose new functionality to the JavaScript running in the Titanium SDK. (That's a mouthful! From now on, we'll just say "JavaScript".)

This guide will help you create modules for Android. We also have an iOS Module Development Guide.

We will accomplish the following by the time you finish reading the guide:

  • Installing the necessary components.
  • Creating an Android module.
  • Understanding the different parts of a module.
  • Importing a module into Eclipse.
  • Titanium APIs for module development.
  • Building.
  • Testing.
  • Distribution and installation.
Info
titleSample Code

There are a number of open-source modules available in the Appcelerator titanium_modules repo:

In particular, the ModDevGuide module is provided as a complement to this guide.

The modules in the titanium_modules repo repository can be used for reference, or as starting points for your custom modules.

 

Installing the Necessary Components

To develop an Android-based module, you will need all of the following installed on your machine:

  • Titanium CLI to create module projects (since Release 3.3.0).
  • Titanium SDK.
  • All of the prerequisites for developing Android applications.
  • Android SDK 2.3.x (API Level 10).  This version must be installed to build an Android module.
  • Android NDK. Add an ANDROID_NDK environment variable pointing to the NDK folder.
  • Ant 1.7.1 or above must be installed and in your system PATH to build from the command line.
  • Eclipse and ADT can be used instead of or in addition to Ant.
  • gperf must be installed and in your system PATH.

See Installing Titanium Advanced Tools for more detailed instructions for installing each of these components.

You can use Studio, Ant, or Eclipse to build Android modules. See the Copy of Android Module Development Guide,  Building with Ant and Building from Eclipse sections for more information.

To use the legacy command-line interface to create and build modules, you may want to add an alias to titanium.py. Follow the instructions in the Legacy Command-Line Interface Environment Setup section.

Creating an Android Module

Creating from Studio

Read the Creating a New Titanium Module guide to find out more about creating and building modules with Studio.

Creating from the Terminal

Starting with Release 3.3.0, the Titanium CLI can create modules.  Run the titanium create command without any options.  You will be prompted to enter the required information.  You can also run the titanium create command with the following options:

Code Block
ti create -p android -t module -d <WORKSPACE_DIR> -n <MODULE_NAME> -u <MODULE_URL> --id <MODULE_ID> 
## Sample Command
ti create -p android -t module -d ~/Documents/Sample_Workspace/ -n calc -u http:// --id org.appcelerator.calc 

Prior to Release 3.3.0:

To create a module, use the titanium.py script and pass some arguments to the titanium create command, namely:

  • The module's name ($MODULE_NAME), which most be all lowercase and ID ($MODULE_ID).
  • The platform we're creating a module for (android).
  • The top-level path to your installation of the Android SDK ($ANDROID_SDK) (e.g. /opt/android-sdk).

titanium create works in your terminal's current directory. Go to the directory you want to create your module in, then customize the following command for the module you want to create. As an example, we will create a module that performs simple addition and subtraction, calling it the "calc" module with an ID of "org.appcelerator.calc". Here we use /path/to/android-sdk to point to the place where we extracted the Android SDK.

Code Block
> titanium.py create --platform=android --type=module --name=calc --id=org.appcelerator.calc --android=/path/to/android-sdk

If this was successful, there should be a calc folder under the current directory. In the next section, we will take a closer look at the files and folders that were created.

Understanding the Different Parts of a Module

A number of files and directories work together to define our module and what it does. Let's take a quick look at each of them:

File/DirectoryDescription
LICENSEThe module's full license text; this will be distributed with the module to let other developers know how they can use and redistribute it.
assets/Module specific assets such as images. For more information, open up the README file located in this directory.
documentation/Documentation in Markdown format that is shipped with your module after being compiled to HTML.
example/The module example project that will be: 1) used to test the module, and 2) bundled with the module for other developers to reference.
android/build.propertiesAn Ant properties file that contains paths to the Titanium SDK, Google API add-ons, Android NDK and Android SDK on your computer.
android/build.xmlThe main Ant build script used to build, test, and finally distribute the module.
android/lib/Place any third party JAR dependencies here and they will be bundled up as a part of your module automatically.
android/manifestContains the version, author, license, copyright, name, id, GUID, and platform information for the module.
android/platform/This optional folder can include an "android" subdirectory, and then any of the resource directories defined in Android's Defining Resources guide (such as "res").
android/src/The source code for the module.
android/timodule.xmlA place to put custom activities, and general XML that will end up in the AndroidManifest.xml of apps. Read more about this file in the tiapp.xml and timodule.xml reference.

You can also include an optional jni folder.  This optional folder (as of Titanium SDK 2.1.0) can include C or C++ code to compile shared libraries. You are required to have an Application.mk file in this directory if it is present. Modules using JNI or NDK support via shared libraries will work with both the V8 and Rhino runtimes.

Note

Since Release 3.3.0, the CLI creates a module project that contains multiple platforms. Each platform contains its own folder with platform-specific resources and common folders for assets, documentation and example.

Prior to Release 3.3.0, none of the previous listed folder are contained in an android folder.

Importing a Module into Eclipse

When we ran titanium create, project settings for Eclipse were created as well. That means we can import the project very easily. In Eclipse, simply follow these steps:

  1. In the top level menu, click on File > Import...
  2. Expand the General folder, and double click on Existing Project into Workspace.
  3. Click on Browse... next to the Select root directory text field.
  4. Choose your module project's folder.  You should see your module project under the Projects list.
    Image Removed
  5. Press Finish and your module project should now be visible from the Package Explorer view in Eclipse.

Titanium APIs for Module Development

The following sections describe the Titanium APIs available for Android module development, and how to expose an API to JavaScript.

For a complete list of the APIs that can be used from an Android module, see the Android Module API JavaDoc.

For conceptual background on modules, proxies and module development, see Titanium Module Concepts.

Modules

A module is a class that provides an API point with a particular ID. That ID can then be used to require the module from JavaScript.

All modules must extend KrollModule and have the @Kroll.module annotation.

Code Block
package com.example.actionbarsearch;

import org.appcelerator.kroll.KrollModule;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.kroll.common.TiConfig;

@Kroll.module(name="Actionbarsearch", id="com.example.actionbarsearch")
public class ActionbarsearchModule extends KrollModule
{

The id annotation element specifies the identifier used with require to import the module. In this case, the JavaScript to require the module would look like this:

Code Block
var actionBarSearch = require("com.example.actionbarsearch");

The module must have a default constructor (that is, one that takes no arguments). 

A module can also have a parent module: Titanium.UI and Titanium.App are children of the Titanium module.

The @Kroll.module annotation can also contain a propertyAccessors element, which defines a set of properties exposed by the module. See Copy of Android Module Development Guide for more information.

Module Lifecycle Events

The module provides several places for you to hook into the application's lifecycle.

Use the @Kroll.onAppCreate annotation to declare a method to be called when the application object is created. This is optional and is only required if you have any application specific initialization, such as starting up a service that is required by the module.

The app create method is called during application startup. It is only called once, before your module is actually loaded.

 

Code Block
@Kroll.onAppCreate
public static void onAppCreate(TiApplication app)
{
	Log.d(LCAT, "[MODULE LIFECYCLE EVENT] onAppCreate notification");
}

The module also provides callbacks that are invoked when the application's root activity is started, stopped, paused, or resumed. For sample usage of these callbacks, see the lifecycle notices in the sample module.

 

Proxies 

  • Proxies can expose methods, properties, and constants to JavaScript. Each of these can be a primitive type, or a proxy.

Methods

Methods of a proxy or module are exposed with the @Kroll.method annotation. A simple example:

Code Block
@Kroll.method
public String getMessage() {
    return "Hello World";
}

You can specify the method parameters in one of two ways:

  • Specify parameters explicitly. In this case, the Kroll layer attempts to validate and convert types before calling the method.
  • Specify a single Object[] argument. Your method must validate parameters and convert types manually at runtime. 

If you specify parameters explicitly and one or more parameters are optional, they must be identified using the @Kroll.argument annotation:

Code Block
@Kroll.method
 public void switchView(@Kroll.argument(optional=true) boolean animate) {
    // do something.
 }

If one argument is optional, all subsequent arguments must be marked as optional as well.

See the @Kroll.method JavaDoc for more information.

For methods with a variable number of arguments, specify the signature as taking a single array argument, and check the number and type of the arguments at runtime.

Code Block
@Kroll.method
 public HashMap doSomething(Object[] args) {
    // check and convert arguments
 }

For information on runtime type checking and type conversions, see Copy of Android Module Development Guide.

If you want to the method name exposed to JavaScript to differ from method name in Java, use the optional name element in the @Kroll.method annotation to specify the JavaScript method name:

Code Block
@Kroll.method(name="setTab")
public void setTabProxy(TiViewProxy tabProxy)
{
    setParent(tabProxy);
    this.tab = tabProxy;
}

Properties

Each proxy object maintains an internal dictionary of properties. Properties can be exposed to JavaScript in one of two ways:

  • Creating custom getter and setter methods. When you create a custom getter and setter methods, you can perform data validation, and take actions when the properties are set.
  • Specifying a list of properties in the @Kroll.proxy (or  @Kroll.module) annotation. This automatically generates getter and setter methods for each of the named properties.

When you use custom getter and setter methods, you're responsible for storing property values in whatever way you want.

Auto-generated property accessors store property values in the internal dictionary. The proxy class provides a set of methods for accessing the proxy's property dictionary from Java:

...

Using custom getter and setter methods is somewhat simpler, and is described first. Subsequent sections describe exposing properties using propertyAccessors, and responding to property changes using a model listener.

Exposing Properties Using Custom Accessor Methods

Properties are exposed as a pair of getter and setter methods with the @Kroll.getProperty and @Kroll.setProperty annotations. This method is very straightforward, but involves writing boilerplate code for each property.

The following example exposes a writable message property to JavaScript. 

Code Block
private String myMessage;
 
@Kroll.getProperty @Kroll.method
public String getMessage() {
    return myMessage;
}
 
@Kroll.setProperty @Kroll.method
public void setMessage(String message) {
    Log.d(TAG, "Tried setting message to: " + message);
	myMessage = message;
}

Note the following two points: 

  • If there were no paired @Kroll.setProperty method, the message property would be read-only.
  • The getter and setter methods also have the @Kroll.method annotation, which exposes the getMessage and setMessage methods to JavaScript.
  • You are responsible for storing and retrieving the value. It can be stored in  in an instance variable (as in the example) or in the internal property dictionary.

In JavaScript, we can now access message as a property, or by calling setMessage and getMessage:

Code Block
var calc = require("module.id");
calc.message = "hi"; // or
calc.setMessage("hi");

The @Kroll.getProperty and @Kroll.setProperty annotations support an optional name element, which specifies the name of the property. If name is not set, the name of the property is constr

Exposing Properties using the propertyAccessors Annotation Element

You can also define a a set of properties in your @Kroll.proxy or @Kroll.method annotation using the propertyAccessors element, and the accessors will be automatically generated for you:

Code Block
@Kroll.proxy(creatableInModule = ActionbarsearchModule.class, 
             propertyAccessors = { "hintText", "value" })

In this case, the proxy has two properties, hintText and value, each with corresponding setter and getter methods, such as setHintText and getValue. These properties are stored in an internal dictionary. You can query properties using getProperty or retrieve the entire dictionary using getProperties

When you define properties this way, you'll usually want to add a model listener to respond to property changes. When you set a property using the generated getter and setter methods, the model listener is automatically notified. 

Note

If you define properties using the propertyAccessors element, you can not override the accessors by defining custom accessor methods. Doing so causes module packaging to fail with a cryptic error. For each property, you must use either propertyAccessors or custom accessors, but not both.

Handling Property Changes using the Model Listener

In most cases, you'll want to do something when the property is set. For this reason, you can use a KrollProxyListener, which receives events when the proxy's properties change. 

The model listener pattern is typically used for views, so that property changes can be delegated from the view proxy to the view object.

To add a listener, call the proxy's setModelListener method:

Code Block
setModelListener(delegate);

In the case of view proxies, the view object is automatically added as a model listener. An instance of the KrollModule class acts as its own model listener, providing a convenient mechanism for handling property changes inside a module.

The KrollProxyListener interface defines four methods that you need to implement:

MethodDescription
listenerAddedCalled when an event listener is added to the proxy.
listenerRemovedCalled when an event listener is removed from the proxy.
processPropertiesCalled when the model listener is added, with a complete set of the proxy's properties.
propertyChangedCalled when one of the proxy's properties changes.

To handle properties, you must add logic to processProperties and propertyChanged for each property you support. The processProperties method receives a dictionary of properties:

Code Block
@Override
public void processProperties(KrollDict props) {
	super.processProperties(props);
	if (props.containsKey("hintText")) {
	    searchView.setQueryHint(props.getString("hintText"));			
    }
	if (props.containsKey("value")) {
		searchView.setQuery(props.getString("value"), false);			
	}
}

The propertyChanged method is fired whenever a property is invoked after the initial call to processProperties.

Code Block
@Override
public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy) {
	if (key.equals("hintText")) {
		searchView.setQueryHint((String) newValue);
	} else if (key.equals("value")) {
		searchView.setQuery((String) newValue, false);
	}
}

You can set properties programmatically on the proxy using either setProperty or setPropertyAndFire. Both methods update the property dictionary and make the new property value visible to JavaScript. The setPropertyAndFire method also invokes the propertyChanged callback on the model listener. In the case of a view proxy, you would typically call setProperty to make a value from the native view object visible to the JavaScript layer: for example, when the user sets the text value in a text field, you want to make the value available to JavaScript. There is no need to fire the propertyChanged callback, since the model listener itself (the view object) is generating the change.

You can also use custom accessor methods when using the model listener. In this case, you'd define the property getter and setter methods using the @Kroll.setProperty and @Kroll.getProperty annotations instead of listing the property in the propertyAccessors element. You can do this if you want to validate or transform the value, or if you want to provide optional arguments in the setter. In the setter, you can then call setPropertyAndFire to store the value and notify the model listener.

Code Block
@Kroll.getProperty @Kroll.method
public String getMessage() {
        return getProperty("message");
}
@Kroll.setProperty @Kroll.method
public void setMessage(String message) {
    // validate or transform the value
    ...
    // store the value and fire the callback
    setPropertyAndFire("message", message);
}

Constants

A constant is simply a static property on a @Kroll.module. Annotate the property with @Kroll.constant and declare it as both static and final. Here's an example:

Code Block
@Kroll.module
public class CalcModule extends KrollModule {
    @Kroll.constant
    public static final int ONE_HUNDRED = 100;
}

The constant can now be referred to directly from JavaScript:

Code Block
calc.ONE_HUNDRED == 100.

Type Conversions

Type conversions can be handled implicitly (through a method signature) or you can explicitly cast Objects to the correct types.

The TiConvert class provides a set of helper methods for casting Objects to specific types. 

The JavaScript, Number, String, Array, Date can be converted into the corresponding Java types, either implicitly or explicitly, as shown in the following table:

JavaScript TypeJava TypeExplicit Conversion
NumberintTiConvert.toInt
NumberfloatTiConvert.toFloat
NumberdoubleTiConvert.toDouble
booleanbooleanTiConvert.toBoolean
StringStringTiConvert.toString or Cast
ObjectHashMap<String, Object>Cast
ArrayObject[]Cast
DateDateTiConvert.toDate or Cast
Ti.BlobTiBlobTiConvert.toBlob or Cast
Ti.Filesystem.FileFileProxyCast

For example, if you declare a method with int values in the signature, the JavaScript Number values passed in will be converted to Java integers implicitly:

Code Block
@Kroll.method
public int multiply(int a, int b)
{ 
	return a * b;
}

The same method with explicit type conversion would look like this:

Code Block
@Kroll.method
public int multiply(Object a, Object b)
{ 
	int aval = TiConvert.toInt(a);
	int bval = TiConvert.toInt(b);
	return aval * bval;
}

Files and Blobs

When a JavaScript Titanium object is passed to Java, the Java method receives a reference to the associated proxy object. Among the most common of these proxy objects are the File and Blob objects.

The Titanium.Blob JavaScript object is represented by an instance of the  TiBlob class. Use TiBlob in method signatures where you want to accept or return a Blob.

Code Block
@Kroll.method
public void addBlob(TiBlob blob)	

To return a Blob from Java, create and return an instance of TiBlob. The TiBlob class provides factory methods to create a Blob from a byte array, File, String, or an Android Bitmap. For example, the following excerpt returns a blob representing a bitmap:

Code Block
@Kroll.method
public TiBlob loadImage()
{
	return TiBlob.blobFromImage(myBitmap);
}

The ModDevGuide project includes sample code for retrieving a bitmap from resources. See ModdevguideModule.java

A Titanium File object is passed into Java as a FileProxy. The ti.modules.titanium.filesystem.FileProxy class is missing from the 2.0 Module API Reference. However, the TiBaseFile object is documented and you can easily get an instance of FileProxy given a TiBaseFile, and vice versa. Many APIs use the TiBaseFile object internally to manipulate files, and you can easily construct a FileProxy from a TiBaseFile

The following example shows one way to create a TiBaseFile using TiFileFactory, and use the new instance to construct a FileProxy:

Code Block
TiBaseFile file = TiFileFactory.createTitaniumFile(new String[] { url }, false);
FileProxy fileProxy = new FileProxy(file);

You can retrieve the associated TiBaseFile from a FileProxy using getBaseFile:

Code Block
TiBaseFile file = fileProxy.getBaseFile();

Adding Views

Views in Titanium must have two classes:

  • The view proxy: A subclass of TiViewProxy.
    • Responsible for exposing methods and properties of the view to JavaScript (just as a normal proxy would do).
    • Implements  TiUIView createView(Activity activity)  which returns a new instance of the associated view implementation.
  • The view implementation: A subclass of TiUIView.
    • Acts as a model listener for the view proxy.
    • Must call setNativeView with an instance of a native Android View either in the constructor, or in processProperties.
    • The view implementation is responsible for taking data from the view proxy, and applying it directly to the native View that it exposes.

For a simple example, see the DemoViewProxy and DemoView in the ModDevGuide public module.

Getting the Current Activity

To get access to the current activity, first use TiApplication's getInstance() method, and then use the getCurrentActivity() method:

Code Block
TiApplication appContext = TiApplication.getInstance();
Activity activity = appContext.getCurrentActivity();

Putting It All Together

As part of the initial project creation, Titanium generated two classes that are used in the example/app.js:

  • The module class: src/org/appcelerator/calc/CalcModule.java
  • An example proxy class: src/org/appcelerator/calc/ExampleProxy.java

Review these and the example/app.js to see modules and proxies in action. Look back through the previous sections to make sure you can answer these questions about the example/app.js before moving on:

  • Where is the ID for the module specified? What are the minimum requirements for an object to be a module?

    Code Block
    var calc = require('org.appcelerator.calc');
  • Where is the "example" method defined? What is its return type, and what should the label.text contain after this line runs?

    Code Block
    label.text = calc.example();
  • Which method in CalcModule will be run when this line executes?

    Code Block
    Ti.API.info("module exampleProp is => " + calc.exampleProp);
  • Which method for this line?

    Code Block
    calc.exampleProp = "This is a test value";
  • Where is this "createExample" method defined, or how did it get defined?

    Code Block
    var proxy = calc.createExample({
  • Where are these methods defined?

    Code Block
    proxy.printMessage("Hello world!");
    proxy.message = "Hi world!.  It's me again.";
    proxy.printMessage("Hello world!");
  • When we are adding the proxy to the window, which of our objects is actually getting sent to the "add" method of Window? Can you pinpoint in our main GitHub repository the code that runs when this line executes?

    Code Block
    window.add(proxy);

Building

The goal of building a module is to get a .zip file that can be included in a Titanium Mobile application. This is how the functionality we exposed gets added to a Titanium Mobile application. With Android modules, these zips are created in the the dist folder of the module being built.

The zip's name will follow this pattern: $MODULE_ID-$PLATFORM-$MODULE_VERSION.zip.

The zip contains:

  • A compiled JAR with classes, generated bindings, and resources from the module project (built from the src folder).
  • Third-party JARs found in the lib folder.
  • The manifest, which includes deployment metadata such as author, version, license, copyright, etc.
  • The timodule.xml.
  • The contents of the platform and example folders.
  • HTML documentation.

Building from Studio

Read the Creating a New Titanium Module guide to find out more about creating and building modules with Studio.

Building from the Command Line with Ant

If ant is already on your PATH, then simply execute it from the top level directory of your module.

On the first build, you should see output similar to this, and an updated zip file will exist in the "dist" directory:

Code Block
$ ant
Buildfile: /Users/marshall/Code/test/test_modules/calc/build.xml

init:
  [mkdir] Created dir: /Users/marshall/Code/test/test_modules/calc/build/classes
  [mkdir] Created dir: /Users/marshall/Code/test/test_modules/calc/dist

process.annotations:
  [javac] Compiling 2 source files to /Users/marshall/Code/test/test_modules/calc/build/classes
  [javac] Note: [KrollBindingGen] Running Kroll binding generator.
  [javac] Note: [KrollBindingGen] No binding data found, creating new data file.
  [javac] Note: [KrollBindingGen] Found binding for module Calc
  [javac] Note: [KrollBindingGen] Found binding for proxy Example

compile:
  [javac] Compiling 2 source files to /Users/marshall/Code/test/test_modules/calc/build/classes
  [copy] Copying 1 file to /Users/marshall/Code/test/test_modules/calc/build/classes

dist:
  [jar] Building jar: /Users/marshall/Code/test/test_modules/calc/dist/calc.jar
  [zip] Building zip: /Users/marshall/Code/test/test_modules/calc/dist/org.appcelerator.calc-android-0.1.zip

BUILD SUCCESSFUL
Total time: 1 second

Building from Eclipse

If you don't have ant in your PATH, or prefer using Eclipse, just follow these steps to build your module from within Eclipse:

  • Right click on build.xml under your module project.
  • Click *Run As* > *Ant Build* (the first option).

You should see output similar to that shown in "Building with Ant from the Terminal", and an updated zip file will exist in the "dist" directory.

Testing and Running

Testing

On Android, there are a number of tools available to help you test and debug your modules: logging and DDMS.

Logging

The Log class offers several static methods for writing to the log.

It is considered a best practice to define a LCAT or TAG variable at the top of your class, and to use that as the first parameter to all calls to Log. For example, the ModDevGuide module defines its tag as "ModdevguideModule" and then it uses it in various log statements.

Remember the tag, because we will use it in a moment in DDMS.

DDMS

DDMS, or Dalvik Debug Monitor Server, is a Google provided app that lets you grab debug information from emulators and connected Android devices.

Read the page on Android.com dedicated to DDMS to get started.

Debugging

The best way to debug your Android modules right now is a bit old fashioned. When there is a problem or unexpected behavior in your module, use log statements to trace through your code's execution. Any advancements in debug capabilities will be announced on our developer blog.

Running

The easiest way to get started with the module is to start writing code in the example/app.js file, and use ant to run and test this code. The example folder is equivalent to the Resources folder of the application, so feel free to copy data files, images, and other code there for testing purposes.

The process for running the example project is simple:

  • Run the android emulator once.
  • Once the emulator is booted, you can run your example app and module as many times as you like.
  • Alternatively install the example app directly to a connected Android device.

Available Ant Build Targets

Ant has what are known as build targets. These are shortcuts to predefined actions. We will talk about how to use them in a moment, but first take a look at this list:

  • dist (the default): Compiled a module and generates a .zip file for distribution.
  • clean: Removes all generated zips and binaries from previous builds.
  • install: Runs the "dist" build target, generates a project using "example" as the "Resources", and then installs it to a connected Android device.
  • run.emulator: Launches an Android emulator for the "run" build target.
  • run: Runs the "dist" build target, generates a project using "example" as the "Resources", and then installs it to a running emulator (hint: use the "run.emulator" target to start up an emulator!).

Now look at the next section if you want to interact with modules from the terminal, or skip to the next section if you want to use Eclipse. Fear not, you can switch between the two at any time!

Running Ant from the Terminal

Ant works with your current directory, so "cd" in to the top directory of your module, then type the following:

Code Block
ant run.emulator

The emulator will launch, and its output will show in the terminal.

Look through the other build targets and try them out.

Running Ant from Eclipse

To start the emulator from Eclipse, we need to setup a launch configuration for each ant build target.

We will start with run.emulator:

  • Right click on  build.xml , click on * Run As * > * Ant Build... * (the 2nd option).
  • A window will open with configuration settings for a new launch configuration.
  • Under * Check targets to execute , uncheck the **dist * target, and check the * run.emulator * target.
  • Rename the * Launch Configuration * to something memorable, such as  run emulator .
  • Click * Apply , then **Run *.
  • From now on you can run the * Launch Configuration * from * External Tools * menu in * Run *, or the toolbar entry.

Now that you have set up run.emulator, also set one up for run and install.

The configurations you set up will be quickly accessible through the Run drop down:

Image Removed

Running the Example Project

Once the emulator is up and running (through the "run.emulator" build target), the example can be run in it. In the last section, you saw how to use build targets. Do "ant run" now to see your app launch in the emulator! (Hint: make sure you unlock the emulator)

Note that instead of running the emulator, you can "ant install" the example app directly to a connected device. You will see a message in the console after the app successfully installs to look for it in your app tray (you must launch the app manually).

You should see a default "hello world" app, such as the following:

Image Removed

Help! *Run* Times Out Trying to Find the Emulator!

If the *run* target times out trying to find the emulator, then the ADB server needs to be restarted. Run the following two commands, replacing $ANDROID_SDK with the path to your Android SDK.

Code Block
$ $ANDROID_SDK/tools/adb kill-server
$ $ANDROID_SDK/tools/adb start-server

Module Distribution and Installation

To use this new module in a Titanium Mobile app, read the Using Titanium Modules guide.

At the end of the Creating a New Titanium Module guide are bullet points to help with using the Open Mobile Marketplace.

Appendix: Building JavaScript Native Modules

Beginning in Titanium Mobile SDK 2.0.0, we also support the ability to package a CommonJS module as a Titanium Android module. Up until now, we've talked only about fully native modules. Let's now talk about JavaScript modules.

Sometimes you want to create a native module but implement them written in JavaScript and distribute them as compiled modules. In Titanium, you would write your module code in a file named "<module_id>.js" in your "assets" directory. Using our sample project, this would be "org.appcelerator.calc.js".

The module file must use the CommonJS format for declaring a module and it's exports. Let's start with a very simple example that defines one property and one function:

Code Block
langjavascript
exports.addition = function(x, y)
{
  return (x + y);
};

Copy this code into a new file named "org.appcelerator.calc.js" under the "assets" folder.

Now, here is some test application code to use the module. Put this in an app.js:

Code Block
langjavascript
var calc = require('org.appcelerator.calc');
var result = calc.addition(5, 6);
alert("5 + 6 = " + result);

CommonJS allows you to cleanly export one or more properties/functions by defining them to the special "exports" object (which is pre-defined before loading your module). Any methods or properties defined outside of the "exports" object will be considered module scoped and won't be visible outside of the module.

Code Block
> titanium.py create --platform=android --type=module --name=$MODULE_NAME --id=$MODULE_ID --android=$ANDROID_SDK

 

These guides assume you are familiar with native development using the Android SDK and an Eclipse-based IDE.

Chapters

Android Module Quick Start

Provides basic information to quickly create, build, package and test modules.

Android Module Architecture

Provides in-depth information about the class components used to build modules.  Titanium uses a specific notation for each module component.

Android Module Project

Provides in-depth information about the structure of a module project as well as using Studio and the CLI to manage the projects.  Also provides information about adding assets and third-party frameworks to the module.

Android Module API Reference

Useful APIs for module development.  The module components extend the KrollModuleKrollProxyTiUIView and TiViewProxy classes.