Appcelerator Developer Blog

Announcing Titanium 3.1.1 Production Release

I am pleased to announce the general availability of our latest Titanium release, version 3.1.1.  In this minor release we addressed over 125 bugs fixes and included several enhancements. For a full list of all changes and improvements in this release, please read the release notes.

Android Enhancements

  • Google Maps v2
    •  Support “userLocationButton” property
      • Allows developers to turn on/off the user location button.
    •  Support “regionchanged” event
      • Provides the delta of the latitude and longitude.
    • Support “isGooglePlayServicesAvailable”
      • Allow developers to determine if Google Play Services are available for the app
  • Camera
    • Support “savePhotoToGallery” property. Previously, photos were automatically stored in the gallery. This property gives you the control to store or not store the photos.

BlackBerry Beta

This release also includes the latest version of our BlackBerry SDK beta, with integrated Studio support for creating and running BlackBerry apps.

Changes That Require Your Attention

  • Android SDK 2.3.3
    • We have increased the minimum Android SDK support from 2.2 to 2.3.3.
  • iOS 5.x
    • We have increased the minimum supported version of iOS from 4.3.x to 5.x.
  • Change of the calendar namespace
    • If you are using the calendar in Android our namespace has changed from Titanium.Android.Calendar to Titanium.Calendar. This means that you will have to change any areas of your code referencing Titanium.Android.Calendar to Titanium.Calendar.

Downloading 3.1.1

For new users, download Titanium 3.1.1 by clicking here.

For existing Titanium Studio users, you will be prompted to update automatically on the next restart. You can also manually check for updates by selecting the “Check for Titanium SDK Updates” from the “Help” menu within Titanium Studio.

If you previously installed the Release Candidate versions of the Titanium CLI and Alloy, that is, npm install titanium@3.1.1-cr, or any -beta or -cr packages, you need to first uninstall these components before installing or updating to 3.1.1.GA. The release notes contain specific instructions on how to do so.

As always I want to thank our 470,000 strong community of developers for your constant feedback and support.


Upcoming ACS changes: user session and geo query

We try to be as transparent as possible about important changes that could impact your development. To that end, we are planning to roll out two ACS changes in next couple of months that may impact your application.

Application User Session Expiration

An application user session never expires today.  We are introducing the policy of expiring and removing sessions that have been inactive for 6 months.

How does it affect your application?  If your application logins a user and saves the session_id, normally stored in a cookie, every time it makes a REST call to ACS using the same session_id, the expiry clock is reset and the user gets another 6 months. As long as the ACS user is active using the same session_id within 6 months, there is no impact on your application and current logged in user. If an application user is completely inactive for 6 months or more, this user session is removed and any subsequent ACS call that requires user login such as create.json, update.json and delete.json will get a 404 error. We recommend your application can handle an invalid user session error and prompts a login screen to the user to login again.

Geo Query

ACS also currently supports MongoDB’s $nearSphere Geo Query.  Geo Query requires a field to be indexed with a geo index.  The ACS fields you can perform $nearSphere on are lnglat (pre-defined location data and only available in places and events) and coordinates (list of custom defined location data and available in all objects).  It implies that places and events have two geo indexes in the same collection and that prevents us from supporting $geoNear operation that is more powerful than $nearSphere.  We will consolidate lnglat value with coordinates values and remove geo index on lnglat field.

How does it affect your application?  For events and places, even if you never explicitly copied lnglat value to coordinates, lnglat will appear as the first element of coordinates.  Performing $nearSphere on coordinates field will return a match if it matches the lnglat value.  $nearSphere query on lnglat or coordinates will continue to work as before.

Questions?

Please post your questions on Appcelerator Q&A forum with “ACS” tag or leave your comments on this blog post.


Building a custom front-end to ACS using Node.ACS [Part 2]

On my previous post we went through the process of setting up a Node.ACS app, and understanding the basics of its built-in MVC framework. It’s now time to integrate ACS back-end services. Our main goal for this mini-project is to use a responsive framework (Bootstrap) to provide a custom, clutter-free front-end for ACS. Think about it this way: You’re using ACS to store locations. Why give your client access to ALL of ACS, just to curate data? ACS’ interface is designed for the developer, not for the end-user. We’ll build a phone and tablet-friendly web user interface what will allow them to easily enter data into the system. So let’s get started!

Structure of our website:

We’ll have a Login screen that will be used to login against the ACS User service. Upon successful login, the user will see a screen displaying a list of places that will be part of the ACS Places service. This screen will provide options for Adding and Deleting places, as well as launching a “Google Map” when a location is clicked. On the top navigation area we’ll have two links, About and Contact with sample content only to illustrate linking and session management. The website will look like this:

App.js

In this file you initialize your website and your session with ACS.

var ACS = require('acs').ACS;
var ACS_KEY='YOUR_ACS_KEY';
var ACS_SECRET='YOUR_ACS_SECRET';

// initialize app
function start(app, express) {
     app.use(express.favicon(__dirname + '/public/images/favicon.ico'));          //set favicon

     // this line is explained @
     // http://docs.appcelerator.com/cloud/latest/#!/guide/node_mvc
     app.use(express.session({ key: 'node.acs', secret: ACS_SECRET }));

     ACS.init(ACS_KEY, ACS_SECRET);
}

Config.json

{
  "routes":
  [
    { "path": "/", "callback": "application#index" },
    { "path": "/error", "callback": "application#error" },
    { "path": "/home", "callback": "home#home" },
    { "path": "/login", "method":"post", "callback": "useraccess#login" },
    { "path": "/logoff", "callback": "useraccess#logoff" },
    { "path": "/about", "callback": "application#about" },
    { "path": "/contact", "callback": "application#contact" },
    { "path": "/api/delete", "callback": "api#deleterec" },
    { "path": "/api/addplace", "method":"post","callback": "api#addrec" }
  ],
  "filters":
  [
    {"path": "/home", "callback": "session_filter#validateSession"},
    {"path": "/about", "callback": "session_filter#validateSession"},
    {"path": "/contact", "callback": "session_filter#validateSession"},
    {"path": "/api/delete", "callback": "session_filter#validateSession"},
    {"path": "/api/add", "callback": "session_filter#validateSession"}
  ],
  "websockets":
  [
    { "event": "", "callback": ""}
  ]
}

This file is in many ways the heart of your app. Here you define how the user is allowed to interact with the website, or how a page should interact with another. The first section, the routes, are a fundamental part of an MVC website. Defining this section is part of your website planning process and provides you a clear idea of how your website will behave.

Path Method File Function
/ GET application index
/error GET application error
/home GET home home
/login POST useraccess login
/logoff GET useraccess logoff
/about GET application about
/contact GET application contact
/api/delete GET api deleterec
/api/addplace POST api addrec

 

I have stored functions in different files, but only for organization purposes. This is more an issue of your personal programming style. You can certainly use a single file for all your functions. This table should be read like: When the user browses to /home, I will execute the home function inside /controllers/home.js and the data will be available via GET.

Now let’s look at the filters section, which has a similar format.

Path File Function
/home session_filter validateSession
/about session_filter validateSession
/contact session_filter validateSession
/api/delete session_filter validateSession
/api/add session_filter validateSession

All entries are using the same function inside the same file. This block is actually providing a way for us to protect certain areas of our website. Instead of having to validate the user session by code on every page, we set a filter on the pages we want to protect. The validateSession function simply verifies the validity of the session. If invalid redirects to error page, if valid, control is returned to the page controller.

function validateSession(req, res, next) {
  if(!req.session.session_id) {
    res.redirect('/error');
  } else {
    next();
  }
}

ACS

Access to ACS methods is consistent with the way you’d used them with Titanium, where you call the method and pass an object and a callback.

For our login method, we grab data from the HTTP POST and then send to ACS.

function login(req,res){
    ACS.Users.login({
        // grab data from http post
        login: req.body.username,
        password: req.body.password
    }, function(data) {
    	if (data.success){
    		// set session data to be used later througout the app
		req.session.session_id=data.meta.session_id;
                req.session.user_id=data.users[0].id;
		req.session.fullname=data.users[0].first_name + ' ' +
data.users[0].last_name;
                // the "home" controller will pick it up
		res.redirect('/home');
    	}else{
    		res.redirect('/error');
    	}
    });
}

When the user successfully logs in, he/she is taken to Home, where a list of Places is displayed. The controller for the “Home” template looks like this:

function home(req, res) {
	ACS.Places.query({
        order: "-created_at" // new on top
    }, function(data) {
        if(data.success) {
            console.log(data);
            res.render('home', {
                                title: 'Beer Places',
                                places:data.places,
                                page:'Home',
                                fullname:req.session.fullname
                                });
        } else {
            res.send('Error occured. Error code: ' + data.error + '.
Message: ' + data.message);
        }
    })
}

The line that reads res.render(‘home’,{}) is sending some data to the View, and one of these pieces is the actual places array that was returned by ACS. This Array is send as a static, client-side array to the view. The templating engine can now loop through the array and write the rows in HTML.

<tbody>
<% places.forEach(function(place){ %>
  <tr id="<%=place.id%>">
    <td><%=place.name%></td>
    <td><%=place.city%></td>
    <td><%=place.phone_number%></td>
    <td><a href="http://maps.google.com/?q=<%=place.name%>@
<%=place.latitude%>,<%=place.longitude%>" target="_blank"
title="Map">Map</a></td>
    <td><a href="javascript:void(0);" onClick="deleterec('<%=place.id%>')"
title="Delete"><div style="text-align: center">
<i class="icon-remove-circle"></i></div></a>
</td>
  </tr>
<%    }) %>
</tbody>

If you look closely, you’ll see that the places array effectively is available to the template. Also notice that you can execute Javascript code by encapsulating it in tags, in this case performing a forEach loop on the Places array, and displaying HTML rows. Just remember, when you want to execute Javascript code you use <%= your_code %> and to echo values you use <% your_variable %>.

An API on top of an API

You could use Node.ACS to provide high-level methods, an API if you like, that interact with the ACS API. An example of this technique is providing a “delete” method that in turn will call the ACS delete place method. Why do this? Well, for one, you don’t want to have your API key available in your Javascript source. With this method, your API key resides inside Node.ACS, that is in the server-side. Another reason could be because you’d like to perform other operations with the data returned by ACS, perhaps even return a new JSON string to your front-end. If you look at our Javascript code for deleting a record, it looks like this:

function deleterec(recid){
      var r=confirm("Delete this record?");
      if (r==true){
          $.ajax({
            url: '/api/delete/?id=' + recid,
            type: 'GET',
            success: function(data) {
              location.href='/home';
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                //alert("Status: " + textStatus);
                //alert("Error: " + errorThrown);
            }
        });
      }
    }

NOTE: In a real-world scenario you’d want to provide a more secure way of deleting your records and not by simply calling a Delete URL with your record id, but those security measures are out of the scope of this post.

Using Node.ACS’ built-in is really fun. The fact of not having to install a web server is a very convenient feature, and being able to take advantage of node.js definitely provides virtually endless possibilities.

The full source code for this example is available at https://github.com/ricardoalcocer/nodeacs_sample_website, simply fork/clone, add your own ACS Key and Secret, and hack away. This is a sample/proof-of-concept so feel free to send me pull request with error corrections or features you’ve added to the project.


Support for iOS 7

The big news of the day at WWDC in San Francisco was the unveiling of iOS 7.

Judging from the reaction, there’s no reason to believe that iOS 7 won’t fulfill Tim Cook’s promise of being “the most significant update to the mobile operating system since its introduction on the iPhone in 2007″.

New features in this release include:

  • Improved controls and notifications
  • Multi-tasking interface and responsiveness to motion for apps
  • AirDrop content sharing
  • In-car integration
  • Personal security enhancements

 

We have already downloaded the beta and have successfully recompiled and run a few simple apps on top of it. No doubt you’ll be doing the same and looking for new and innovative ways to take advantage of these new capabilities.

Rest assured that we are committed to delivering support in the Appcelerator Platform and Titanium on the day it is released.

In the meantime, please share with us and the rest of the community your feature requests and requirements for iOS7-specific support, as well as any issues, via the Titanium Community JIRA. https://jira.appcelerator.org/browse/TC

Stay tuned for more information as we get closer to the general availability of iOS 7 in the fall.


Featured App Spotlight – SV Waldhof Mannheim

Today’s featured spotlight comes from Kenan Sulayman. Kenan and his team built a slick soccer app that enables users to follow multiple teams in one app and get live feeds and extensive player information on the go. Hear more about how Kenan tackled this feat using Titanium.


Why did you pick Titanium for your development needs?

Waldhof Titanium is awesome. It’s open unlike other platforms and can be modified as we want, when we want.

We didn’t chose native SDKs because we wanted flexibility, fast development speed and extensibility; we are Javascript-gurus and have background as architects using node.js-powered Cloud-solutions. (scalable web-apps, innovative database solutions and real time communication)

Tell us a little bit about choosing your development option

So we had the basic concept of “that” soccer app. We asked how we could do something really innovative and beautiful, while keeping spent resources low, and creativity and flexibility at maximum.

There were many development options we considered, including Sencha Touch and PhoneGap. We even considered Adobe’s “Publish to iOS” feature. We explored these options because everyone on our team feared the Objective-C mess that would happen if we tried to use it in an extremely dynamic way.

Ultimately, this is why we chose Titanium and the ability to leverage Javascript to build solid and native experiences for mobile devices.

Can you describe the app in more detail?

We wanted an innovative soccer app that combined real-time information with user-interaction. This includes information about every player – his interests, pictures, per-game information, live-ticker, etc. and a platform on which everything could thrive.

We didn’t just build an app, we built an app sandbox! Titanium makes it extremely easy to customize an app so that we could not only implement several teams into one app, but also have the opportunity to easily extend the app to be a white-label product: this allows us to build unique experiences for as many teams as possible — without reinventing the wheel each time.

What development problems did you face prior to using Titanium?

We faced several problems with the app including memory leaks that we had to chase down, the complexity of plain Objective-C compromising our creativity and lastly the deployment time of updates and hotfixes.

Can you walk me through how your team developed this application?

We sat down with our designer and built a concept for many pages. We then decided on the the most efficient way of implementation. Do we use deep-nested Views, templated Views, etc. We even thought about using UIWebViews.

We wanted a truly dynamic application, so we built a skeleton which got data from the server and outputted it. Then we made that data redundant, making it available offline.

We then started the design of the app. First, we got the navigation bar beautiful, then we placed the logo on top of everything. We split our scrum into each window and feature. It was astonishingly easy from there on – development from top to bottom.

We even were able to build functions generating a whole window subsystem … something which would be extremely messy and complex in Objective-C. For instance, when we want to display game information, we have a global controller which dynamically checks every parameter before the window is generated: orientation, current page, usage history, etc. This generates each window as dynamically as possible.

The development took 6 months, which boils down to 3 1/2 months if we leave out logistical problems (contact with the team, their ideas and feedback, and of course other projects).

How does Titanium fit into your future development plans?

Through this process we gained a ton of experience using Titanium. To keep our skills sharp, we have a hackathon each month and recently we were able to build an app in just 5 hours. It was a home automation application (the backend was implemented with node.js, a few Raspberry Pi’s, serial connectors and some hacked-together on-off controllers (for light) and one thermometer sensor).

The development is so easy and straightforward that we can build everything our creativity allows us to do. We go from idea to concept in one or two days, and then to a finished app in one month (depending on complexity — the dynamic nature of the soccer app is waaay more complicated than the home-automation system).

What kind of database, content, or cloud services are you accessing?

For the database we’re using PHP/MySQL on one server as a data aggregation for news and other static data. For dynamic data (i.e. publish-subscribe messaging system for the live-ticker), it’s determined based on the device (performance, capacity, internet speed, etc.) what type of connection routine is used. We also use a server side parser of the static data and data streams from third-party sources, a content provider for dynamic data like games and we use a plain Node.js / LevelDB configuration for everything which has to be quick and fast.

For the content we’re using a database for in-app data. We built an update distribution system which can update the app without losing our AppStore rating. With Titanium this is easy since we are unable leave the Javascript-sandbox and can’t in any way execute malicious code.

We’re using Titanium Analytics, Google Analytics and a self-built analytics system. Our own backends and cloud-solutions are backed by Level3, AWS EC2 and Elastic Load Balancing.

What kind of native features are you using in your app?

We’re using the native UI, video (MP4s from YouTube), the camera, a SQL database and geolocation for analytics and cache data using direct file system access with indices stored as JSON.


Big thanks to Kenan for taking the time to give us some insight into his experience and success with Titanium app development. Interested in having your Titanium app showcased? Send us an email at community@appcelerator.com and share your story with us!

Page 1 of 9212345...102030...Last »