Last month I presented a talk at the Atlanta Titanium Developers meetup and wanted to share many of those items here in a blog as well. The talk was a bit long, so this isn’t going to encompass the talk in its entirety. I’ll save the later portions of that talk for additional posts.

Many Titanium developers make use of Titanium Studio which is a fantastic tool, but rarely take advantage of the other tools that can help them become more effective in the pursuit of mobile application development. Items that this post will address:

  • logging in Titanium Android and iOS applications
  • building, launching (in the simulator) and deploying (to a device) with Android and iOS platform tools
  • why creating a custom logger is useful

In Titanium Studio, you can modify the log level that your target is launched with in the configuration settings. To do this, open the run configuration for an application you’ve previously launched and set the “Log Level”.

Now inside our application we could execute the following code.

1
2
3
4
Ti.API.warn("hi @warn");
Ti.API.info("hi @info");
Ti.API.debug("hi @debug");
Ti.API.trace("hi @trace");

Which will produce the following log statements in Titanium Studio’s console for iOS. As you can see both “hi @debug” and “hi @trace” are ommitted from the console.

1
2
3
4
5
[INFO] One moment, building ...
[INFO] Application started
[INFO] pragmatics_skills/1.0 (2.1.3.GA.15997d0)
[WARN] hi @warn
[INFO] hi @info

And the following for Titanium Studio’s console for Android.

1
2
3
4
5
6
7
8
9
10
11
[INFO][TiApplication( 399)] (main) [199,199] Titanium 2.1.3 (2012/10/02 16:16 15997d0)
[INFO][TiDbHelper( 399)] (main) [252,451] No value in database for platform key: 'unique_machine_id' returning supplied default ''
[INFO][TiDbHelper( 399)] (main) [10,461] No value in database for platform key: 'hardware_machine_id' returning supplied default ''
[INFO][TiApplication( 399)] (main) [9,563] Titanium Javascript runtime: v8
[INFO][TiRootActivity( 399)] (main) [0,0] checkpoint, on root activity create, savedInstanceState: null
[INFO][TiApplication( 399)] (main) [1,1] Analytics have been disabled
[ERROR][TiApplication( 399)] (KrollRuntimeThread) [643,644] APP PROXY: ti.modules.titanium.app.AppModule@40522ae0
[WARN][V8Object( 399)] Runtime disposed, cannot set property 'userAgent'
[INFO][ActivityManager( 62)] Starting: Intent { cmp=com.ehirelabs.pragmaticskills/ti.modules.titanium.ui.TiTabActivity (has extras) } from pid 399
[WARN][TiAPI ( 399)] hi @warn
[INFO][TiAPI ( 399)] hi @info

Now lets focus on running the code in Xcode. To do this, you must first have launched your application through Titanium Studio. Titanium creates an Xcode project at the location below.

1
#{projectdir}/build/iphone/#{projectname}.xcodeproj

Open the project and select the scheme for your #{projectname} target and select the “iPhone 6.0 Simulator” as your runtime. Make sure that the output pane is visible as seen in the screenshot below. You’ll notice now that the logging filter is no longer valid for running the project in this mode (both “hi @debug” and “hi @trace” are no longer omitted).

Now that we’ve demonstrated running in Xcode for the simulator, lets next move onto running on the device from Xcode. Before you can run your application on your device via Xcode, we have to enable the device for development. Attach your device via the USB connection, then open Xcode and goto the orangizer under “Window” > “Organizer” and select your device and click “Use for Development”.

This will install the Xcode development tools on the device. Now, in the organizer you can have access to:

  • provisioning profiles
  • applications – to remove then as you wish
  • screenshots – to capture assets directly for the appstore, etc
  • console – key for viewing logs on an application that is already installed on a device

For Android, the tooling is broken down into 3 major tools:

  • ddms: “Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS), which provides port-forwarding services, screen capture on the device, thread and heap information on the device, logcat, process, and radio state information, incoming call and SMS spoofing, location data spoofing, and more.”
  • adb: “Android Debug Bridge (adb) is a versatile command line tool that lets you communicate with an emulator instance or connected Android-powered device.”. From it you can undeploy/deploy apps, get shell access to the device. run logcat
  • android sdk manager: used for installing android components as well as for the AVD (Android Virtual Device) manager. commonly used for launching emulator profiles

Lets focus on logging with ddms

    • start your application via Titanium Studio
    • make sure that $ANDROID_HOME/tools is on your path
    • start ddms
1
2
3
4
5
$ which ddms
/opt/android-sdk/tools/ddms
$ ddms
2012-10-29 16:48:57.427 java[18251:f0b] [Java CocoaComponent compatibility mode]: Enabled
2012-10-29 16:48:57.428 java[18251:f0b] [Java CocoaComponent compatibility mode]: Setting timeout for SWT to 0.100000

In the screenshot below, we see the logs for the simulator instance “titanium_7_HVGA” which is currently running. DDMS is great for tailing logs and give you the ability to clear, filter based on level or string search as well as save to file and select the appropriate application/process that is running.

Now that we’ve used ddms, lets take a look at building an apk and deploying it to our connected device. First lets generate the keystore which we will save to a file named pragmaticskills.keystore.

1
keytool -genkey -alias pragmaticskills -storepass pragmaticskills123 -keypass pragmaticskills123 -keystore pragmaticskills.keystore -dname "cn=Andrew Zuercher, ou=Development, o=eHire Labs, c=US" -validity 10000

Now, publish your app in Titanium via the menu: “Publish” > “Distribute – Android App Store” and fill in the keystore location, password and alias.

If you look at the very first lines that are printed to the console when the apk is created, you’ll see a commandline call to the Titanium scripts.

If you want, you can copy this command and create a script with it to automate this task:

1
/Users/azuercher/Library/Application\ Support/Titanium/mobilesdk/osx/2.1.3.GA/android/builder.py distribute pragmatics_skills /opt/android-sdk /Users/azuercher/workspace/pragmatics_skills com.ehirelabs.pragmaticskills /Users/azuercher/workspace/pragmatics_skills/pragmaticskills.keystore pragmaticskills123 pragmaticskills /Users/azuercher/workspace/pragmatics_skills 7

Before we can even see our device as an available device, we need to enable it for development. On the device, goto your home menu, then “Settings” and click “Applications” enable “Unknown Sources” and “USB debugging”.

We can now use adb to help us with deploying and undeploying the application. First lets start off by listing the current devices.

1
2
3
4
$ adb devices
List of devices attached
emulator-5560 device
3135C2A58BE600EC device

As you can see I currenty have both the simulator running and a connected hardware device. I suggest that you only keep one connected at a time, so lets go ahead and kill the simulator. To install the app, just provide the location of the apk.

1
2
3
4
$ adb install pragmatics_skills.apk
3964 KB/s (5943789 bytes in 1.463s)
pkg: /data/local/tmp/pragmatics_skills.apk
Success

Note that if you wanted to do an update instead of an install, you can use the -r option.

1
$ adb install -r pragmatics_skills.apk

I rarely do an update, instead I remove the app to ensure that I’m working with the application from scratch. To uninstall the app use your appid (android packagename):

1
2
$ adb uninstall com.ehirelabs.pragmaticskills
Success

As I just mentioned, I typically do both the uninstall and then the install. To see all of this come together in one script, lets consider the following which does a clean, builds the signed apk and then uninstalls from the device and installs the apk. Using a script like this will save you quite a bit of time clicking through the UI.

1
2
3
4
5
6
rm -rf build/android/**
 
/Users/azuercher/Library/Application\ Support/Titanium/mobilesdk/osx/2.1.3.GA/android/builder.py distribute pragmatics_skills /opt/android-sdk /Users/azuercher/workspace/pragmatics_skills com.ehirelabs.pragmaticskills /Users/azuercher/workspace/pragmatics_skills/pragmaticskills.keystore pragmaticskills123 pragmaticskills /Users/azuercher/workspace/pragmatics_skills 7
 
adb uninstall com.ehirelabs.pragmaticskills
adb install pragmatics_skills.apk

We can use the android platform tools to launch our application on a ton of different simulator images. To do so, we’ll make use of both adb and the android sdk manager. Start the android sdk manager:

1
$ android

goto “Tools” > “Manage AVDS….”

You can now create a new image or start an existing image. Select the image you want to launch and then click the “Start…” button on the right. To deploy to the custom image, build your apk and then run the adb commands to deploy and undeploy to the simulator.

In most Titanium applications that I write, I also include a custom logger. One reason may seem obvious now – it will allow me to control the logging level regardless of whether I run via Titanium Studio or using the native tools themselves. A little less obvious reason is for distribution. Typically I develop with logs at DEBUG level and then move to INFO level when I create a distribution for testing or to submit to the marketplace. Having this isolated in one place makes doing this very easy.

For this example, please see the pragmatics_skills github repository. The example is in Resources/logs.js and is uses the commonJS approach.

As we can see in the usage snippet below, we require the log and then set the level for it (I’d suggest doing this in app.js or some entry point in your code).

1
2
3
4
5
6
7
8
var logger = require('log').logger;
logger.level = logger.INFO;
Ti.API.info('Log is '+logger.getLevel());
 
logger.warn("log @warn");
logger.info("log @info");
logger.debug("log @debug");
logger.trace("log @trace");

As you can see the behavior is as intended (both “hi @debug” and “hi @trace” are omitted):

1
2
3
[INFO] Log is info
[WARN] log @warn
[INFO] log @info

We’ve covered a bit of technologies in this post which hopefully have been useful to you and helped arm you with some tactics that otherwise would not have had exposure to. As a recap, we covered:

  • running Titanium based iOS apps through Xcode (simulator and device)
  • building Titanium commandline based on the Titanium Studio console output
  • launching specific Android emulators via the android avd manager
  • deploying to Android emulators and devices via adb
  • viewing Android logs via ddms
  • the justification for and the implementation of a custom logger

Hopefully with this you can now take advantage of the platform tools, work more effectively and reduce development cycles while troubleshooting your application better in the simulator and on the device with logging.