Category Archives: code

How to generate a release .apk file from a Cordova project

The following batch file takes a Cordova project and builds, signs, and deploys a .apk file. I had found this script to be helpful for myself, so hopefully it will help others as well. Just replace keystore_file and alias_name with your own keystore information.

cordova build --release android

for /f "delims=" %%x in ('dir /od /a-d /b platforms\android\ant-build\*.apk') do set recent=%%x

set recentShort=%recent:-release-unsigned.apk=.apk%

ECHO Y | DEL %recentShort%

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -storepass transitKey -keystore keystore_file platforms\android\ant-build\%recent% alias_name

zipalign -v 4 platforms\android\ant-build\%recent% %recentShort%

adb install -r %recentShort%

Nokia X is an Android phone with poor support for Android

Nokia has just announced their new X line of phones that run a skinned version of Android. In their announcement, Nokia boasted that 75% of existing Android apps were already compatible. However, instead of being impressed, my gut instinct was that the number seemed rather low…

NokiaXA run through the compatibility checker confirmed my fears. Of the five android apps I am currently selling through Google Play, only one had no compatibility issues. Most of the problems with the apps centered around support for in-app billing (there are also issues with supporting any mapping APIs). While the tool regards this as a minor issue, the ability to make money from apps is kind of important (and due to my use of the AIR framework also tricky to fix).

The billing API is mostly a drop-in replacement for Google’s, but I feel that it would be easier if Nokia took a page from BlackBerry’s book and allowed the apps to integrate with its store without any code changes at all. Amazon does a similar thing to Nokia in forcing developers to rework their apps, but in exchange at least promises a unique and sizable market. Meanwhile, Nokia’s X phones live under the threat of being axed by Microsoft before we even reach summer.

Improving app efficiency

It can be rather impressive to see how much the efficiency of your code can improve as you get to know a platform better. When it comes to writing BlackBerry 10 apps in Cascades my code has gotten dramatically better. This is not the result of any special magic, but instead a by product of putting in the required hours for a given platform. For example my Mileage Tracker app has recently been updated to version 1.5 and despite continuing to add new features in each new version, the size of the .bar file is as small as it has ever been. To look at the overall sizes of the .bar file for the Mileage Tracker app see the below chart.

MileageTrackerBarSize

Forcing a dark theme on Windows Phone

Despite the fact that it looks terrible, Windows Phone offers users the ability to place their phones into a light theme. For any app that applies a specific color or background anywhere, testing against this theme is a critical step before submitting a new application, and is almost guaranteed to cause a few headaches.

While BlackBerry 10 allows you to force a dark theme for your app with a single line of XML, for Windows Phone you need to force individual components into a dark theme. For the most part this is done by remembering to explicitly set your background and foreground colors for every component, this can usually be done either in XAML or in C#. Below is an example of setting the colors for the ApplicationBar in C#.

ApplicationBar appBar = new ApplicationBar();
appBar.BackgroundColor = Color.FromArgb(255, 0, 0, 0);
appBar.ForegroundColor = Color.FromArgb(255, 255, 255, 255);
ApplicationBar = appBar;

Setting the SystemTray to a dark theme requires a bit a more unique approach, where you add attributes to the root element of the main PhoneApplicationPage in XAML. As seen in the following lines of code.

shell:SystemTray.BackgroundColor="Black"
shell:SystemTray.ForegroundColor="FloralWhite"

Also note that you can not set the SystemTray ForegroundColor to exactly white. It can be very close to white such as a very light gray, or the FloralWhite that I used, but it can not be exactly white. While the small print of Microsoft’s documentation is very clear on this, the reason why seems to be a complete mystery.

Deploy BlackBerry 10 apps with device name instead of ip address

DeviceNameWhen using a script (or the command line) in order to deploy apps to a device you can use the phone’s device name (which seconds as a network name) in place of the ip address. For example instead of

blackberry-deploy -installApp -launchApp -device 192.168.1.104 -package PixelatedShapes.bar -password password

you could use

blackberry-deploy -installApp -launchApp -device BLACKBERRY-Z10E -package PixelatedShapes.bar -password password

This shortcut is particularly helpful to use when writting scripts, so you do not have to update the file every time that the phone is assigned a new ip address.

BlackBerry 10′s problem with the swipe-down menu

IMG_00000036The UI that BlackBerry introduced on the PlayBook, and continued on BlackBerry 10 calls for the support of a swipe-down menu where a user can swipe down from the top bezel and gain access to additional options for the app. The design in very good in theory in that it allows a dedicated menu area without consuming any real estate on the screen or requiring a dedicated menu button. However, far too few apps make use of this menu for consumers to expect it to be there.

I have written about this problem before. Over two years ago I noticed this problem on the PlayBook and the issue has only gotten worse since then. The Cascades framework instead encourages the use of an overflow menu, and even less preinstalled apps make use of the swipe-down menu.

Major apps such as the Browser, Facebook, and the search app do not have a swipe-down menu at all. Many other first party apps such as the Pictures app, the Videos app, the Music app, and the File Manager make only trivial use of the swipe down menu offering nothing more than a link to an external help file. (Couldn’t BlackBerry at least open these help menus as a card?) Even more interesting is the Calculator app that had a swipe down menu when BlackBerry 10 first launched, but as of 10.1 no longer has one at all.

IMG_00000049Following BlackBerry’s lead, many developers (including myself) stopped using swipe-down menus. Following the current UI guidelines for Cascades almost every app will have some sort of an action bar making it trivial for developers to just place everything else in the overflow menu where it is much more discoverable by users. At this point I honestly can not recommend that anyone rely on the swipe-down menu as the only way to do anything in their app.

In version 5.1 of my Twinkle app (pictured) I am implementing a swipe-down menu in a Cascades app for the first time. Yet all three of the options there are redundant and are also available through the standard action bar overflow menu. At this time, this is the absolute most support that I am willing to give to the swipe-down menu. If BlackBerry wants this situation to change, they should seriously rethink their UI guidelines and what they are doing with their own apps…

How to link to Facebook and Twitter in Cascades

In cascades it is possible to link directly to a particular Facebook or Twitter profile using the following code.


void MyApp::invokeTwitter()
{
bb::system::InvokeManager* m_invokeManager;
m_invokeManager = new InvokeManager(this);
InvokeRequest request;
request.setTarget("com.twitter.urihandler");
request.setAction("bb.action.VIEW");
request.setUri("twitter:connect:ebscer");
m_invokeManager->invoke(request);
}

void MyApp::invokeFacebook()
{
bb::system::InvokeManager* m_invokeManager;
m_invokeManager = new InvokeManager(this);
InvokeRequest request;
request.setTarget("com.rim.bb.app.facebook");
request.setAction("bb.action.OPEN");
QVariantMap payload;
payload["object_type"] = "page";
payload["object_id"] = "152370494833193";
request.setMetadata(payload);
m_invokeManager->invoke(request);
}

Calling this code will directly open the Twitter and Facebook pages for Ebscer.

Script for deploying most recently created .bar file

The following batch script is what I use to automatically deploy the most recently created .bar file in a folder to either a PlayBook or BlackBerry 10 phone.

@echo off
for /f "delims=" %%x in ('dir /od /a-d /b *.bar') do set recent=%%x
@echo on
call blackberry-deploy -installApp -launchApp -device <device-ip-address> -package %recent% -password <device-password>

Just replace <device-ip-address> and <device-password> with your actual ip address and password.

Why you should use the captive runtime for your Android apps

For Android apps compiled against Adobe AIR, it is best if you include the entire AIR runtime as part of your distributable .apk file. It may not be as nice from a programing standpoint, but it is far better for the end user. I have three Android apps in the Google Play store (Xploding Boxes, Runaway Trains, and Black Out), at first I relied upon users to download AIR for themselves, but have since realized that bundling the runtime gives a much better experience for Android users.

For developers the idea of having the AIR runtime as a separate installation presents a much prettier (and more loosely coupled) architecture. It allows the app to have a smaller file size, and to share the AIR platform with any other apps that need to make use of it, while also allowing the two installations to be updated individually.

However on Android (unlike the BlackBerry PlayBook and the Barnes and Noble Nook) the AIR framework is not preinstalled on the OS, so if the captive runtime is not used to bundle AIR into your .apk than when users first launch the app they are presented with a screen asking them to go download and instal Adobe AIR. This is just giving your users another chance to quit, and ignore your app, and even resulted in a poor review for one of my apps from a user who did not understand what Adobe AIR was.

Instead if you bundle AIR into your app using the captive runtime you result in a larger distributable file, but when the user goes to launch it for the first time it is guaranteed to just work.

Zygote results in real speed improvements

Last week RIM announced project Zygote where they are improving the start up times of cascades apps by pre-compiling shared libraries. I gave it a go with some of my existing cascades projects and found significant improvements to the launch times of my apps.

App Name Before After Improvement
Mileage Tracker 1.67 s 0.76 s 2.2X
Liar’s Dice 2.08 s 1.09 s 1.9X
10,000 Farkle 1.82 s 0.82 s 2.2X

On average these changes have eliminated 52.3% of the load times for these applications, making these changes well worth it. For details on how to implement this see instructions here and here.

How to create a Toast in C# for Metro apps on Windows 8

The documentation that Microsoft provides for creating toasts is far more complicated and confusing then it really needs to be. The sample app for Toast Notifications runs over 20 files and multiple projects, yet the good news is that it is actually quite simple. The basics can be demonstrated in less then 10 lines. This is primarily done by hand writing the toast’s xml structure by hand as a string.

string title = "TITLE";
string message = "toast details";
string imgURL = "ms-appx:///Assets/Logo.png";

string toastXmlString = “<toast><visual version=’1′><binding template=’toastImageAndText02′><text id=’1′>”+title+”</text><text id=’2′>”+message+”</text><image id=’1′ src=’” + imgURL + “‘/></binding></visual></toast>”;

Windows.Data.Xml.Dom.XmlDocument toastDOM = new Windows.Data.Xml.Dom.XmlDocument();
toastDOM.LoadXml(toastXmlString);
ToastNotification toast = new Windows.UI.Notifications.ToastNotification(toastDOM);
ToastNotifier toastNotifier = Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier();
toastNotifier.Show(toast);

Every bug is your fault

When you write software you need to take responsibility of any bug that users might blame you for. No matter if it is your fault or not. If the end users think it is your fault, then you should take responsibility to fix the problem no matter where it actually lies.

As posted by Brandon Bloom:

When you run a business, if your software has a bug, your customers don’t care if it is your fault or Linus’ or some random Rails developer’s. They care that your software is bugged. Everyone’s software becomes my software because all of their bugs are my bugs. When something goes wrong, you need to seek out what is broken, and you need to fix it. You fix it at the right spot in the stack to minimize risks, maintenance costs, and turnaround time. Sometimes, a quick workaround is best. Other times, you’ll need to recompile your compiler. Often, you can ask someone else to fix it upstream, but just as often, you’ll need to fix it yourself.

True hackers have come to terms with a simple fact: If it runs on my machine, it’s my software. I’m responsible for it. I must understand it. Building from source is the rule and not an exception. I must control my environment and I must control my dependencies.

Although this attitude needs to extend beyond dependencies, and also cover things like your distribution.

Posting to Facebook and Twitter

The following code will help you post to Facebook or Twitter from a BlackBerry Java application. This code requires the use of some API elements that were not introduced until OS 7 so you will want to use a different build in order to continue to support older devices. This code was used in version 3.1 of the game Pixelated.

Code for posting to Facebook


public void postToFacebook(String text)
{
JSONObject context = new JSONObject();
MenuItem fb = null;
try
{
context.put(SendCommandContextKeys.TEXT, text);
SendCommand[] sendCommands = SendCommandRepository.getInstance().get(SendCommand.TYPE_TEXT, context, false);

if (sendCommands != null && sendCommands.length > 0)
{
SendCommandMenu scm = new SendCommandMenu(sendCommands, 0, 0);
SendCommandMenuItem[] scmi = scm.getSendCommandMenuItems();
for(int i=0;i {
if(scmi[i].toString().equals("Facebook"))
{
fb = scmi[i];
}
}
fb.run();
}
}
catch(Exception e){}
}

Code for posting to Twitter


public void postToTwitter(String text)
{
JSONObject context = new JSONObject();
MenuItem tw = null;
try
{
context.put(SendCommandContextKeys.TEXT, text);
SendCommand[] sendCommands = SendCommandRepository.getInstance().get(SendCommand.TYPE_TEXT, context, false);

if (sendCommands != null && sendCommands.length > 0)
{
SendCommandMenu scm = new SendCommandMenu(sendCommands, 0, 0);
SendCommandMenuItem[] scmi = scm.getSendCommandMenuItems();
for(int i=0;i {
if(scmi[i].toString().equals("Twitter"))
{
tw = scmi[i];
}
}
tw.run();
}
}
catch(Exception e){}
}