Android BOOT_COMPLETED handler module

This Titanium Android module provide a place where you can run your JS script when the device receives BOOT_COMPLETED broadcast intent. By simply adding boot_completed.js into your Resources folder, this JS file will be run when the broadcast intent received.

Continue reading Android BOOT_COMPLETED handler module

Android Progress Notification module

Android Progress Notification module is a module to display notification in Android notification area which contains progress bar. In addition, it also support setting the number of notification, useful if you have a number of grouped notifications.

nc_progress_notif_1 nc_progress_notif_2

Continue reading Android Progress Notification module

Add custom framework to Titanium iOS module

For example, I’m creating a module com.mymod, which include MillennialMedia SDK, that has 2 custom frameworks:

  • MillennialMedia.framework
  • SpeechKit.framework

Copy the frameworks into <module folder>/platform/iphone/custom_frameworks

Open the module in Xcode & include the framework – you can choose to include into any folder, for example the root of project

Edit module.xcconfig. Choose a unique variable name to set the environment variables (e.g MYMOD)

MYMOD_ID=com.mymod
MYMOD_VER=1.0
MYMOD_DIR=$(SRCROOT)/../../modules/iphone/$(COM_MYMOD_MYMOD_ID)/$(COM_MYMOD_MYMOD_VER)/platform/iphone

OTHER_LDFLAGS=$(inherited) -F"$(COM_MYMOD_MYMOD_DIR)/custom_frameworks" -framework MillennialMedia -F SpeechKit

Notice that we’re not using the defined env vars. This is because Titanium build script rename the var based on the module id (com.mymod becomes COM_MYMOD). If we’re referring to the var name that we define, it produces distorted value, example, MYMOD_VER become ” 1.0 1.0″

Reference: https://developer.appcelerator.com/question/132459/module-dev-third-party-framework

Titanium Studio unbound classpath container error

Faced this error while creating Titanium module. This solution is not in exact order, however after trying all the steps I finally could get rid of the error message

Environment:

Set JAVA_HOME

  • edit ~/.bash_profile
  • export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  • source ~/.bash_profile

Edit Titanium Studio preferences

  • Preferences > Java > Compiler
  • set ‘Compiler compliance level’ to ‘1.6’
  • Java > Installed JREs > Add > Standard VM
  • set ‘JRE Home’ to JAVA_HOME
  • Finish
  • clean project

After cleaning the project, the error should go away

Method calling thread for Titanium module (Android)

When creating method for a Titanium module in Android, using @Kroll.method annotation, this method will be invoked on KrollRuntimeThread. This is important to know if that method is accessing UI component, such as TextView or WebView, since all UI related components must be handled on main thread.

@Kroll.method annotation have one convenient argument that allow method to be called on UI thread

@Kroll.method(runOnUiThread=true)
public void show() {}

However, it is deprecated – as noted on Specific Changes no. 18 of Android Module Porting Guide , you can use TiMessenger class.

Or, easier way is to use Activity runOnUiThread method

@Kroll.method
public void show() {
    getActivity().runOnUIThread(new Runnable() {
        @Override
        public void run() {
            // code here
        }
    });
}

Add project as library – Titanium module (Android)

Native Android application can include other projects as library, when they need that particular SDK library functionalities – using Eclipse, right click project > Properties > Android > Library. However for Titanium module, there’s no option to add other projects as library. Instead, we need to include the whole project itself into the module project directory.

For example, I’m creating GooglePlayServices module, so I need to copy files from ANDROID_SDK_DIR/extras/google/google_play_services/libproject/google-play-services_lib/ into the module folder

export MODULE_DIR=~/Workspace/ti.googleplayservices/
cd $ANDROID_SDK_DIR
cp -r libs/*.jar $MODULE_DIR/lib
cp -r res/ $MODULE_DIR/platform/android/
cp -r src/ $MODULE_DIR/src/

Most of the time, the library that being included will be missing R.java and BuildConfig.java file. Depending on the library itself, create those files manually. For this GooglePlayServices module, the generated resource file (R.java) is located at com.google.android.gms namespace:

touch $MODULE_DIR/src/com/google/android/gms/R.java

(for Facebook SDK that I created sometime ago, it’s at com.facebook.android)

Now, again depending on the library we’re including, the content of R.java can be found either from the source code (like Facebook SDK) or from the documentation (GooglePlayServices).

Originally, R.java is generated by Android build tool when building APK file for a project, but since we’re building a Titanium module, R.java cannot be generated, since it’s value might clash with the actual project that use this module. Values inside R.java are generated from the XML resources (such as strings.xml, values.xml, layout.xml), or graphic files (icons / images files, also known as drawables).

The difference between this file and the generated one, is that we need to initialize it to populate its values. By using TiRHelper, we will get and assign all the values at runtime.

package com.google.android.gms;

import org.appcelerator.titanium.util.TiRHelper;
import org.appcelerator.titanium.util.TiRHelper.ResourceNotFoundException;

public class R {

    public static class attr {
        public static int adSize;
        public static int adUnitId;
        public static int allowShortcuts;
        // ... more ...
    }

    public static class color {
        // ...
    }

    public static class drawable {
        // ...
    }

    public static class id {
        // ...
    }

    public static class integer {
        // ...
    }

    public static class string {
        // ...
    }

    public static class styleable {
        // ...
        public static final int[] AdsAttrs = {
            styleable.AdsAttrs_adSize,
            styleable.AdsAttrs_adSizes,
            styleable.AdsAttrs_adUnitId,
        };
        // ... more ...
    }

    public static void initialize() {
        R.attr.adSize = getResource("attr.adSize");
        R.attr.adUnitId = getResource("attr.adUnitId");
        R.attr.allowShortcuts = getResource("attr.allowShortcuts");
        // ... more ...
    }

    private static int getResource(String path) {
        int id = 0;
        try {
            id = TiRHelper.getResource(path);
        } catch (ResourceNotFoundException e) {}
        return id;
    }
}

Then, in the main module class, don’t forget to call initialize() method on app creation.

@Kroll.onAppCreate
public static void onAppCreate(TiApplication app) {
    R.initialize();
}

Use view from custom module inside Titanium ListViewItem

Most example I found on how to create view inside ListViewItem are using Titanium views itself (those from Ti.UI namespace). This post shows how to use views from other modules. For example, I’m using canvas view module, TiAndroidCanvas (Android) and ti.canvas (iOS)

Updated:

In order for ListView to use the custom module, listview.js need to be able to access the JS variable pointing to the module, and invoke the create* method to create the view instance. So, instead of using try-and-error method as shown previously, just assign your require()-ed module to global scope

Android example:

global.CanvasModule = require('com.wwl.canvas');

// template
{
    type: 'CanvasModule.CanvasView'
}

(therefore, listview.js will invoke CanvasModule.createCanvasView() to create the view instance)

iOS example:

global.CanvasModule = require('ti.canvas');

// template
{
    type: 'CanvasModule.View'
}

(therefore, listview.js will invoke CanvasModule.createView() to create the view instance)

Android

Include the module into global variable, then in ListItemTemplate, assign using the view’s class name (in Java source code, the class that inherits TiViewProxy, without -Proxy suffix)

var Canvas = require('com.wwl.canvas');

// in template
{
    type: 'Canvas.CanvasView',
    properties: {},
    events: {}
}

iOS

No need to include the module, but in ListItemTemplate, assign using the actual view proxy class name in Objective-C code.

// in template
{
    type: 'TiCanvasView',
    properties: {},
    events: {}
}