Android Module Project

Introduction

This guide covers how to manage your module project as well as how to add third-party frameworks and bundle assets with your module.  You can use Studio, Eclipse or the Appc-CLI to build Android modules.

Prerequisites

To develop an Android-based Module, you need to install the following tools and setup a few additional environment variables:

If you want to use Studio, install:

Project Structure

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/Directory Description
LICENSE The 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/

The directory where you should place module assets, such as images. The items in this directory are added to the JAR library's asset folder, which is distributed with your module.

documentation/ The directory where you should place your module documentation for end-users. The file index.md is a Markdown-formatted template file that you should use when writing your module documentation. You may also write your documentation using the TDoc Specification. This is only required for module distributed in the Appcelerator Marketplace. You can safely ignore this directory if you do not intend to distribute your module.
example/ The directory where your module example(s) should go. The file app.js will be generated to include a sample loading of your module in a test window. This file can be used for quickly testing your module as well as give an example to end-users on how to use your module. This directory is distributed with your module.
android/build.properties An Ant properties file that contains paths to the Titanium SDK, Google API add-ons, Android NDK and Android SDK on your computer. (Deprecated since 5.0.0 in favor of the Appc-CLI build)
android/build.xml The main Ant build script used to build and package the module.   (Deprecated since 5.0.0 in favor of the Appc-CLI build)
android/lib/ Place any third-party JAR dependencies here and they will be bundled up as a part of your module automatically.
android/manifest A special file that describes metadata about your module and used by the Titanium compiler. This file is required and is distributed with your module. 
android/platform/ This optional folder can include an android subdirectory, then add any of the resource directories defined in Android Developer: Providing Resources guide.
android/src/ The source code for the module. This directory is not distributed with your module.
android/timodule.xml A 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 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.

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.

Build properties file

Icon

This was deprecated since 5.0.0.


The build.properties file contains build variables used by the Ant CLI. Using the build.properties is deprecated in favor of the unified build-command appc ti build -p android --build-only.

Variable Description Example
titanium.platform Path to the Titanium SDK android folder /Users/<USERNAME>/Library/Application Support/Titanium/mobilesdk/osx/<VERSION>/android
android.platform Path to the Android SDK platforms folder /Users/<USERNAME>/ opts /android- sdk /platforms/android-23
google.apis Path to the Google APIs add-ons folder /Users/<USERNAME>/ opts /android- sdk /add-ons/addon-google_apis-google-23
android.ndk Path to the Android NDK (if needed) /Users/<USERNAME>/ opts /android-ndk

Titanium SDK 6.0.0 Changes

Manifest file

Titanium module metadata is described in a special text file named manifest. This file is a simple key/value property format.

Before you distribute your module, you must edit this manifest and change a few values. Some of the values are pre-generated and should not be edited.  These are noted with the comment before them. In the manifest file, any line starting with a hash character (#) is ignored. The following are the descriptions of each entry in the manifest:

Key

Description/Purpose

version

This is the version of your module. You should change this value each time you make major changes and distribute them. Version should be in the dotted notation (X.Y.Z) and must not con-tain any spaces or non-number characters.

architectures The binary architectures the module supports as a delimited list. Example: x86 armeabi-v7a

description

This is a human-readable description of your module. It should be short and suitable for display next to your module name.

author

This is a human-readable author name you want to display next to your module. It can simply be your personal name, such as "Jon Doe" or an organizational name such as "Axway Appcelerator".

license

This is a human-readable name of your license. You should use a short description such as "Apache Public License", "MIT" or "Commercial".

copyright

This is a human-readable copyright string for your module. For example, "Copyright (c) 2017 by Axway Appcelerator, Inc."

name

This is a read-only name of your module that is generated when you created your project. You must not edit this value.

moduleid

This is a read-only module id of your module that is generated when you created your project. You should not edit this value. NOTE: you must generate a unique id. We recommend using your reverse-DNS company name + module_name as a pattern to guarantee uniqueness. The Titanium Marketplace will only allow unique module ids when distributing modules. If you must edit this value, you must also edit the value in your module implementation file.

guid

This is a read-only unique module id for your module that is generated when you created your project. You must not edit this value.

platform

This is a read-only platform target of your module that is generated when you created your project. You must not edit this value.

minsdk

The is a generated value for the minimum Titanium SDK version that was used when creating your module. The current minimum version for new Android modules is 6.0.0.

respackage This is specific package name to generate a R.java. If you got exception like java.lang.NoClassDefFoundError: com.example.mypackage.R$layout then add the following entry to the your module manifest file: respackage: com.example.mypackage . This will generate a corresponding java R file com.example.mypackage.R.java

CLI tasks

Create a new module project

To create a new module project, run the following Appcelerator CLI command: 

appc new -d /PATH/TO/WORKSPACE -n <MODULE_NAME> --id <MODULE_ID>
### when prompted for the project type, select "Titanium Module" 

### Example
$ ti create -n test --id com.example.test
Appcelerator Command-Line Interface, version 6.2.2
Copyright (c) 2014-2017, Appcelerator, Inc.  All Rights Reserved.
? What type of project are you creating? 
  Native App 
  Arrow App 
❯ Titanium Module (timodule)
  Apple Watch App

If you omit any of the options, the CLI will prompt you to enter them.

Build and package the module

To build and package a module, run ti build in the android directory.

cd /<PATH_TO_MODULE_PROJECT>/<MODULE_NAME>/android
appc run -p android --build-only

After the build completes, you should have a ZIP file in the android/dist directory and see the following message in the console: 

** BUILD SUCCEEDED **

With the ZIP file, you can either:

  • Uncompress it in the Titanium SDK home path to install the module globally for all your Titanium applications
  • Uncompress it in a Titanium project's parent directory to install the module locally for that one Titanium application
  • Distribute the ZIP file

Clean the project

Earlier, you could clean your module with ant clean. These days, using the Appc-CLI, the build will be cleaned automatically before a new build is made.

Studio tasks

Create a new module project

  1. From the menu, select File > New > Mobile Module Project to open the New Mobile Module Project dialog.
  2. In the Project name field, enter a name for the module.
  3. In the Module ID field, enter a module ID for the module.
  4. In Deployment Targets, select Android.
  5. Click Next.
  6. In the Module Manifest File page, enter information about your module, such as the license information, version number, etc.  You can also edit this information in the manifest file later.
  7. Click Finish.

Build and package the module

You can either use Studio's launch toolbar or use Ant from the right-click context menu.

Studio Toolbar

  1. Select your module folder in the Project Explorer view.
  2. Verify Package and Android Module are displayed in Launch Mode and Launch Target, respectively.
  3. Click the Package icon to open the Package Android Module dialog.
  4. In Output Location, select either
    1. Titanium SDK to install the module in the Titanium SDK home path to be accessed by any Titanium application
    2. Mobile App Project and choose an application to install the module locally that can be accessed by one that Titanium application
    3. Location and enter a path to copy the ZIP file to for distribution
  5. Click Finish.

In the Console view, you will see the build log output.  After the build completes, the package (ZIP file) will be in the module's android/dist folder.

Test the module

To test a module:

  1. Create a new Titanium Classic or Alloy project.
  2. Install the module to either the Titanium SDK home directory or in the project.
  3. Add the module as a dependency to the project.
  4. Load the module and make module API calls.

Debug the module

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.  

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.

private static final String TAG = "FooProxy";
 
@Kroll.method
public void fooFunction(String arg)
{ 
    Log.i(TAG, "fooFunction received: " + arg);
}

DDMS

DDMS, or Dalvik Debug Monitor Server, is a Google-provided application that lets you grab debug information from emulators and connected Android devices.  To get started, see Android Developer: Using DDMS.

Add a third-party JAR

To use a third-party JAR in your module, add the JAR file to the module's lib directory (not the libs directory), so it can be copied over during the module's build process and linked when building the application.  If you are using Studio, you need to add the JAR as a dependency to the module project before importing the package and making API calls.

To add a JAR as a dependency in Studio:

  1. Right-click the module project (root folder) and select Properties to open the project's properties dialog.
  2. In the left pane, select Java Build Path.
  3. In the right pane, click the Libraries tab.
  4. Click the Add External JARs... button to open the JAR Selection dialog.
  5. Navigate to the module's android/lib folder and select the JAR to add.
  6. Click Open.  The JAR should be added to the JARs list.
  7. Click OK to dismiss the dialog.

Using Android Libraries

With Titanium 6.1.0 and later, you are also able use Android Libraries (.aar) in native Android modules as well. You add them the same way as .jar files by simply placing them into the lib directory. During the build process they will be extracted and processed by our build pipeline and can use all bundled classes and resources.

Resolving Android Library dependencies

If the Android Library you want to use in your module has dependencies on other libraries, you also need to place them in your module's lib directory. Due to the fact that we do not yet support Gradle, we can not automatically resolve those dependencies for you, but there are two easy ways to resolve them on your own.

For smaller libraries it often is enough to take a look at the .pom file that you can view on the library's repository page on jCenter or Maven Central. This file lists all required dependencies of that package.

Since the dependencies listed in a .pom can have more dependencies on their own, the above can get a tedious task for huge dependency trees. If you have Gradle installed, you can use it on a dummy project to print the dependency graph for you. To do, create a build.gradle file inside an empty directory and add the following:

Gradle dummy project file  Expand source
apply plugin: 'com.android.application'
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    defaultConfig {
      applicationId "com.example.deps"
    }
}
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
    }
}
dependencies {
  // List your module dependencies here, for example the appcompat-v7
  compile 'com.android.support:appcompat-v7:25.3.+'
}
  

After that you can run ANDROID_HOME=<android-sdk-path> gradle dependencies --configuration compile from within the directory where the above file is located and Gradle will print all dependencies for you. Now you will need to grab the listed dependencies and place them inside your module.

Where do i get .aar files?

Icon

Most third-party libraries can be downloaded from either GitHub or from one of the popular repositories like jCenter or Maven Central. Copies of the Android Support Libraries can be found inside your Android SDK directory under <andriod-sdk>/extras/android/m2repository/com/android

Overriding bundled Android Support Libraries

By default Titanium comes bundled with a set of Android Support Libraries. These are locked to a specific version with each release, which can cause incompatibility with the latest version of a third-party library you might want to use in your module. To solve this it is possible to override the bundled Android Support Libraries with a newer version from within your modules. To override the bundle, place them inside your module's lib directory as you would for any other library.

We currently bundle the following Android Support Libraries with Titanium SDK 6.1.0 and later, all in version 23.0.4:

  • appcompat-v7
    • support-annotation
    • support-vector-drawable
    • animated-vector-drawable
  • cardview-v7
  • support-v4

Although it is possible to replace a single Android Support Library, it is recommended to replace all of those libraries entirely with a new version. For example, if you want to replace the bundled Android Support Libraries with a recent version from 25.x, you would have to place the following libraries in your module's lib directory:

  • appcompat-v7-25.3.1.aar

  • support-vector-drawable-25.3.1.aar

  • animated-vector-drawable-25.3.1.aar

  • support-v4-25.3.1.aar

  • support-compat-25.3.1.aar

  • support-core-ui-25.3.1.aar

  • support-core-utils-25.3.1.aar

  • support-fragment-25.3.1.aar

  • support-media-compat-25.3.1.aar

 

Quality of life improvements planned

Icon

This is a brand new feature in Titanium 6.1.0 and we are already looking into improving this so you won't need to copy the actual libraries yourself. Since Google is rapidly changing those libraries and their dependencies there is quite some work to be done there. Stay tuned for further updates!

Adding Android Libraries to Studio

To properly resolve any imports of your used Android Libraries in Studio, you need to add the JARs they are contained in to Studio's Java build path. Before you add any import statements to your code, build the project at least once. This is required to process the AAR files and extract the JAR files they contain. After that, add the required JARs to Studio just as described in the Add a Third-Party JAR section of this guide. The extracted JAR files can be found under build/android/intermediates/exploded-aar. There you'll find a directory for each AAR file. Inside each of those directories, add the classes.jar and any additional JAR files under the lib directory.

Bundle Module Assets

For Android modules, you can either add assets in the module's assets folder or android/platform folder.

Assets folder

Files in the assets folder are added to the JAR library's assets folder. To access these files, use the Android Class's getResource() method to retrieve a URL object or getResourceAsStream()  method to retrieve an InputStream object. 

// Original file was in assets/image.png
URL url = getClass().getClassLoader().getResource("assets/image.png");
Log.i("GETFILE", url.toString());
// do something with the URL
Icon

The README file and JavaScript files (any file with a .js extension) in the assets folder are not added to the JAR library.

Platform folder

Files in the platform folder are distributed in the module's ZIP file and copied over to the application's platform folder.  Add an android subfolder, then add any of the resource directories defined in Android Developer: Providing Resources. To access these files, you can use Android's AssetManager class or the Titanium SDK TiRHelper  helper library.

// Original file was in android/platform/android/res/drawable/image.png
int result = 0;
try {
    result = TiRHelper.getApplicationResource("drawable.image");
    Log.i("GOODSTUFF", new Integer(result).toString());
    // do something with the result
} catch (ResourceNotFoundException e) {
    Log.e("BADSTUFF", "[ERROR] EXCEPTION -- RESOURCE NOT FOUND");
}		

 

Distribute your module through the Appcelerator Marketplace

To distribute your module through the Titanium+Plus Marketplace, you'll first need to package normally. Once you have tested your module locally and are ready to distribute it, you can then submit it to the marketplace for distribution. There are several prerequisites you'll need before you can distribute:

  • You must have a valid Titanium developer account.
  • You must have fully completed filling our your manifest values.
  • You must have a valid license text in the LICENSE file in your project.
  • You must have a valid documentation file in the index.md file in your documentation directory of your project.
  • You must specify some additional metadata upon upload such as the price (which can be free).
  • If you are charging for your module, you must establish a payment setup with Appcelerator so we can pay you.
  • You must accept the Titanium+Plus Marketplace terms of service agreement.

Once you have upload your module and completed the necessary submission steps, your module will be queued for submission and availability in the marketplace directory.

Known issues

Conflicting jar files detected

When building an application that includes two or more modules that contains the same library, in particular, the google-play-services.jar, the JAR files may conflict indicating that each module is using a different version of the library (MOD-1985).

Error Log  Expand source
[ERROR] Application Installer abnormal process termination. Process exit value was 1
[ERROR] :  Conflicting jar files detected:
[ERROR] :  
[ERROR] :  The following modules have different "google-play-services.jar" files
[ERROR] :     mymodule   (version 3.0.3) (hash=8b95ece0c3ae132fb898ec8beef1cb2d)
[ERROR] :     ti.map     (version 2.2.3) (hash=a9b753b4c63719e24d0022e341c57b2e)
[ERROR] :  
[ERROR] :  You can either select a version of these modules where the conflicting jar file is the same or you
[ERROR] :  can try copying the jar file from one module's "lib" folder to the other module's "lib" folder. 
  

To resolve this issue, you can either delete one of the JAR files from one of the modules or copy the JAR file from one module's lib folder to the other's to make both versions the same.  This solution only works on a per-application basis and is not a global solution.

If you include the Google Play services library in your module, you many need to include instructions telling the developer how to workaround this issue if they include other modules that use the Google Play services library, such as the ti.map or ti.cloudpush modules.

Related Links