Friday, August 9, 2013

Using the Promises Pattern in Titanium

Promises are part of the commonjs standard and can be defined as "objects which represent the pending result of an asynchronous operation. [which can be used] to schedule further activity after the asynchronous operation has completed" [Fowler, April 2013]

I wanted to see how I could use a promise as part of a remote request in Titanium.  I could of course, simply pass an onLoad and/or onError callback when I invoked createHTTPClient, but using a promise in this manner gives one the ability to chain a number of asynchronous events and avoid the "Pyramid of Doom"

I decided to use Q from Kris Kowal for my Promises.  The first thing I did was write a commonjs module that wrapped Q and HTTPClient.  My code for this is here;


Now I can call my new qxhr module and chain my method calls like so


qxhr.create(conn)
.then(function(data) {
    //do something with the data
}, function(error) {
    //handle the error
});

or I could do

Q.fcall(qxhr.create(conn))
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (data) {
    // Do something
})
.catch(function (error) {
    // Handle any error from all above steps
})
.done();

Thursday, June 27, 2013

virtual device lab for android

Working on my current project (an android port of an iOS app) has got me thinking that with thousands of different Android devices out there, it would be neat to have a virtual device lab community of developers and testers, where we could register our various devices and collaborate on testing our apps on those devices.  I know there are device labs out there, but these tend to be web app only, with no native apps allowed.

I know that there are issues in terms of competition - we are all competing for work, after all, I but think that an element of co-opetition could be beneficial.

This is how I see it working;

1) we use a testflight project to register our devices and apps

2) we use a unit test runner like ti-jasmine to produce an app in "test mode"

3) we upload the app to testflight and inform those people with relevant devices to download it

4) the users install and run the app

5) the developer gets feedback via TF or some other way TBD

Clearly there has to be some trust relationship involved here and the choice of whether to install the app and run it has to remain with the device owner.

Is this feasible? what would we need to do to make it work?

Interested?

drop me a line or tweet @paulatstepup if you are interested

Monday, June 17, 2013

Installing Node.js for ACS under current user

Installing node using a package manager is simple on most platforms, but NPM still wants to run as root for most things.  BAD idea unless you want your machine to be pwned.

Here is how I did it;

1) download node.js source from the distro site.  I downloaded it to $home/local/src.  At the time of writing Node 0.8.13 is the minimum version needed for ACS support.
2) decide where you want to install it.  I chose $HOME/local
3) create/edit the file ~/.npmrc and add the following;
root =    /$HOME/local/lib/node_modules
binroot = /$HOME/local/local/bin
manroot = /$HOME/local/share/man

4) cd into your source folder and install node
./configure --prefix=~/local
make
make install

5) Create a ~/.node_modules symlink
cd
ln -s local/lib/node_modules .node_modules

6) Add the following to your ~/.bash_profile directory
export PATH=$HOME/local/bin:$PATH

7) type
which npm

If it says ~/local/bin/npm you are done

I adapted the instructions 1 to 7  from this original blog

8) install ACS
npm install -g acs

9) check your ACS install
acs login

10) you will be promoted for your username and password
ACS: Appcelerator Cloud Services Command-Line Interface, version 1.0.3
Copyright (c) 2012-2013, Appcelerator, Inc.  All Rights Reserved.

username:

11) if successful you should see
Welcome back, xxxx! You are now logged in.

12) Now you need to ensure Titanium know where your install is.  On a mac, go to Titanium Studio > Preferences > Studio > NodeJS

Set your Node Executable and Node Source paths as appropriate.  Your detected path should match the path set in step 4 above




Monday, June 3, 2013

Cross Platform Development with Titanium - differences between iOS and Android pt2

A really simple (and brief) one today;

I was using a callback to update  button title from a picker;  I was defining a callback as follows;
When no selection is made, the above code made my app crash on Android. On iOS it worked fine. This threw a cast exception on Android.
The fix was a simple one. Just add an empty string to the selection;

Monday, May 13, 2013

Cross Platform Development with Titanium - differences between iOS and Android pt1

Developing Android apps with Titanium is a lot of fun.  As I get deeper into developing on my current Android app, it struck me that whilst the documentation provided by Appcelerator on Titanium is generally excellent, there are some best practice steps and "gotchas" that are not highlighted and are worthy of exposition.  I thought I would use this blog to share some of them. I intend to expand on these in future posts.  Here is a simple one to start with;

Screen Resolution

In Titanium 2.0, Appcelerator introduced a new layout system.  In addition to this, they introduced a concept called Universal Unit Support, allowing the developer to specify units for size and position values. 

The following table lists the supported units:

Unit
Abbreviation
Note
pixels
px

density-independent pixels
dip or dp
Equivalent to Apple "points."
inches
in

millimeters
mm
Android, iOS only
centimeters
cm
Android, iOS only
points
pt
1/72 of an inch. Android only. Not to be confused with Apple "points."
On Android, a density-independent pixel (DIP) corresponds to one pixel on a 160DPI display.
On iOS, a DIP corresponds to one pixel on a non-Retina display, which
is 163DPI for iPhone/iPod touch and 132DPI for the iPad. A DIP
corresponds to 2 pixels of width or height on a Retina display.
On Mobile Web, both DIP and pixel are equal to one browser pixel, which may
not correspond to a pixel on the display. From testing, most browsers seem to
report a DPI value of 96DPI, regardless of the actual display density.
The absolute measures, such as inches, are dependent on the device correctly reporting
its density. On Mobile Web, these values are unlikely to be exact.
If no units are specified, a system-default unit is assumed. The system default unit is:
  • pixels on Android
  • DIP on iOS
  • DIP on Mobile Web
When developing cross platform applications, you can save yourself time (and write less code) simply by changing the default units to DIP to make it consistent across the different platforms you are working on.  This is done simply by changing the default unit setting in tiapp.xml;

<property name="ti.ui.defaultunit" type="string">dip</property>

This is a not a silver bullet, but experience has shown me when developing an Android/iOS cross platform app, this should be your default setting.



Friday, May 3, 2013

Mobile App Development with Titanium - plist entries

In the past whenever I have wanted to modify a plist entry for a titanium app, it has involved building the app and then copying back the info.plist file from the build folder into my project root.  I discovered today that you can simply edit the tiapp.xml with the plist dictionary items you need.  The following is an example for adding custom fonts in iOS



<ios>
    <plist>
        <dict>
            <key>UIAppFonts</key>
            <array>
                <string>fonts/Handlee-Regular.ttf</string>
                <string>fonts/Oswald-Bold.ttf</string>
                <string>fonts/Oswald-Light.ttf</string>
                <string>fonts/Oswald-Regular.ttf</string>
            </array>
        </dict>
    </plist>
</ios>