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:
- Titanium SDK
- Android SDK API 26+
- Studio or the Appcelerator Command-Line Interface (CLI) for creating modules, and building and running test applications
- Android NDK and add an ANDROID_NDK environment variable pointing to the NDK directory. See Installing the Android NDK.
- gperf must be installed and in your system PATH. See Installing gperf.
- Python, Python setuptools and the markdown module, and Python in your system PATH. See Installing Python and Installing Required Python Packages.
If you want to use Studio, install:
- Eclipse Java Development Tools plugin. See Installing the Java Development Tools.
- Android Development Tools plugin. See Installing the Android Development Tools.
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 can place module assets such as images. The files in this directory are added as JAR resources which you can be fetch in Java via the ClassLoader.getResourceAsStream() method. They're also copied to the APK's "assets" folder. |
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. 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. |
Resources/ |
Supported as of Titanium 9.0.0. Files placed in this directory will be
copied to the Android app's root "Resources" directory when built,
making them accessible to the Titanium app's JavaScript files. These files
are also accessible in Java via the AssetManager class. |
android/build.gradle |
As of Titanium 9.0.0, this optional gradle file allows a module to define its dependencies. |
android/lib/ |
Place any third-party JAR dependencies here and they will be bundled up as a part of your module automatically. As of Titanium 9.0.0, it is highly recommended to reference dependencies via "build.gradle" instead to avoid dependency collision with other modules. |
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/android/AndroidManifest.xml |
As of Titanium 9.0.0, you can optionally specify the module's custom AndroidManfiest.xml here. Alternatively, you can do the same within the timodule.xml as documented below. |
android/platform/android/aidl/ |
As of Titanium 9.0.0, you can add Java code generation templates here, as defined by the Android Developer: AIDL guide. |
android/platform/android/assets/ |
As of Titanium 9.0.0, you can optionally provide files that will be copied to the APK's root "assets" folder here. |
android/platform/android/jniLibs/ |
As of Titanium 9.0.0, you can add C/C++ *.so libraries to be bundled with the module. These libraries must placed under
subdirectories named after their respective architecture such as armeabi-v7a , arm64-v8a , x86 , and x86_64 . |
android/platform/android/rs/ |
As of Titanium 9.0.0, you can add RenderScript files here as defined by the Android Developer: RenderScript guide. |
android/platform/android/res/ |
Optional folder where you can add Android resource files such as drawables, layouts, mipmaps, values, etc. as defined in the Android Developer: Providing Resources guide. |
android/src/ |
Folder containing your Java source files for the module. Can contain Kotlin source files as of Titanium 9.0.0. 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. |
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
, example
, and Resources
.
Build properties file
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-25 |
google.apis | Path to the Google APIs add-ons folder |
/Users/<USERNAME>/opts/android-sdk/add-ons/addon-google_apis-google-25 |
android.ndk | Path to the Android NDK (if needed) | /Users/<USERNAME>/opts/android-ndk |
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 arm64-v8a |
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) 2020 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. 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 7.0.0. |
respackage |
This setting only applies to Titanium versions older than 9.0.0. This is specific package name to generate a R.java. If you got exception
like |
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> $ appc new -n <MODULE NAME> -- id <MODULE ID> Appcelerator Command-Line Interface, version 7.1.2 Copyright (c) 2014-2018, 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
- From the menu, select File > New > Mobile Module Project to open the New Mobile Module Project dialog.
- In the Project name field, enter a name for the module.
- In the Module ID field, enter a module ID for the module.
- In Deployment Targets, select Android.
- Click Next.
- 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. - 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
- Select your module folder in the Project Explorer view.
- Verify Package and Android Module are displayed in Launch Mode and Launch Target, respectively.
- Click the Package icon to open the Package Android Module dialog.
- In Output Location, select either
- Titanium SDK to install the module in the Titanium SDK home path to be accessed by any Titanium application
- Mobile App Project and choose an application to install the module locally that can be accessed by one that Titanium application
- Location and enter a path to copy the ZIP file to for distribution
- 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:
- Create a new Titanium Classic or Alloy project.
- Install the module to either the Titanium SDK home directory or in the project.
- Add the module as a dependency to the project.
- 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. The Java 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); } |
Adding 3rd party libraries
Gradle Dependencies
As of Titanium 9.0.0, you can reference libraries via gradle by adding
a build.gradle
file to the module's root android
directory. This is the preferred way of adding libraries because
the gradle build system will automatically include a dependency's dependencies
and resolve version conflicts.
An example can be found here: ti.map/android/build.gradle
The below is an example build.gradle
file which provides access to the Google "Material Components"
library.
dependencies { implementation 'com.google.android.material:material:1.1.0' } |
Local Dependencies
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:
- Right-click the module project (root folder) and select Properties to open the project's properties dialog.
- In the left pane, select Java Build Path.
- In the right pane, click the Libraries tab.
- Click the Add External JARs... button to open the JAR Selection dialog.
- Navigate to the module's
android/lib
folder and select the JAR to add. - Click Open. The JAR should be added to the JARs list.
- Click OK to dismiss the dialog.
With Titanium 6.1.1 - 8.3.1, you can also copy AAR (Android Archive) library
files to the module's lib
directory. However, this is not supported as of Titanium 9.0.0, which
requires you to reference these AAR libraries via a build.gradle
file instead.
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.
Bundling files
For Android modules, you can either add assets in the module's assets
folder or android/platform
folder.
Module "assets" folder
Files in the module's assets
folder are added as JAR resources. 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()); |
Module "platform/android/res" folder
Add any of the resource directories defined in Android Developer: Providing Resources to add drawables, layouts, values, etc. to the built app. To
access these files, you can use the Titanium SDK TiRHelper
helper class.
// 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()); } catch (ResourceNotFoundException e) { Log.e( 'BADSTUFF' , '[ERROR] EXCEPTION -- RESOURCE NOT FOUND' ); } |
Format / Lint source-code
The Titanium SDK uses clang-format to have a unified code-style in its source-code (clang-format for iOS and Android, ESLint for the CLI). You can do the same by following the following few steps:
- Copy the
.clang-format
file from here to the "android/
" directory of your module project, e.g.<module-root>/ios/.clang-format
- Install the clang-format CLI:
npm install -g clang-format
-
Optional: Ensure that you have your module project in Git to be able to restore the old files in case you do not like the predefined format
- Format your source with:
clang-format -style=file -i src/<yourmodule>/*.java
- Thats it! All *.java files have been formatted.
Now that you have a format, you can also extend your .clang-format with more formatting rules or adjust existing ones to match your own code style.
Troubleshooting
Conflicting JAR files / Google Play Services
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.
Prior to Titanium SDK 7.0.0, 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. In Titanium
7.0.0 and later, use the ti.playservices module to handle play services dependencies centralized. Simply add it
to your timodule.xml and users will be notified if they do not include
the module in their project.
Android NDK build fails
If the Android NDK build fails, it can be because of various reasons:
- Your module has compile errors. Usually the build on the "javac" compile step already, but in case it does not, scroll up in the logs to see the actual error)
- Your NDK version is outdated (Check for the latest version here)
- Your project path contains spaces, which is not recommended for projects
in general but especially causes build failures like
/android-ndk/build/core/build-local.mk:158: *** Android NDK: Aborting
, which is an Android NDK error for spaces in projects OR invalid directories for the Android NDK. Please note that spaces in a sub-directory can also cause this.
In any case, ensure to run your Titanium module build with log-level "trace"
(e.g. appc run -p android -build-only -l trace
) to see the whole build command. If you find issues that are not listed
here, feel free to let us know via JIRA or TiSlack.