Solving Appcelerator Studio’s “Invalid Request” when Compiling

I use Titanium for many of my projects and have found it a great framework. Just like with any tools every once and awhile you run into some interesting errors. I am often switching networks and every once and awhile I get the below error in the Appcelerator Studio console window.

[INFO] :   Alloy compiled in 9.88357s
[INFO] :   Alloy compiler completed successfully
[TRACE] :  offline build file ...
[TRACE] :  online 1
[TRACE] :  sending request ...
[TRACE] :  result from /build-verify=> {"success":false,"error":"invalid request","code":"com.appcelerator.security.invalid.session"}, err=null
[ERROR] :  invalid request

This is an interesting warning as it means the Appcelerator CLI no longer has valid session information.  Great for security, but can be confusing as the error is not resolved by logging in and out of Appcelerator Studio.

This is easily resolved by the following:

  1. Open terminal
  2. Type appc logout, this will logout the Appcelerator CLI
  3. Type appc login, then enter your Appcelerator credentials

If you are using the CLI most likely will never see the above but for those of us that like to use Appcelerator Studio might find this little trick helpful.

Android orientation locking for Titanium

Locking the orientation of a Titanium Android app if fairly straightforward after you’ve done it once or twice.  I thought it would be helpful to outline the steps that I follow to lock several of my applications in a portrait orientation.

To start with you first must build your Titanium Android app.  It doesn’t matter if you have any functionality in your project yet.  You just need to make sure an AndroidManifest.xml file is created in your project’s build/android folder.  Once you have done a build, you will need to open your AndroidManifest.xml and look for the android:name property of your launch activity.  You can see an example of this in the below snippet found in our AndroidTest AndroidManifest.xml. Look for the .AndroidtestActivity line.  This is the line and pattern you will want to look for in your project’s AndroidManifest.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
	<application android:icon="@drawable/appicon" 
           android:label="AndroidTest" 
           android:name="AndroidtestApplication" 
           android:debuggable="false" 
           android:theme="@style/Theme.AppCompat">
		<activity 
                 android:name=".AndroidtestActivity" 
                 android:label="@string/app_name" 
                 android:theme="@style/Theme.Titanium"       
                 android:configChanges="keyboardHidden|orientation|screenSize">
		   <intent-filter>
		     <action android:name="android.intent.action.MAIN"/>
		     <category android:name="android.intent.category.LAUNCHER"/>
		    </intent-filter>
		</activity>
	</application>
</manifest>

You can see the naming convention is a period then your project name with the first letter capitalized followed by Activity.  In our example project this is .AndroidtestActivity. This is the pattern you will want to look for in your AndroidManifest.xml.

Once you have the activity name of your launch activity you will want to replace the default Android configuration with a new template.

First open your project’s tiapp.xml and locate the below default Android entry.

<android xmlns:android="http://schemas.android.com/apk/res/android"/>

Replace the default information with the below template.

    <android xmlns:android="http://schemas.android.com/apk/res/android">
        <manifest>
            <application>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:screenOrientation="portrait"
                    android:name="[replace me]">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:name="org.appcelerator.titanium.TiActivity" 
                    android:screenOrientation="portrait"/>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:name="org.appcelerator.titanium.TiTranslucentActivity"
                    android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Translucent"/>
            </application>
        </manifest>
    </android>

Next replace the [replace me] placeholder with the name of the launch activity you found earlier.  The below example shows this replacement being done for our AndroidTest app.  Please remember to remove the brackets when making the replacement.

    <android xmlns:android="http://schemas.android.com/apk/res/android">
        <manifest>
            <application>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:screenOrientation="portrait"
                    android:name=".AndroidtestActivity">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN"/>
                        <category android:name="android.intent.category.LAUNCHER"/>
                    </intent-filter>
                </activity>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:name="org.appcelerator.titanium.TiActivity" 
                    android:screenOrientation="portrait"/>
                <activity
                    android:configChanges="keyboardHidden|orientation|screenSize"
                    android:name="org.appcelerator.titanium.TiTranslucentActivity"
                    android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Translucent"/>
            </application>
        </manifest>
    </android>

Next you will need to tell Alloy to only create Windows with a portrait orientation.  This is super easy and can be done by adding one class to your app.tss as shown below.  Your app.tss can be located in your app/styles folder.  If your project doesn’t already contain an app.tss you can create one by simply creating a file called app.tss in your project’s style folder.  To learn more about global styles please read the documentation available here.  The following snippet creates a global style for the windows in your project setting the orientation to portrait.

"Window" : {
	orientationModes :[
		Ti.UI.PORTRAIT
	]
}
FAQ:
  • Q: Why lock at the Android Activity level, isn’t adding the Alloy style enough?
  • A: Unfortunately no. The Alloy style is applied after the window is created. So if the device is held in a landscape orientation you will see the window open and turn. Locking at the Android Activity level stops this behavior.
  • Q: Does this mean all of my Ti.UI.Window object will be locked in portrait?
  • A: Yes, this locks both at the Android Activity and Titanium object levels.
  • Q: Can I later change the orientation by updating my Ti.UI.Window orientation?
  • A: No, orientation is locked at the Android Activity level as well.

Settings Dialogs with Titanium

The handling for prompts for network, location, and other settings is fairly common when building apps.  I think we have all written code that verifies a network connection and then prompts the user to check their network settings.

For a recent project I encapsulated a network and location prompt into a CommonJS model called SettingsDialog.  This is just a light wrapper around Ti.UI.AlertDialog.  You can find the module here along with a sample app.js.

Network Example

Many of my apps deal with travel, so I end up dealing with network issues more than I would like.  Once a network issue has been identified you might have to alert the user that a feature is unavailable to them do to their network conditions.  The following example shows how to use the module to create a cross platform dialog with a network settings button.  When clicked on Android this will take the user directly to their Network Settings and on iOS will take them directly to their Application Settings.

The below is an example how to create a cross platform network dialog as shown below. When the user taps on the Settings button, they are taken to the device’s settings screen.  On iOS you are taken to the App’s Settings and on Android you are taken directly to the Network Settings screen.

Code:


//Before we get started, require the module into our project
var alertSettings = require("settings-dialogs");
	alertSettings.prompt({
		title:"Information", 
		message:"We can't find a network connection. Please check your settings.",
		buttonNames:["Settings", "Continue"],
		settingsType : alertSettings.SETTINGS_TYPE.NETWORK, //The type of prompt 
		settingsIndex : 0 //What button index should launch the settings
	}, function(d){
		console.log("prompt results = " + JSON.stringify(d));
	});

UI Example:

ios_network android_network

Location Example

With greater permissions being applied to both iOS and Android likely will need to handle the scenario where the user might change location permissions needed for a feature.  You can use the SettingsDialog module to create a prompt asking them to enable Location Services and providing a Settings button to jump them to the Settings screen to make the change.  The below example illustrates how to use the module to create cross platform location dialogs.

Code:


//Before we get started, require the module into our project
var alertSettings = require("settings-dialogs");
	alertSettings.prompt({
		title:"Information", 
		message:"Please enable location services to use this feature.",
		buttonNames:["Settings", "Continue"],
		settingsType : alertSettings.SETTINGS_TYPE.LOCATION_SERVICES, //The type of prompt 
		settingsIndex : 0 //What button index should launch the settings
	}, function(d){
		console.log("prompt results = " + JSON.stringify(d));
	});

UI Example:

ios_locationandroid_network

A full gist is available here.

Adding a center button on your iOS Ti.UI.TabGroup

Remember the original “big center button” of the Instagram app?  Although this design language isn’t cutting edge anymore it still can be useful for a class of apps.  In this post we will explore how through a few lines of code you can create a center action button using the Titanium Alloy framework by Appcelerator.

View Code

To get started, first you need to create a Ti.UI.TabGroup with five Ti.UI.Tab’s.  You might notice that only four of the five Ti.UI.Tab’s are visible, but the hidden Ti.UI.Tab is needed to maintain spacing.  In the below snippet I’ve named and labeled each tab by number.  In our case, the third Ti.UI.Tab is the place-holder.

<Alloy>
	<TabGroup id="tbgroup">
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 1">
				<Label>I am Window 1</Label>
			</Window>
		</Tab>
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 2">
				<Label>I am Window 2</Label>
			</Window>
		</Tab>
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 3">
				<Label>I am Window 3</Label>
			</Window>
		</Tab>		
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 4">
				<Label>I am Window 4</Label>
			</Window>
		</Tab>	
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 5">
				<Label>I am Window 5</Label>
			</Window>
		</Tab>			
	</TabGroup>
</Alloy>


Controller Code

Next alittle controller magic is needed.  Since Alloy does not allow for a Ti.UI.Button to be added to a Ti.UI.TabGroup in our view xml we need to do this programmatically in the controller.  The following snippet shows how a Ti.UI.Button named btnAction is created then added to the Ti.UI.TabGroup

var btnAction = Ti.UI.createButton({
	title:"I'm a button",
	backgroundColor:"#e7e7e8",
	width:85, height:55, bottom:0, borderColor:"#999"
});
 
$.tbgroup.add(btnAction);
$.tbgroup.open();

Since no position is provided, Titanium will automatically center the btnAction control within the boundary of the Ti.UI.TabGroup it is attached.  You just need to make sure the Ti.UI.Button you are attaching is larger then the Ti.UI.Tab place-holder in order to avoid incorrect touch events from firing.

What will we end up with?

The combination of the view and controller code creates the following screen with an oversized center action button.  Since these are just Titanium UI components you can style them and use event listeners as needed.

center-button-tabgroup

Event Sharing between Titanium, iOS Extensions, and the Apple Watch

JavaScript style events are one of the features I miss most when building native applications.  The fact that Titanium allows for this on mobile is one of things I enjoy most about the platform.  When Appcelerator introduced the ability to create native extensions in version 3.5.x, I began to explore how to pass information through between native iOS extensions and a Titanium application.

In the native world, Mutual Mobile solved this with their MMWormhole project.  MMWormhole uses the Darwin Notifications and your application’s shared directory to pass messages between your app and your extensions.  This seemed exactly what was needed to create events between your Titanium app and extension (or Watch Apps).

After some experimentation and hacking, a Titanium friendly version of MMWormhole called Ti.Wormhole as created.  This allows for events to be published/subscribed between native extensions and your Titanium app.  This is done through a native Wormhole client that you add to your native extension communicating with a native Titanium module installed within your app.

Ti.Wormhole in Action

The following video shows a quick walk through of the Ti.Wormhole running in the iOS simulator.

Before you get started

Before you get started, this development approach requires you program largely in native ( Objective-C or Swift ).  So if you are not comfortable in Xcode, you might want to explore another alternative.  Next, you will need a nightly build of Titanium 3.5.x or greater.

How does it work?

The mechanics are of Ti.Wormhole are straightforward.  Messages are passed from MMWormhole in your Titanium app using a native module to your native extension.  In your native extension another version of MMWormhole  receives your messages providing you the information passed from your Titanium app.  All Ti.Wormhole really does it make MMWormhole work nicely with Titanium.

overview

Native Extension to Titanium

The process of sending events from your native extension to Titanium is relatively straightforward.  First you need to create your native extension… and yes you do this completely native without any JavaScript or Titanium helpers.  Next add the MMWormholeClient classes to your project.  These will give you all of the helpers you need to talk to your Titanium app.  Next you add the Ti.Wormhole module to your Titanium project. This enables your Titanium project to end/receive notifications.

Native to Titanium

Your native extension will publish notifications that will later be turned into Titanium JavaScript events.  The following diagram illustrates the end to end process for doing so.

native-to-ti

A diagram is great but how does this actually work?  Well… to broadcast events from your extension to a Titanium app the first thing you need to do is to create an instance of the MMWormholeClient class.  This class is one half of the bridge you need between your Titanium app and extension.  The below shows how to create this class in both Objective-C and Swift.  The key thing to remember, is the GroupIdentifier and Directory need to match the parameters use by the Titanium module. Otherwise your messages will not be received.

Objective-C Example:

objc-init

Swift Example:

swift-init

Next your native extension needs to send a notification. This is done using the passMessageObject function of the MMWormholeClient class.  The important thing to remember here is that the identifier provided, needs to be the same as the event you are listening to in your Titanium app.  In the below example we are broadcasting to an event named wormEvent.

Objective-C Example:

objc-post

Swift Example:

swift-post

That is all we need to do from our native extension, the rest will be done in our Titanium app.

The first thing we need to do in our Titanium app is to require an instance of the Ti.Wormhole module.


var wormhole = require('ti.wormhole');

Next we use the start method to configure the module to interact with the MMWormholeClient class in our native extension.  The key thing to remember here is that the suiteName and directory need to match the parameters used to create the MMWormholeClient class instance in your extension.

wormhole.start({
      suiteName:"Your suite identifier",
      directory:"Your message directory"
});

Finally, you just need to use the addWormhole method to create an event listener.  This will listen for a specific event and generate a callback when it is triggered.

wormhole.addWormhole("wormEvent",function(e){
    console.log("Event in ti app: " + JSON.stringify(e));
});

Titanium to Native

It is just as easy to go from Titanium to Native.  The following diagrams the end to end process that is used in sending messages from Titanium to your native extension.

ti-to-native

I know what you are thinking, another diagram great, show me the code.  To save time we will skip over the requiring the Ti.Wormhole module and calling Start method. This would be the same as the Native to Titanium example.

The first step is to send a message from Titanium using the Ti.Wormhole module’s post method as shown below.  Since you will want to background your app and access notification center, you might want to use setTimeout to give yourself a few seconds.

setTimeout(function(){
     wormhole.post("wormEvent",{displayNumber:displayCount});
},10000);

By calling post, a message is placed into the notification queue to be picked up by your native extension.  To receive these notifications you need to add a listener in your native extension as shown in the following Objective-C and Swift examples.

Objective-C Example:

objc-listen

Swift Example:

swift-listen

Examples

The Ti.Wormhole project has examples written in both Objective-C and Swift.  You can see video overview of the project here.  Everything else is at https://github.com/benbahrenburg/Ti.Wormhole.

Using iOS Visit Events in Titanium

It seems every app has its own way to handle Geo Location.  In many of my cases, your destination is more important then your journey. In iOS 8 Apple provides the CLVisit API specifically designed to provide this type of functionality.  Events are generated when you arrive to a location, and another is generated when you leave.  This provides a very battery friendly approach to solving place based Geo Location problems.

So how do you use this in Titanium?  Like almost any other Titanium requirement you run into there is a module already available.  You can download the Ti.GeoVisits module to use this functionality today.  I used the example app.js for a week and found that the Visit event fired reliably after I was in a single location for more then 10 minutes and about 5 minutes after leaving a location.  This wait time does cause for quick stops such as picking up take away to be missed.  Although this approach has trade offs, it virtually has no impact on battery life.

Below is a record of my tests over the last 9 days.  I’d encourage you to try the same test yourself.  As simulator testing isn’t really a meaningful option for Geo Location apps, I would suggest installing the example app.js and heading out to do a few errands.

Results for the last 9 days:

IMG_0214

What does the Ti.GeoVisits API look like?

The full Ti.GeoVisits API is very small consisting of only three methods and four events.  The below snippet summaries all of these.  For full documentation please visit here for details.

var visits = require('ti.geovisits');
//Fired when Ti.GeoVisits starts
visits.addEventListener('started',function(e){});
//Fired when Ti.GeoVisits stops
visits.addEventListener('stopped',function(e){});
//Fired when Ti.GeoVisits errors
visits.addEventListener('errored',function(e){});
//Fired when Ti.GeoVisits registers a place visited or left
visits.addEventListener('visited',function(e){});

//Boolean indicating if module supported
visits.isSupported()

//Method used to start monitoring for visits
visits.startMonitoring();

//Method used to stop monitoring visits
visits.stopMonitoring();

Learn more about Ti.GeoVisits on Github at https://github.com/benbahrenburg/Ti.GeoVisits.

You can also download the module GitTio at http://gitt.io/component/ti.geovisits

Titanium Charting with JBChartView

How to use Charts on mobile is one of those areas where everyone has an opinion.  Usually these approaches boil down to the use of a WebView or taking a dependency on a 3rd party native framework.

Usually I recommend using a WebView as the web charting tools tend to provide a greater level of functionality. But recently I discovered JBChartView by Jawbone which changed my mind.  JBChartView  provides charting functionality I typically use bundled in an easy to use native iOS (sorry not android version) project.

To make JBChartView consumable by Titanium I’ve wrapped the project into a module, Ti.JBChart , and created Titanium specific documentation and examples.  The below animated gif shows the Ti.JBChart examples in action.

In Action

An example

The Ti.JBChart  github project has examples for Bar, Line, and Area charts.   The following snippet shows an example on how to use the LineChartView in your Titanium project.

    function createData(){
        var result =[];
        function createRandom(min,max){
            return Math.floor(Math.random()*(max-min+1)+min);
        }   
        for (var iLoop=0;iLoop<12;iLoop++){
            result.push(createRandom(1,12));
        }
        return result;
    }

    var data = [];
    //Add first line chart
    data.push(createData());
    //Add second line chart
    data.push(createData());

    var myStyles = [];
    //Create the first line chart with a solid  line
    myStyles.push(chart.CHART_LINE_SOLID);
    //Create the second line chart as a with a dashed line
    myStyles.push(chart.CHART_LINE_DASHED);

    var lineChart = chart.createLineChartView({
        width:Ti.UI.FILL, height:250, 
        data : data,
        toolTipData : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
        selectedLineColors :['yellow','orange'],
        lineColors:['green','blue'],
        styles : myStyles,
        selectionBarColor:'purple',
        chartBackgroundColor:'#404041'
    });

Looking for more?