Configuring Apache Cordova with JetBrains WebStorm

Stepping back into the mobile arena after a bit of an absence, I decided to take a bit of advice from a gentleman who sat in on my 2014 Ohio Linux Fest lecture “Android Development on Linux” (generously, and anonymously, curated on the Internet Archive) and look not just at Android but at cross platform. For the longest time, this has always been a topic of considerable consternation. One has to think, upon reflection of the history of technology, that we’ve experienced in some ways a regression to the days when cross platform littered the landscape and was, in certain respects, paralyzing. Fortunately for myself and others, we weren’t the only ones who recognized this. Some have taken action to help ensure that we do have a shim solution for these cases, and this is where Cordova enters the fray. Being derived from PhoneGap and adopted by Apache, Cordova attempts to bring to mobile developers the ability to write a program using web languages such as HTML, CSS, and JavaScript and deploy it to multiple platforms including but not limited to Android, iOS, and Windows Phone.

As I mentioned before, the focus this time around is on cross platform development. I had a little taste of PhoneGap a few years ago and it never really stuck but there seems to be a little community acquiescence toward Cordova. Not to say that I’m following the grain too much here because there is a genuine personal interest in the framework on my part, but I want to be able to help people as well.

Now, the development environment that I use is detailed here. As you should be aware, you may want to keep this in mind proceeding forward.

  • OS: Linux
    • Distribution: Ubuntu 15.10
    • Only the default upstream repositories are used in dpkg
  • Arch: 64
  • IDE: JetBrains WebStorm (I have a license for this; the unlicensed version only works for thirty days).

As the title indicates, this tutorial is specific to configuring WebStorm to be used with Cordova. As such, there will be a lot of WebStorm-specific information here that, if you were using an alternative IDE, may not be applicable. You’ll want to follow your IDE’s integration instructions or deduce it on your own at that rate.

Prerequisite – NodeJS/NPM

I’m going to be frank here – there is very little that I know about NodeJS other than what it is, that it’s been the subject of quite a lot of hype in the web development community since its conception, and that it is a requirement on behalf of Cordova. While there is still quite a bit of homework that needs to be done on my part, I have been able to successfully install and configure it so that it works for the purposes of Cordova. This will be the topic that is covered here.

Node can either be installed by downloading it in a pre-compiled package from the Node website or through your distribution’s default repositories. If you elect to download from the Node website, you’ll need to be responsible for manual maintenance of the package and for extracting it to a location that you have access to via your permissions or ACLs (if your file system supports them). The method I used was installing was the former since updates are automatic and installation is performed in the appropriate directories. This can be done with the following command

sudo apt-get install nodejs

Once this command completes, you’ll have Node installed on your computer. To test this, you’ll want to start a Node interpreter by issuing the command nodejs at your terminal. If you’re brought to a new prompt lacking the traditional user and host name information, Node is all set to go. You’ll need to press Ctrl+C twice to end the program and return to your traditional prompt.

NPM, a pseudo package manager for JavaScript libraries, is required since this is the preferred method for installing Cordova. It will also help with obtaining Cordova plugins and other JavaScript libraries that you might want to use later on for development. It can be installed in the same was as Node was with the distribution’s package manager.

sudo apt-get install npm

To test the installation, you can simply issue npm at the terminal. If you get back a page of text indicating the usage syntax, NPM has been installed successfully.

Installing Cordova

When you’re using WebStorm, it’s apparently possible to install Cordova entirely through the IDE once you have configured it to locate both Node and NPM. These steps, however, are a little convoluted to follow, especially with all of the potential pitfalls you’re going to encounter, so we’re going to avoid this entirely and install Cordova with NPM on the terminal.

NPM has two install modes: local and global. A local installation will create a node_modules directory in the working directory where the command was issued at and install the module there. The global installation places all of the modules in a consolidated directory and makes that available to the system through environment variables; Cordova is best installed in global mode (recommended by the official install documentation). The installation can be performed with a single NPM command

sudo npm install -g cordova

The installation, when in the global scope, will need to be run as root hence the use of sudo.

Caveats… Already

To test Cordova, you’d do it in the same way that you would with both Node and NPM. However when you type cordova into the terminal and press enter, you will most likely, but certainly not always, get in response an error that may look like this:

/usr/bin/env: node: not found

The issue here is that Cordova is looking for the Node binary with a specific identifier, node. However when Node is installed through the package manager, the identifier of the binary is nodejs. Despite there being several tutorials on the Internet offering advice such as aliasing nodejs as node in your .bashrc file, the solution that needs implemented here is to create a symlink in /usr/bin named node that links back to nodejs. So what your directory tree looks like then is similar to this

cordova-node-usrbin-dirstructure

If the highlighting gets in the way, what you should be paying attention to here is that the bottom highlighted line shows the actual Node binary, nodejs, and the top line shows the node symlink which points straight to the nodejs binary. They’re both in the same directory but Cordova is looking specifically for the node file. I’m unsure if this can be configured in Cordova in some way so if someone knows, please share how to do this. Either way, once this symlink exists in /usr/bin, you should be able to then issue cordova from the terminal and get syntax help printed out to the terminal. If this happens, Cordova can see Node and is ready to go.

Prerequisite – Platform SDKs

As great as Cordova may be, it needs the platform SDKs in order to build for each one specifically. Obviously, while capable of bridging the gap between platforms, you still need the platforms themselves to actually accomplish anything. The good thing is that the Cordova wiki hosts a plethora of information relative to acquiring the corresponding SDKs. Being on a Linux system, you can install without a serious amount of labor the Android, BlackBerry and Ubuntu SDKs. For the sake of this tutorial, we’re only going to be focusing on the Android SDK. If there is further interest in setting up any of the other SDKs, I’ll create them later.

Downloading and installing the Android SDK should be a relatively straightforward process at this stage. I’m going to assume that you either know how to do this or can follow the instructions outlined on the Cordova wiki. Post installation, you’ll want to ensure that you have added an environment variable called ANDROID_HOME and included it in your PATH environment variable that points to the root directory of the SDK; again assuming that you know how to set persistent environment variables on your Linux computer..

As a secondary caveat, if you’re starting WebStorm from a desktop link or a link in the Unity Launcher, there is a bit of a catch in that the invocation context will be such that the program won’t notice the user-modified PATH variable that contains the ANDROID_HOME variable. What this means is that the IDE won’t be able to see the location of the Android SDK (I’m assuming that this would be the case for other SDKs as well). The way to fix this is to modify the EXEC field in the file to preface the issuing command with bash -ic.

cordova-node-wsdesktopstart-mod

Keep in mind that traditional desktop icons are found in ~/.local/share/applications while Unity Launcher icons are located in /usr/share/applications.

So long as all of these conditions are met, you should be able then to start WebStorm and create a Cordova project. Let’s step through that process next.

WebStorm – Creating a Cordova Project

webstorm-cordova-launch001

As you can tell, I’ve been at this for quite some time.

The first thing you’ll want to do is click on Configure at the bottom-right and then select Settings which will be the first item in the subsequent menu.

webstorm-cordova-launch002

First you’ll want to examine to ensure that WebStorm knows the location of Node. It’s highly unlikely that it has automatically determined its location so you may have to set it. Keeping in mind the location of the Node binary that was installed through your system’s package manager, you’ll want to get this fully qualified path name, along with the binary, into the Node interpreter field. Code Assistance may not be enabled for you by default. Frankly I’m unsure what this feature is but I have it enabled because… reasons.

webstorm-cordova-launch003

Next you’ll want to instruct WebStorm as to where to find the Cordova binary. Again, there’s a very high chance that it’s not automatically detected by your installation so you’ll have to manually specify. As we did with specifying the Node installation directory, you’ll need to do that here in the first field labeled PhoneGap/Cordova executable. Note that WebStorm still retains the PhoneGap label for all things Cordova even though Cordova has absorbed PhoneGap. Once the installation directory has been specified and WebStorm sees the Cordova binary, the PhoneGap/Cordova version field should automatically populate. The third field, PhoneGap/Cordova working directory shouldn’t be filled out at this point; ignore my entry here. This field is specific to your current project. This also explains the error that you’re seeing at the bottom of the window in the screen shot.

Once those are set, you can click OK and go back to the WebStorm Greeting Window. Here, you can click on Create New Project.

webstorm-cordova-launch004

Once the New Project dialog appears, you’ll select PhoneGap/Cordova App on the left side and then fill out the Location field. The PhoneGap/Cordova field is simply the location of the Cordova binary; we set this previously in the global settings. Click Create and WebStorm should take care of the work to generate the files necessary for your project.

webstorm-cordova-launch005

Now so long as the steps above were followed to the letter, you shouldn’t have any errors, other than something simply blowing up, that get thrown from WebStorm. Now you can start working on your program.

Deployment

webstorm-cordova-launch006

Testing your Cordova program can be done by creating multiple Run Configurations. Each of these would be distinguished by the value in the Name field. The value in the Command field will determine if Cordova will attempt to delegate to the emulator for the target platform, and the value in the Platform field will determine which platform is being targeted with this Run Configuration. I prefer to test on actual hardware, unless I’m constrained by the lack of, so for Android deployments I’ll deploy strictly to the device.

This should be enough to get you started. You can always read more on the Cordova Wiki to get a primer on the Cordova specifics. Otherwise you can start hacking away using HTML, CSS, and JavaScript

Vagabond 1.0 – Nearly Here

Yes that’s right. After much toil, and missing my self-imposed deadline for a release, I’m nearly complete with the program and can give it a 1.0 which means that it’ll go into General Availability.

I’m not posting Vagabond News on its website because I want that strictly to be a place to get the program from and a reference for information that developers would be interested in. Just wanted to get that out of the way as well. 🙂

Right now the program is about 98% done. All that remains is to test two additional features, push to the repository (assuming they work, which they will) and then build Debian, RPM and Source Taballs for deliverables. I haven’t built Debian packages for quite some time so I’m having to go through several refreshers to bring myself back up to speed on the workflow.

After this release, I have some additional features I want to work in so development will continue alongside general maintenance coding. I want to be able to add support for choosing to use either the official Android SDK or to use the Replicant SDK. This is more of an ethical decision as I feel like Replicant is a great choice for developing in an open-source manner but might not be the best idea if you’re writing Android to be published on Play. But the option should be there. I’m also considering the idea of implementing SDK Administrative Task Shortcuts. These are commands that can be passed to Vagabond that will inflate to more robust tasks passed to the VM that maintain the SDK.

If all goes as planned, and work and life leave me alone long enough, I can potentially have this ready to go by the end of the week.

Another Vagabond Update

I wanted to take some time out from working on it to provide you with an update to the Vagabond project.

Recently I had some piqued interest on Twitter for the project and it’s lit a little more of a fire under my arse to get it going. I’d continued to work on it but I was putting in on the back-burner in favor of other projects that I’ve been working on. It’s safe to say that I’ve got enough interest now to get it done.

If you need another synopsis on it, please check out my previous post about what Vagabond is.

Changes

My PoC code was a shell script that did the whole thing for me. I’ve since migrated the project to C++ and am going to build both Debian and RedHat Packages and also provide a source tarball. After some consideration, I may actually take this and eventually migrate to a web-interface in Perl but I’m still not too sure yet. I’ve got too much work going into the C++ conversion that I need to stick with that and see where that takes me. Additionally, I’ve put the development branch up on my GitHub. The project is under the BSD 3-Clause License so you can do what you want with it so long as it carries the license and you don’t use my name on derived works without pinging me first.

Right now the project is sitting at about 3011 lines of code (tallying both insertions and deletions but the graph is laid out on the GitHub). This may seem inflated but I’m adhering to the 80-line gutter since I’m editing exclusively in vim and I hate the word wrap on there. Rightly this could be consolidated and I’d probably manage to shave off a hundred or so lines. A compilation is possible as it is now and the help feature is 100% complete. The create option is responsive to tests but doesn’t do anything useful at this point and the Vagrant Propagation command isn’t coded yet. Most of the code might seem redundant compared to the PoC but I wanted to use some of the more robust features of C++ like Exceptions and Namespacing for proper encapsulation.

I’m still looking to be able to have this done by the end of next week. At least a rev one. If anything comes up that keeps that from happening, I’ll change the date but I’m pouring nearly all of my free time into the project so I should be able to hit it.

Vagabond – Update

Aside from the getandroidsdkdl script that I was offering for people who wanted to get started with Android Development on Linux, another cool tool I wanted to throw out there was a script I call “Vagabond” which is a Vagrant deployable which automatically configures a development environment that you can use for Android Development on your Linux computer. In fact, it may prove far easier to use it instead of the getandroidsdkdl script (it actually builds off of it). The actual Vagabond script isn’t available yet but I’m letting a rather close circle of friends test it out first before I make it public which shouldn’t be too far off from now. I wanted to give an overview of what it does.

If you’re unfamiliar with Vagrant, follow the previous link to get a better understanding of what it is.

What is Vagabond?

Vagabond is little more than a bash script that you’ll download and execute. Once you execute it, all you’ll need to do is sit back and relax while it configures the VM, installs all of the requisite packages to both update the base VM and the required packages for the Android SDK, and then exposes the synced directory from the guest to the host via host’s PATH and that should take care of everything. The user can then install an IDE of their choice on the host and run the Android SDK tools from their host computer.

Got that? To further simplify, the purpose of the Vagrant image is to host and isolate the the Android SDK and to make it even more portable since it’ll exist exclusively in a VM. The Vagrant Provisioner Script, in tandem with the Vagabond Script, exposes the SDK hosted in the guest VM to the host machine. If it still doesn’t make any sense, you may need to read up on what Vagrant is so that it sinks in a little more.

Vagabond Usage

Vagabond is, and will continue to be, stupid simple to use. I’m planning on adding some additional features to it but for right now, it only requires that you provide it with a directory where you want Vagrant to install and configure the VM in. That’s it. The rest is up to the script.

vagabond.sh [vagrant-project-directory]

Vagabond Details

Vagabond relies on three different pieces of software – Vagrant, Git and Zenity. It will check for the existence of these three on the computer before attempting to do anything. If either one of these are missing from the computer, the script will fail and return an error code specific to whichever program was missing. These codes are detailed in the comments in the script.

Clearly, the reliance on Vagrant should be rather obvious. Git needs to be installed since Vagabond will pull down the Vagrantfile and bootstrap provisioning script from my GitHub. Zenity is used to display the output from Vagrant while it’s running the VM configuration and provisioning script. The choice to use Zenity was made since the output from the provisioning script couldn’t easily be piped back to the terminal that was running Vagabond. I’m still not really sure why this was the case but that’s what was happening. If I can figure it out, or if someone a bit more skilled at bash scripting than myself modifies the source, I’ll yank the Zenity dependency out of there. I can’t say I don’t entirely dislike it though.

Vagabond then attempts to make the directory that the user specified while launching the script. No real magic here. The only thing is that it will check to see if the directory exists prior to running mkdir. Some may see it as a redundant check since mkdir will cater to already existing directories but I wanted some conditionally verbose output. Sue me.

Next Vagabond will move into the new directory and use Git to clone from my GitHub repository that contains the Vagrantfile and bootstrap Provisioning Script. Details on the Vagrantfile can be found if you read the Vagrant documentation. The purpose of the bootstrap script will also become evident as well. At least what it does with regard to Vagrantfile. Cloning from the GitHub will make a vagabond directory inside the directory the user specified for the Vagrant Project and we don’t want that. Vagabond will move the cloned files out of the cloned vagabond directory into the Vagrant Project directory and then remove the cloned directory.

At this point, we’re ready to use Vagrant. Now that Vagrantfile and bootstrap are in place, a call to vagrant up will use the Vagrantfile to configure the VM. Vagrantfile will then rely on bootstrap to supply additional configurations and instructions to the VM. The Vagrant Box used is the hashicorp/precise32 (Ubuntu Precise 32-bit). All other Vagrant configurations are defaults. The bootstrap Provisioning Script does the following:

  • Update apt repositories
  • Upgrade the system as well as install base dependencies for the Android SDK
  • Use a modified version of my getandroidsdkdl script to download the Android SDK from Google. This script will also unpack the SDK into /opt in the VM and configure permissions on it.

Once this is done, Vagabond will expose the synced directory, which is linked to the directory in the VM that contains the SDK, to the host system via a modification to PATH. That’s it. After that, so long as the VM is running, the host will have access to the SDK. The user can download and use whatever tools they want. Since the SDK exists exclusively in the VM, you can port the VM to anywhere you want.

What’s Next?

As I mentioned before, I’m letting a few people test this before I give it GA. Once I get those test results back and make some modifications to the script based on those tests, the version will be locked as 1 and released for GA. Stay tuned!

Development Journal – Smsr Update 001

I’d like to think that I started working on a rough draft with Smsr and then it evolved into something else.

This “rough draft” had a bit of code in it encapsulated in an entity called ConversationThread. A function of this class in particular was really nasty since what it did was take all of the SMS messages on the device and effectively organize them in a cohesive manner that didn’t rely on querying sub-providers like Sms.Inbox or Sms.Sent. The reasoning behind this was that when I would query some of the more specific Content Providers, like Sms.Conversations, the Cursor returned from that query would only contain three fields regardless of the applied projection. In other words, despite the fact that the contract class inherited from base interfaces that gave it the additional fields you’d want, this inheritance doesn’t apply to what’s returned from queries against the provider because these columns are missing from the Cursor. So it wouldn’t contain things like ADDRESS or _ID. And because these Content Providers weren’t designed with the ability to perform SQL Joins via queries (despite the fact that the documentation would lead you to believe so), the only other alternative, really, is to perform several separate queries against several different Content Providers and join them using either MatrixCursor or CursorJoiner. The issue there is (A) how to do this without blocking on the UI thread and (B) because subsequent queries would rely specifically on information that was contained in previous queries, how then to make sure that the queries had completed before attempting to use them?

I really tried to avoid the solution where multiple queries were involved because it just seemed so… lackluster. Not to mention that the idea of tossing back and forth between five or six Cursors seemed like an explosion in the works. But there was a major issue with the way I was doing it originally – real-time updates. Because the backing data was effectively abstracted into this seemingly convoluted construct that didn’t directly bind to the backing data, if something changed in the data (i.e. received a new text message), the structure would effectively have to be completely rebuilt. One pass on building that thing was expensive enough since it relied heavily on Collections. Doing it over and over again could lead to some really janky issues.

So I went back to the drawing board. And what I came out with, after struggling for a bit to understand MatrixCursor, was a solution that does in fact query multiple Content Providers which will yield several Cursors and then combines them into a MatrixCursor which is then given to my custom CursorAdapter. The result here also adds to a modified layout for the Conversation Stubs which uses a LayerDrawable to get the contact’s image (default if none) and apply a gradient over top of it that leads to the other half of the list.

Unfortunately, this change has broken the Activity that will show the Conversation Thread because the data that’s now contained in the stubs is different than what that Activity was looking for in the first place. But the stub viewer looks nice! 😀

If you want to follow along, the branch that this work is being done on is the “rewrite” branch.

https://github.com/gregfmartin/smsdemo/tree/rewrite

Development Journal – Smsr

The SMS client that I’ve been working on for Android is now being renamed to Smsr (even though the root directory of the project will still say sms_demo).

I’ve uploaded the source code to Github so feel free to take a look at the source, fork or do whatever the hell you want with it. I’m going to be updating the contents of the wiki and the project landing page as major changes are made to the upstream build.

http://gregfmartin.github.io/smsdemo/

Development Journal – Android SMS App

For the longest time, I’ve been wanting to write a SMS app for Android. The issue originally (and still is unfortunately) was that if you’re running a device that has a version of Android less than KitKat (4.4.x), a programmer doesn’t have access to native public-facing APIs to get access to these Content Providers. Instead you have to rely on the Reflection APIs to poke around for them and, if they’re there, use them that way. It might not seem like it at first but Reflection can be a bit heavyweight on more resource-constrained devices (which can potentially toss ANRs or even cost battery cycles) and also makes for some really nasty looking code. I’ve worked on several projects where Reflection was the order of the day (especially for things like accessing Enterprise Configurations in WifiManager) but unless I really had no other choice, I tried to stay away from the Reflection solution as much as possible. Even going to the lengths of not writing this SMS app I wanted to do for so long because there wasn’t a public API for it. Enter KitKat with these packages and now I’m going to town.

Putting aside the fact that Google likes to arbitrarily break your code with new upstream versions, the package that contains the contract classes for these Content Providers, android.providers.Telephony, is actually quite solid. Unless they go ape-shit on this package like they did with ContactsContract (which is an absolute fucking nightmare to work with), we should be okay for the time being.

I’ll save the technical discussion for another post (or even a video) but what I wanted to do here was showcase the current state of the build that I have for the SMS app. Honestly I’ve spent more time trying to figure out the nuances of the contracts and how to use them and fucking around with 9-Patch than anything else (9-Patch is cool technically but why can’t someone at Google make decent documentation?) Additionally, I wanted to provide a tentative roadmap for where this is going.

A listing of all Conversation Stubs
A listing of all Conversation Stubs

Here’s a screen capture of the home screen which will display what I refer to as the “Conversation Stubs.” No, those aren’t native constructs in Android, it’s a custom object that I’ve built for this app. The goal here was simple – after doing all the magic necessary to sort the messages to have them make sense, grab the most recent one and from it derive the contact’s display name and a 45-character snippet of the message body. If the snippet length equals 45-characters, an ellipsis is appended to it to indicate that there’s more to the message than what’s visible. What’s missing here is an indication that the message was sent from you to the intended recipient (coming in the next nightly build). By the way, I swear I didn’t plan the colour of the ActionBar to match that of my site. 😉

Pressing on one of the Conversation Stubs will bring you to another screen which will display the entire Conversation Thread.

A Conversation Thread listing
A Conversation Thread listing

As with Conversation Stub, a Conversation Thread is not a native construct to Android. Now if you’ve done a little digging into the package yourself, you might be thinking why not just use the Conversation Contract? I’ll do more on that in the technical discussion.  Although there are no clear visual cues as to who said what, messages that have been sent from you to the recipient are on the right side and messages from the recipient to you are on the left. Each message is time-stamped currently using 24-hour format (this will be customisable in a later build). The thread recipient’s display name occupies the ActionBar in the top-left. The list of messages is sorted in descending order from the top and will automatically start from the bottom when opened which will display the most recent messages. Right now, there’s not much else here other than what you see.

 

Current, if short, Preferences
Current, if short, Preferences

The last point of interest here is the slowly building Preferences. One of my targets here is to have a decently high level of customisation while still retaining the overall look-and-feel of the app that I want. The bottom option is the more interesting one right now. As I mentioned before, KitKat will allow a user to specify an app to be the dedicated Messaging app. Of course I want the user to be able to choose this one as the default if they wish to do so. Pressing this brings up a dialogue that will allow you to choose the default app.

Overall, the goal here is quite simple. I prefer as vanilla of an experience on my Android devices and I like the Google Play Services and default apps but I have a serious beef with Hangouts. It just feels too clunky and I wanted something a little more back-to-basics. The current build cannot actually compose or send SMS yet (coming in two builds) nor can it determine or store draft messages (coming in a build after the previously mentioned one). MMS is also not yet handled but is coming shortly. I do not want to do anything fancy like integrate with Google Accounts like Hangouts does. I want this to be a pure unadulterated SMS/MMS experience. Nothing more.

Some tentative features that I have in mind though are sticky messages, cherry-pick deletion, hidden threads, export a conversation thread to a file (I’ve actually had a lot of interest in this from some clients for legal reasons) or print a conversation thread directly to a printer (relies on Android Print Services) or email a conversation thread to an email address, bulk messaging (one-to-many) and group messaging (many-to-many).

I’ll do a technical discussion on how to use the SMS Contracts and all of the nuances that I’ve discovered with them soon. Either way, I’m looking to have a first version published by the end of the month.