Using Circle Layouts in your Titanium MapView

In my last post, I outlined how you can add Polygon support to your Titanium MapView.  Continuing with this topic, I have added Circle Overlay support (MKCircle) to the Titanium MapView module.

To avoid any namespace collisions I forked the native Titanium MapView implementation and create the benCoding.Map module.

To show how this works, I’ve create a demonstration showing all of the worlds nuclear power plants with a circle showing a 10 and 50 mile radius.

Link: http://www.youtube.com/watch?v=jwnByWz1eJo

Please visit github for the compiled module, documentation, and sample apps. The project can be found at https://github.com/benbahrenburg/benCoding.Map

The Polygon and Circle example apps are included in the modules example folder or on github here.

Hopefully these examples will be useful for anyone working with GIS functions in Titanium.

Using Polygons in your Ti.Map.View

For a recent project, I needed to add Polygon support to Titanium’s MapView.  To avoid any namespace collisions I forked the native Titanium MapView implementation and create the benCoding.Map module.

To show how this works, I’ve put together a sample showing Polygon’s for all of the US States, and a country level Polygon for the United Kingdom.

Link: http://www.youtube.com/watch?v=1rudu6S9-rc

For the compiled module and associated code please visible https://github.com/benbahrenburg/benCoding.Map

The demo project shown in the video is included in the module’s example folder.

Hopefully these examples will be useful for anyone working with GIS functions in Titanium.

Using Local Notifications in Titanium

A recent Titanium project called for the use of Local Notifications.  I wanted to share my experience implementing this feature in hopes it will help others.

Tips / Questions

1. Tips on using Ti.App.iOS.scheduleLocalNotification

The current (version 2.0.2 ) implementation of the Ti.App.scheduleLocalNotification API requires that you call this method as part of a background service.  Keep in mind, this might change in future versions so please test your scenario on the current version of the framework.

Most problems with scheduling local notifications can be solved by moving your scheduling actions to a background service.  The below shows how the KitchenSink sample app performs this task.

First we need to register the background service in app.js. This will create the service once the app is based into the background.

    // register a background service. this JS will run when the app is backgrounded
    var service = Ti.App.iOS.registerBackgroundService({url:'bg.js'});

Second we create the notification in the bg.js


  var notification = 	Ti.App.iOS.scheduleLocalNotification({
	alertBody:"Kitchen Sink was put in background",
	alertAction:"Re-Launch!",
	userInfo:{"hello":"world"},
	sound:"pop.caf",
	date:new Date(new Date().getTime() + 3000) // 3 seconds after backgrounding
  });

Please visit this great QA Forum thread to learn more about different strategies to implement Ti.App.scheduleLocalNotification.

2. How do I cancel an individual notification?

It is my understanding there is currently two ways to do this:

  • You can call cancel on the notification after you create a notification.  See below for an example show how to implement this approach as demonstrated in the KitchenSink sample app.

Notification example from bg.js


  var notification = 	Ti.App.iOS.scheduleLocalNotification({
	alertBody:"Kitchen Sink was put in background",
	alertAction:"Re-Launch!",
	userInfo:{"hello":"world"},
	sound:"pop.caf",
	date:new Date(new Date().getTime() + 3000) // 3 seconds after backgrounding
  });

  // we cancel our notification if we don't want it to continue
  notification.cancel();

  • I believe you can use Ti.App.iOS.cancelLocalNotification to cancel a notification using a convention.  If when you created your notification you set the userInfo.id property to a unique integer value you can then pass this integer into the Ti.App.iOS.cancelLocalNotification method to cancel your notification.  This approach seems to work under some use cases but not others.  I would recommend testing on device to make sure it fits your app’s workflow.

Modify the bg.js example to add id to the userInfo object.


  //Create the notification
  var notification = 	Ti.App.iOS.scheduleLocalNotification({
	alertBody:"Kitchen Sink was put in background",
	alertAction:"Re-Launch!",
	userInfo:{"id":4, "hello":"world"},
	sound:"pop.caf",
	date:new Date(new Date().getTime() + 3000) // 3 seconds after backgrounding
  });

  //Cancel the notification using the id passed in as part of the userInfo object
  Ti.App.iOS.cancelLocalNotification(4);

3. How do I cancel all of my my Scheduled Notifications?

To cancel all of your notification you simply need to call the Ti.App.iOS.cancelAllLocalNotifications() method.  This will cancel all scheduled notifications linked to your app.


    // Cancel all notifications linked to your app
    Ti.App.iOS.cancelAllLocalNotifications();

4. How do I list my Scheduled Notifications?

Currently Titanium does not support querying scheduled notifications.  I discuss this more in how I implemented by solution below.

My implementation

Titanium is open source and extendable, making it easy to understand the platform’s current implementation and quickly add functionality.  For this project I needed to implement a custom workflow around local notifications that allowed users to schedule and managed their own notifications through a “dashboard”.

To assist with that I created a custom module that allows you to extend or replace the extending Titanium creation and cancellation methods.

  1. ScheduleLocalNotification – Same as the native Titanium but without the return object and you are able to call without a background service.
  2. activeScheduledNotifications  – Provides a callback with a list of your scheduled local notifications.
  3. returnScheduledNotifications – Provides the same collection of scheduled local notifications as the activeScheduledNotifications but directly without the callback.
  4. cancelLocalNotification – Takes an id and loops through canceling any scheduled local notification with a userInfo.id property that matches. A value is returned with the number of notifications that were scheduled.
  5. cancelAllLocalNotifications – Works the exact same way as the native method.

If you are interested in learning more about the benCoding.localNotify module please visit the project on Github here.

Using Titanium’s Transport.py

The Titanium Mobile SDK comes with the powerful transport.py script that allows you to generate stand alone XCode projects for your existing Titanium Mobile Projects.

The transport.py script allows you to share your XCode project with clients, third parties, or others that do not have the Titanium SDK installed.  You can also use this process to simply the App Store, Ad Hoc, and other processes by directly using Apple’s tools.

I use the transport.py process for all of my release compiles.  Below is the process that I follow when using this script.

Before We Get Started

For this example I’m going to use the Titanium SDK version 1.8.2 to create an XCode project for bARk.  You can download bARk from github if you want to follow along.

Verifying Your Titanium Project

Before running the transport.py script I recommend verifying a few things in your Titanium Project.

  1. Open Titanium Studio and go to your project
  2. When in your project open your tiapp.xml file and confirm the SDK Version is set to the correct version.  In this case we are using 1.8.2. as shown below.
    Verify Titanium SDK Version
  3. After confirming the SDK version we next need to make sure the project has been cleaned. This will ensure that the transport.py script performs a full build of your project.
  4. To clean your project click on the Project option in your toolbar then select Clean…
  5. This will open the below dialog box.  Select to either clean all projects or select the one you want to run transport.py against.  In the below example I’ve selected to only Clean the bARk project.
    Clean Project
  6. After your project has been cleaned, open Finder and go to your <Project>/build/iphone directory and confirm that it is empty.  This is important as the transport.py will create it’s files here.
    Confirm Directory Is Empty
  7. You can now close Titanium Studio and move onto running the transport.py script as outlined in the next section.

Running The Transport.py Script

The transport.py is a Python script located in your ~/Library/Application Support/Titanium/mobilesdk/osx/<SDK Version>/iphone directory.  This file is available with each release of Titanium so to use a later version update navigate to the correct directory.

For this example we’re using the path ~/Library/Application Support/Titanium/mobilesdk/osx/1.8.2/iphone

To run this script please follow the below steps.

  1. Open terminal and navigate to your ~/Library/Application Support/Titanium/mobilesdk/osx/1.8.2/iphone directory
  2. Issue the following command  ./transport.py <path to your project directory>  in my case that is ./transport.py /Users/benjamin/Dev/Projects/Ti/Demos/bARk/
    Transport.py Path Example
  3. You will now is the project building, the output should look like the below.
    transport.py console output
  4. Once the build has completed you will see a message saying “Finished! Share and Enjoy.”
    transport.py finished message
  5. Transport.py has now generated a stand alone XCode project for you in your Titanium Project’s build/iphone directory.
  6. Open Finder and navigate back to your <Project>/build/iphone directory that we cleaned in the “Verify Your Titanium Project” section.

Moving The Build Directory

Since Titanium often re-generates your project’s build directory I recommend moving the <Project>/build/iphone folder to another location before opening it in XCode.  This ensures the project wont be deleted by mistake.

XCode Project Updates

You now can work with your application using XCode directly.  Simply click on the .xcodeproj file in your output directory.

The below are a few configuration updates I typically make in XCode before creating a build. 

Remove Unwanted Targets

The transport.py script generates iPhone, iPad, and Universal targets when running.  It is recommended that you remove any targets you do not need.

Project Targets

To remove a target, simply select the target and press delete. You will be presented with a confirmation box such as the one below.

Press delete to remove the target from your project

Deleting a project target

Since bARk is only an iPhone app, I’ve removed all other targets just leaving the below.

iPhone Target

Verify Icon’s and Splash Screen Configuration

You will want to confirm that your app icons and splash screens are correctly associated with your project.

If you select your target ( in my case bARk) then press the Summary tab at the top you will see all of your icons. You can see in the below sample that we need to set both of our app icons and associate our retina splash image.

Target Icons

To add an icon you need to right mouse click ( control + shift + click ) on the different image boxes. 

Select Image

This will allow you to select an image using the Finder. To select your icons and splash images you want to navigate to the Resources/iphone directory in your build output folder.  The below shows an example of the path.

Image Finder

You will want to perform the above steps for any missing images.  When completed the Summary tab for your target should look like the below.

All images added 

Add or Remove Icon Gloss Effect

For some apps you will want to remove the prerendered-icon ( or gloss effect) on the icon.

By default this effect is enabled.  To remove this effect select your target, then go to the Info tab. Under the “Custom iOS Target Properties” section you will see a configuration entry called “Icon already includes gloss effects”. Toggle this effect to NO to remove the gloss effect.

See the below screenshot for an example.

Default Gloss Effect

In iOS 5 Apple introduced an additional property to control the icon gloss effect.  You can update this configuration by selecting your target, then go to the Info tab. Under the “Custom iOS Target Properties” section you want to expand the “Icon files (iOS 5) property and under the “Primary Icon” option you will see an option called “Icon already includes gloss effects”. Toggle this effect to NO to remove the gloss effect.

See the below screenshot for an example.

Icon Gloss Effect iOS5

Adding Icon to your URL Types

You have the ability to set custom URL Types.  By default you have a main URL Type for your application. 

To add an icon, select your target then press the Info tab at the top of your screen.  Then scroll to the end of screen to a section labeled URL Types. To add an icon, click on the icon dropdown box as shown below.

Adding a URL Icon

The dropdown will list all of the icons associated with your project.  Select the icon you want to use and it will populate the URL icon preview box as shown below.

URL Icon Added

What’s Next?

You now have a full stand alone XCode project. 

This can be helpful when performing the following:

  • Sending to a client or third party for signing and App Store Submission
  • Creating Ad Hoc distributions
  • Submitting to the App Store with non Titanium defaults
  • Pushing to device using the native Apple tools.

Watch The Video

Below is a video walk through of the above.

Titanium Stepper Module

Want to use the iOS UIStepper in your Titanium App?

stepper115 Use the native iOS UIStepper in your Titanium application. This module provides Titanium accessibility to Apple’s native UIStepper introduced in iOS5.

See the below on how to get started using this in your Titanium apps today.

Want To Download The Module?

You can download the compile module here.  Please take a look at the “Before You Start” section to make sure you have all of the module dependencies.

Interested In The Source?

The source is available in the benCoding.Stepper repo on GitHub.

Before You  Start

  • You need Titanium 1.8.1 or greater
  • This module will only work with iOS 5 or great.

How Does It Work?

This module provides Titanium access to the native Apple UIStepper controller.  The module’s API has been fashioned after the Titanium slider to make it familiar to use.

What Does It Look Like?

See is a quick video showing the module in action.

Documentation & Examples

For the example app shown above and full html documentation please check out the documentation and example folders in the module zip.

How Do I Use It?

//First we bring in the module using the require syntax
var stepper = require('bencoding.stepper');

//We now create our stepper control
//The stepper is added to any view, window, etc just like any other Titanium control
var myStepper = stepper.createStepper({
    min:10, //Minimum stepper value
    max:200,//Maximum stepper value
    value:25, //Initial or starting value of the stepper
    continuous:true //increment on value ( or stepvalue ) for each touch event
});

//We listen for the change event.
myStepper.addEventListener('change',function(e){
Ti.API.info('e.value: ' + e.value + ' myStepper.value=' + myStepper.value);
});

Titanium SMS Module

Need a SMS Dialog in your Titanium app?

The benCoding.SMS module makes it easy to add SMS functionality into your iOS Titanium apps. We unleash the power of Apple’s native Apple SMS component to Titanium with an API fashioned after the Titanium EmailDialog to make it familiar to use. 

See the below on how to get started using this in your Titanium apps today.

Want To Download The Module?

You can download the compile module here.  Please take a look at the “Before You Start” section to make sure you have all of the module dependencies.

Interested In The Source?

The source is available in the benCoding.SMS repo on GitHub.

Before You  Start

  • You need Titanium 1.8.1 or greater
  • This module will only work with iOS 4 or great.

How Does It Work?

This module provides Titanium access to the native Apple SMS component MFMessageComposeViewController.  The module’s API has been fashioned after the Titanium EmailDialog to make it familiar to use.

What Does It Look Like?

 Example AppDialog Sample  Completed Event 

Documentation & Examples

For the example app shown above and full html documentation please check out the documentation and example folders in the module zip.

How Do I Use It?

//Create SMSDialog object
var sms = require('bencoding.sms').createSMSDialog({ barColor:'#336699' });

Ti.API.info("Is This Feature Supported? => " + sms.canSendText);
//This is an example of how to check if the device can send Text Messages
if(!sms.canSendText){
	var noSupport = Ti.UI.createAlertDialog({
			title:'Not Supported',
			message:"This device doesn't support sending text messages" 
	}).show();

	return;

}else{

	//Set the SMS message, you can also do this when you create the SMSDialog
	sms.setMessageBody("Appcelerator Titanium Rocks!");
	
	//Set the SMS ToRecipients you can also do this when you create the SMSDialog
	//This is an array so you can pass in several numbers for the message
	sms.setToRecipients(["555-555-1234","444-444-1234"]);
	
	//This call opens the SMS Message Dialog
	sms.open({
		animated:true //Animated on open (OPTIONAL)
	});
}

Titanium Dictionary Module

What to use the native iOS5 Dictionary in your Titanium Mobile app?

The new benCoding.Dictionary module that makes it easy to this functionality into any Titanium app that targets iOS5 or greater.

Want to download the module?

You can download the compile module here.  Please take a look at the “Before You Start” section to make sure you have all of the module dependencies.

Interested in the source?

The source is available in the benCoding-Dictionary repo on GitHub.

Before You Start

This module has a few dependencies, make sure you meet the below criteria.

  • You need to be targeting Titanium 1.8.1 or greater.
  • This module requires iOS5

How Does It Work?

The module provides a Titanium wrapper around Apple’s native UIReferenceLibraryViewController.

What Does It Look Like?

Since this is largely a UI component please find below a short video showing the example app running in the simulator.

Documentation & Examples

For the example app shown above and full html documentation please check out the documentation and example folders in the module zip.

Need A Quick Example?

Here is a quick example showing how to use the module.  To learn more please see the documentation link here and the example link here.


var referenceLibrary = require('bencoding.dictionary').createReferenceLibrary();
Ti.API.info("This feature is only supported in iOS5 and above");
Ti.API.info("Check if we have the min OS version needed");
Ti.API.info("Is Supported? => " + referenceLibrary.isSupported());
Ti.API.info("Check if Apple knows the definition for fanboy");
var hasDefinition = referenceLibrary.wordHasDefinition('fanboy');
Ti.API.info("Term has definition =>" + hasDefinition);

if(!hasDefinition){
alert('You can still call showDialog it will just display a message that no definition was found');
}else{
//If you want you can define some callbacks
function termDialogBoxHasBeenClosed(){
Ti.API.info("I'm a callback when the Definition Dialog Box has been closed.");
};
function termDialogHadError(e){
Ti.API.info("I'm a callback when an error happens this error is due to: " + e.error);
};

Ti.API.info("You can add an event to be called if there is an error");
referenceLibrary.addEventListener('errored', termDialogHadError);

Ti.API.info("You can add an event to be called when the definition dialog is closed");
referenceLibrary.addEventListener('closed', termDialogBoxHasBeenClosed);

//Open the definition dialog window
referenceLibrary.showDialog({
//This is the term to search for (REQUIRED)
term:'fanboy',
//Indicate if the dialog should be animated on open (OPTIONAL)
animated:true,
//This is the transition style (OPTIONAL)
modalTransitionStyle:Ti.UI.iPhone.MODAL_TRANSITION_STYLE_FLIP_HORIZONTAL
});
}

Adding BackgroundModes to your Titanium Project

Since the introduction of iOS 4 Apple has supported background services for the below listed specific tasks.

  • Audio – The application plays audible content to the user while in the background.
  • Location – The application keeps users informed of their location, even while running in the background.
  • VOIP – The application provides the ability for the user to make phone calls using an Internet connection.

Titanium has always supported these through the use of a custom plist.  In recent versions of Titanium allow you to manage this directly within your project’s tiapp.xml file.

To use this, simply add the backgroundModes node to your iphone configuration section.  After adding this configuration block, clean your Titanium project and run your project again.  Titanium will automatically create a new info.plist with your new backgroundModes.

 

backgroundModes

Something to consider

Please remember that Apple has very specific guidelines around these configuration options and will perform specific tests during the approval process if your info.plist has any backgroundModes keys. 

For example, if you have the audio key but do not use this feature correctly you will receive the below rejection notice for Apple.

While your app has declared support for audio in the UIBackgroundModes key in your Info.plist, no audio is played when users switch to another application. The audio background mode is meant for applications with audio streams, like radio applications. You’ll need to provide audible content to the user while the app is in the background or remove the “audio” setting from the UIBackgroundModes key.

For more details please see the Apple documentation here.

If you are interested in the Titanium implementation details, please read this Jira ticket.

Titanium: Reading Files in the Private Documents Directory

The 1.8 release of Titanium contains several iOS 5 compatibility updates.  One of the more interesting updates is the installation directory for database have changed.

In prior versions you could access the database like below:


function fetchDbFile(dbName){
    Ti.API.info('We build the directory path to find ' + dbName + '.sql');
    return Ti.Filesystem.getFile(Ti.Filesystem.applicationSupportDirectory, 'database', dbName + '.sql');
};

var myDbName = 'foo123';
Ti.API.info('We create a db to test our method')
var testDb = Ti.Database.open(myDbName);
Ti.API.info('No we get the file')
var dbFile = fetchDbFile(myDbName);
Ti.API.info('Did we find it? ' + dbFile.exists());
Ti.API.info('Here is the nativePath ' + dbFile.nativePath);
Ti.API.info('Example Finished');

With iOS 5, Apple has introduced new guidelines that have altered the database installation directory.  Databases are now installed into the Private Documents Directory.  There currently is not a property for accessing this directory in the Ti.Filesystem module.

But since the Ti.Filesystem module only proxies the url request to iOS you can reference it directly. Below is a method that demonstrations how to do this.


function privateDocumentsDirectory(){

    Ti.API.info('We need to open a file object to get our directory info');
    var testFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory);
    Ti.API.info('Now we remove the Documents folder reference');
    var privateDir = testFile.nativePath.replace('Documents/','');
    Ti.API.info('This is our base App Directory =' + privateDir);
    Ti.API.info('Now we add the Private Documents Directory');
    privateDir+='Library/Private%20Documents/';
    Ti.API.info('Our new path is ' + privateDir);
    return privateDir;
};

var myDbName = 'foo123';
Ti.API.info('We create a db to test our method')
var testDb = Ti.Database.open(myDbName);
var testNativePath = testDb.getFile().nativePath;
Ti.API.info('Our nativePath to test against is ' + testNativePath + ' this is what we need to end up with');
var privateDocFolder = privateDocumentsDirectory();
Ti.API.info('Our Private Document Folde is ' + privateDocFolder);
Ti.API.info("Let's see if we can find our database");
var dbCheck = Ti.Filesystem.getFile(privateDocFolder, myDbName+ '.sql');
Ti.API.info('Did we find it? ' + dbCheck.exists());
Ti.API.info('Do our file paths match? ' + (dbCheck.nativePath==testNativePath));
Ti.API.info('Example Finished');

To help work with your existing databases Appcelerator has added a getFile property onto the database object.  This is extremely helpful if you are performing any back-up operations yourself.  See this link to read more.

Setting Your Location in the iOS 5.0 Simulator

After upgrading my development tools to XCode 4.2 and iOS 5, I started to run into location unavailable errors when running in the iOS Simulator.

Having battled with the Android Emulator over the years, I figured there was a new location services setting I missed.

After a quick look at the iOS Simulator’s debug menu I found what I was looking for. Apple has changed the Location options for the better. You now have full control over their settings, similar to the Android emulator, just much easier.

By default the simulator will have no location defined.  Depending on your development platform this can surface in a variety of errors.  Below is the error Appcelerator’s Titanium provides.

step1

To define your location, simply open the iOS Simulator and select the Debug option, then select Location.  This has seven options:

  1. None – This will not return any location information. You can use this to test when the GPS is unavailable.
  2. Custom Location – This allows you to set a specific Latitude and Longitude.
  3. Apple Stores – Uses an Apple Store’s coordinates
  4. Apple – Apple headquarters coordinates
  5. City Bicycle Ride – Simulation of a bicycle ride in Cupertino, ie the device simulate it is moving
  6. City Run – Simulation of a run in Cupertino, ie the device simulate it is moving
  7. Freeway Drive – Simulation of a drive in Cupertino, ie the device simulate it is moving

I have a series of geo location test cases, so I tend to use the Custom Location option since it allows me to enter specific coordinates.

step2

This will open a dialog that allows you to enter your Latitude and Longitude.

step3

Press Ok, and you are ready to go.  The iOS Simulator will remember your Custom Location between restarts of the simulator.  You will need to remember to update your Latitude and Longitude when testing different scenarios or traveling. But Apple has made the process extremely straight forward.

done

The new location options in the iOS 5 simulator are a big improvement for anyone doing location based applications.