BlackBerry PlayBook NDK Command Line Advanced Quickstart Guide

Phil keeps telling me I need to document what I do. After all, I’ve worked on a ridiculous number of platforms, and with many SDK’s.

So alright, I’m going to record and share my notes here. I’m going to assume you have your own build system figured out, and cover the highlights and key things you need to know and do to get native code up and running on the PlayBook.

Device Summary

Just a few highlights about the platform.

  • Dual Core 1 GHz ARM Coretex-A9 w/ Neon, 7″ 1024×600 IPS LCD (drool), PowerVR SGX 540 GPU
  • NDK Available. Work either through a custom Eclipse IDE, or entirely from the command line
  • Command line is a typical GCC cross compiler setup, with custom tools for packaging/deploying
  • Linux-like platform. EGL and GLES1/GLES2 available. OpenAL available (Notes)
  • BlackBerry packages are BAR files, which are actually JAR files, which are actually ZIP files
  • Was on sale for just $199 during the weeks surrounding “Black Friday”.

Step 1. Request Signing Keys

This is step 1 because how long it takes is entirely outside your control.

Go to http://developer.blackberry.com/native/signingkey (ALT) and make your request. Typically within a few hours you will get a series of e-mails containing .csj files, so if you’ve previously downloaded the SDK, you’ll be waiting a while before you can test on device. More details here.

IMPORTANT: REMEMBER YOUR PIN AND COMPANY NAME! YOU WILL NEED IT!

For times like these, I like to create a text file containing the signing code, and put it alongside the signing keys. Yes, technically that partially defeats the security purpose of the keys, but keys and signing is usually such-a-pain.

Step 1b. Apply for a Blackberry AppWorld Vendor account

This also takes a while, so do this early to get in the queue sooner.

https://appworld.blackberry.com/isvportal/

You will eventually get an email asking for a scan of government issued ID such as a drivers license, or business related documents (to prove you are real). If you have these ready, you can respond to the request quickly.

Payments are via Paypal, so you will need a valid Paypal account to be paid.

Step 2. Get the NDK

Yeah! You can do it! Click them links and go go go!

https://bdsc.webapps.blackberry.com/native/

Notably, the downloader tries to install some Akamai service thingy. I couldn’t get this working, but that’s okay. There’s an option to say “this did not work” in the popup box, and after the popup closes there’s an option to download directly without Akamai. Use it.

Step 3. Install the NDK

PSA: RIGHT CLICK AND RUN INSTALLER AS ADMIN!!

After installation, a batch file and shell script can be found in the install folder that contains all paths.

C:\bbndk-1.0\bbndk-env.bat

The batch file, by default, does not bring up a shell. It simply correctly sets the environment variables.

Me, I made a copy of the batch file (now bbndk-env-shell.bat), and simply added a line “cmd” to the end of the file. Now I have a shell.

One further addition I made was adding MinGW’s MSys to the path. I rely on Unix tools like readlink and basename in some of my shell scripts, and the simplest way for me to get access to these was to just use the ones that ship with MinGW. If you’re not as Unix’y as I am, simply adding “cmd” will be enough to build the any of the example programs using make.

My complete script (bbndk-env-shell.bat) is as follows.

Alternatively, if you’d prefer to work inside bash, you can use “bash -l” instead of “cmd“.

Step 4. Create Signing Tokens

I used this for reference.

By now you have hopefully received your signing keys from RIM. If not, go get coffee… then Pizza… then watch a movie. Once you do get them, put them somewhere safe. I like to bundle them inside my source tree, in a platform specific place. That way, I have a copy on all PCs that sync my source repository.

Browse to your keys folder.

Execute the following four commands to set up your signing account.

Where {PASSWORD} is a unique password you will remember, {MY_COMPANY} is the company name used when you signed up for your keys, {PIN} is the unique code you picked when you signed up for your keys, and client-RDK-????????.csj/client-PBDT-????????.csj the the name of your RDK and PBDT key files respectfully.

(NOTE TO SELF: I used to set -keystore author.p12 on the command line, like my reference suggested, but I’m hoping by omitting this it works too. Explicitly setting keystore wouldn’t create author.p12 inside the settings folder. Moving to another computer, for whatever reason, would only work if the .p12 file was alongside the settings, and not explicitly via the command line)

Step 5. Create a provisioning token for our device

We need to request a token (BAR file) to provision each of our devices.

blackberry-debugtokenrequest -cskpass {PASSWORD} -storepass {PASSWORD} -deviceId {HEX_DEVICE_PIN} mydebugtoken.bar

{PASSWORD} is used twice (well, it can be different but that would be annoying). {HEX_DEVICE_PIN} should be your device PIN in a format like 0xABCD1234 (found under Settings->About->Hardware->PIN, and mydebugtoken.bar is the BAR file we’ll be writing.

Step 6. Installing the provisioning token on our device

To install the provisioning token (BAR file), you need the IP address of the device. Get this from Settings->About->Networking.

Next, you need to enable developer mode and to actually send the token via WIFI. Go to Settings->Security->Development Mode be sure Use Development Mode is On. You may have to do this every time you reboot the device.

We send the debug token to device by doing the following:

blackberry-deploy -installDebugToken mydebugtoken.bar -device {DEVICE_IP} -password {DEVICE_PASSWORD}

Where {DEVICE_IP} is the devices IP address on your network, and {DEVICE_PASSWORD} is the password set when you first enabled developer mode (or if you set a password).

NOTE: You’ll need to generate a new provisioning (debug) token every 10 days (Step 5), and send it to the device (Step 6). You can check the status of the token in the Security->Development Mode section of Settings.

Phew!

Now we are ready to send our own binaries to the device. Great! But how do we make one?

Step 7. Compiling Code

GCC and all the tools used above can be found in “C:\bbndk-1.0\host\win32\x86\usr\bin“. The PlayBook is an ARM based device, so we need to invoke the correct GCC build.

  • GCC tools (gcc, g++) prefixed with ntoarmv7- are your Native PlayBook compilers (ntoarmv7-g++)
  • GCC tools (gcc, g++) prefixed with ntox86- are your Simulator compilers (ntox86-g++)
  • Alternatively, a tool exists “qcc” for QNX GCC, which acts as a frontend to the above tools. The C++ version is QCC (caps).

GNU Make, Bash, and a plethora of other typical Unix tools are included as well. Omitted are some of more Unix specific ones like readlink and basename, but if you have MinGW+MSys installed, you can add them easily (see Step 3).

The BlackBerry command-line tools (batch files and shell scripts) include:

  • blackberry-airpackager – Make Adobe Air Apps BAR packages
  • blackberry-connect – Allow SSH access
  • blackberry-debugtokenrequest – Used to get us a token (see above)
  • blackberry-deploy – Send a BAR package (apps) to a device
  • blackberry-keytool – Used to generate keys (see above)
  • blackberry-nativepackager – Make BAR packages for deployment
  • blackberry-pythonpackager – Hey neat, apparently you can do Python
  • blackberry-signer – Sign BAR packages
  • blackberry-uripackager – Make BAR packages that are a URL

The batch files and shell scripts are merely frontends. In actuality, the tools are all Java based.

For reference, Library files can be found in:

C:\bbndk-1.0\target\qnx6\armle-v7\lib
C:\bbndk-1.0\target\qnx6\armle-v7\usr\lib
C:\bbndk-1.0\target\target-override\armle-v7\lib **
C:\bbndk-1.0\target\target-override\armle-v7\usr\lib **

Header files can be found in:

C:\bbndk-1.0\target\qnx6\usr\include
C:\bbndk-1.0\target\target-override\usr\include **

The libraries in the paths above with ** need to be explicitly added to your include paths and library search paths (-I and -L).

Step 8. Library Linking Notes

Not actually a step, but you’re going to need to link against some libraries to get access to any useful features of the device. I’m going to assume you know how to link a program with GCC/G++, and how to specify libraries (-l).

Very important, you need to add the Target Overrides to your include and library search paths (-I and -L). If you don’t, older versions of the libraries will be referenced. This is bad because RIM changed the names and argument counts of some functions (Navigator library functions used to be nav_ prefixed, but are now navigator_ prefixed). I made this silly mistake of omitting this, and got totally confused, as the documentation suggests different names. The correct function names are available with the overrides.

-I$(QNX_TARGET)/../target-override/usr/include

And the library paths:

-L$(QNX_TARGET)/../target-override/$(CPUVARDIR)/lib
-L$(QNX_TARGET)/../target-override/$(CPUVARDIR)/usr/lib

If you’re using the bbutil.h and bbutil.c files included with the sample apps, be sure to include FreeType in your include paths (unless you’d rather fix the file):

-I$(QNX_TARGET)/usr/include/freetype2

As well, add the Freetype and libPNG libraries to your project.

-lfreetype -png

TIP: If you're developing a game that uses OpenGL ES 2, and you want to use bbutil.h and .c, you'll have to modify (or comment out) parts of the font code, as it relies on some OpenGL ES 1 calls.

PlayBook features many standard libraries including:

  • EGL 1.4 (OpenGL Contexts): -lEGL (libEGL.a), /usr/include/EGL/
  • OpenGL ES 1.1: -lGLES_CM (libGLES_CM.a) or -lGLESv1_CM (libGLESv1_CM.a), /usr/include/GLES/
  • OpenGL ES 2.0: -lGLESv2 (libGLESv2.a), /usr/include/GLES2/
  • Lib Curl (simple HTTP fetching): -lcurl (libcurl.a), /usr/include/curl/
  • zlib (gzip compression): -lz (libz.a), /usr/include/zlib.h
  • Lib PNG (PNG Image Read/Write): -lpng (libpng.a), /usr/include/libpng/
  • Open SSL (Security): -lssl (libssl.a), /usr/include/openssl/

More details can be found here, as well as a complete list of PlayBook libraries can be found here.

(NOTE: Every library has a version with a trailing capitol S (libEGLS.a, libcurlS.a, etc). These are apparently something to do with relocatable code. Details here. Where this is useful, I have no idea. I can build binaries fine without it.)

Step 9. Preparing bar-descriptior.xml

Before we can deploy to the device, we need to package it. Before we can package it, we need to provide some details for the packager. We do this inside a file bar-descriptor.xml.

The easiest way to make a bar-descriptor.xml is to steal it from one of the sample programs, such as HelloNativeSDK.

This file is well documented, so go in and adjust it to suit your needs.

Well, everything except these.

As it turns out, those toolchain Id's are important. Be sure they don't change.

Further details can be found here.

Step 10. Packaging a BAR file

BAR files are the native format of BlackBerry binaries. You can define the contents of the package using the bar-descriptor.xml file, or via the command line.

NOTE: Environment Variables aren't, for whatever reason, passed to blackberry-nativepackager. I had to manually pass QNX_TARGET on the command line using -D.

blackberry-nativepackager -package MyApp.bar -devmode bar-descriptor.xml -DQNX_TARGET=%QNX_TARGET%

Or if a BASH shell:

blackberry-nativepackager -package MyApp.bar -devmode bar-descriptor.xml -DQNX_TARGET=$QNX_TARGET

If you did not specify either the Author Name or Author Id inside the bar-descriptor.xml file, you can have blackberry-nativepackager extract them from your debug token file for you.

blackberry-nativepackager -package MyApp.bar -devmode -debugToken mydebugtoken.bar bar-descriptor.xml -DQNX_TARGET=%QNX_TARGET%

Eventually, you will need to look up the Author Id. See Appendix C for a way.

A BAR file is actually a JAR file, and both BAR and JAR files are actually ZIP files. Simply rename to or append a ".zip" to the file name, and you can browse the contents using any standard archiver.

Step 11. Installing and Launching the BAR file

It's been a long journey, but the end is finally here.

blackberry-deploy -installApp -device {DEVICE_IP} -password {DEVICE_PASSWORD} MyApp.bar

NOTE: It's silly, but the BAR file name must come after the DEVICE_IP.

To also run the application after installing, use -launchApp.

blackberry-deploy -installApp -launchApp -device {DEVICE_IP} -password {DEVICE_PASSWORD} MyApp.bar

If you really wanted to, you can also "just launch" the app by omitting "-installApp" from the above command. Everything else in the command is required.

Huh-freaking-zah! We did it!

Step 12. SSH'ing in to a PlayBook to get Logs

I used this as reference.

First, we need to make an RSA key for SSH. From the shell, invoke:

ssh-keygen -t rsa -b4096 -f MyRSAKey

Using a passphrase is up to you.

This generates two files: MyRSAKey (private key) and MyRSAKey.pub (public key).

Next, we're ready to open an SSH connection to the PlayBook. Make sure you have developer mode enabled (Settings->Security->Developer Mode, swipe the slider button to on).

NOTICE: We are going to need 2 shells for this part.

From a new (dummy) shell, execute the following command.

blackberry-connect -targetHost {IP_ADDRESS} -devicePassword {DEVICE_PASSWORD} -sshPublicKey MyRSAKey.pub

NOTICE: This step used the Public key.

Finally, in your original shell, open an SSH connection as follows.

ssh devuser@{IP_ADDRESS} -i MyRSAKey

NOTICE: This step used the Private key.

Deployed applications can be found in /apps/.

STDOUT can be found under /accounts/1000/appdata/{APP_NAME}/logs/ in a file "log".

{APP_NAME} will be something like "com.mycompany.MyApp.ab312938a32ddae". The exact name can be extracted from the Manifest file (see Appendix D).

NOTE: PlayBook logging is slightly delayed, so for accurate results in the log file, I highly recommend you call fflush(0) after every printf call. Yes, this slows things down, but it makes tracing remote crashes SO MUCH easier (from impossible to possible).

Step 13. Sharing Builds with Testers

To send a build to a tester (or a friend), you need the 8 character PIN of their device. This can be found in Settings->Hardware->PIN.

With the PIN, you can generate a signing token for their device. Exactly like Step 5:

blackberry-debugtokenrequest -cskpass {PASSWORD} -storepass {PASSWORD} -deviceId {HEX_DEVICE_PIN} TesterDebugToken.bar

TIP: Multiple DeviceID's can be added to a Provisioning Token (similar to iPhone Adhoc). Simply repeat -deviceId for each PIN.

Your application BAR file is already in developer mode (-devmode), so paired with this Debug Token file, the tester can run your game. Send them both BAR files.

Now, actually having your tester install the bar files on the device is the tricky part. If it makes sense for them to have the SDK installed, then this will be easier. However, if they are just a tester and not a developer, giving them a build can be a little clumsy.

Your tester needs a version of the blackberry-deploy available on their PC. If they do, simply have them bring up a shell, and execute the following.

blackberry-deploy -installDebugToken TesterDebugToken.bar -device {DEVICE_IP} -password {DEVICE_PASSWORD}

blackberry-deploy -installApp -device {DEVICE_IP} -password {DEVICE_PASSWORD} MyApp.bar

Realistically though, a tester wont have such a setup handy.

blackberry-deploy is actually a frontend for a Java program "BarDeploy.jar". The JAR files can be found in C:\bbndk-1.0\host\win32\x86\usr\lib. If the tester has Java installed, you can probably rig up a simple batch file for installing the token and the binary.

A good place to start is by looking at blockberry-deploy.bat:

java -Xmx512M -jar "%~dp0\..\lib\BarDeploy.jar" %*

Where %* is where the command line arguments go, and %~dp0 is the currently executing batch file's directory. Tweak accordingly.

You are going to need a few files from C:\bbndk-1.0\host\win32\x86\usr\lib. BarDeploy.jar is not standalone. As of the time of this writing, I have not had the chance to go through and determine the specific dependencies. You could just cheat, and copy them all (it's only 2 MB).

The tester will need to enable Developer Mode on their device, and set a password. This password is needed when sending to the device.

If you don't like passwords, you can disable the password once you are done, but you'll have to re-set it every time you want to send a build (in other words, developers, get used to it).

Step 14. Submission

*UNFINISHED*

Again, I used this as reference.

TODO: Submit Smiles HD, and finish this section.

Appendix A: Setting up new computers

You should read this. We're basically doing that.

  1. Do Step 3 (Install SDK)
  2. On original PC, browse to C:\Users\MY_USER_NAME\AppData\Local\Research In Motion\
  3. Make a copy of author.p12, barsigner.csk, and barsigner.db
  4. Place them in the equivalent location on the new PC (C:\Users\MY_USER_NAME\AppData\Local\Research In Motion\)

That's it.

TODO: See if I can use the same SSH keys across multiple computers.

Appendix B: Setting up new devices

*UNFINISHED*

TODO: Install Smiles on Mom & Dads Xmas gift, and take note of anything.

Appendix C: Getting AuthorId

Here's a shell script that extracts the AuthorId from a manifest file stored inside a BAR file.

Use this program on your Provisioning (Debug) Token BAR file.

Alternatively, you can make a copy of the Provisioning (Debug) Token BAR file, with a ".zip" extension on the end. Then simply open it as a ZIP file, browse to META-INF and take a look inside MANIFEST.MF for the Package-Author-Id.

Appendix D: GetLog.sh - A shell script for viewing the log (STDOUT)

This script retrieves the log (standard output capture) of a BAR file that was recently run on a remote device. It connects via SSH, views the file, then closes the connection.

Regrettably, opening an SSH connection to a PlayBook isn't very fast, but once connected it's speedy.

Open a connection in a separate shell like you do in Step 12, then invoke this shell script.

The script extracts the Package Name and Id from the local copy of the BAR file, and uses that to build the path.

Appendix E: Misc

Just some misc notes.

  • GDB is ntoarm-gdb. Start it.
  • Open a connection by doing "target qnx IP_ADDRESS:8000" (this is normally "target remote IP:PORT", but the protocol is a little different on QNX).
  • Some details.
  • blackberry-deploy -debugNative -launchApp -device {IP_ADDRESS} -password {PASSWORD} MyApp.bar
  • The above launches the app in debugNative mode. It returns the PID (result::SOME_NUMBER).
  • From GDB do "attach PID", where the PID is the number returned above.

Regrettably, the above isn't very useful, as none of the debug logging is sent your way (nor does the program know anything about its symbols). Still, I've noted the details for later once I do figure this out.