Skip to content

Towards a native maps plugin for PhoneGap/Cordova and Android

I recently did some prototyping for a native maps plugin for Android.  For iOS/phonegap, you have the mapkit plugin which I was able to get working on phonegap 2.0, with some help from the google group.  But for Android, the concensus seems to be that you should use the web version of Google Maps (either the javascript version or the static map images).  While that advice works for a subset of users, if you pull out your Android phone and compare the performance between the web version of Google Maps and the native app, you’ll quickly choose the native app.

There are two paths forward for a native map plugin.  The main limiting factor is that a native map view is only instantiable by a MapActivity,”because it depends on threads which access the network and filesystem in the background; these threads must be shepherded by the lifecycle management” of the MapActivity.

So, you can either:

  • have your app be managed by a MapActivity and embed a Cordova webview in the app.  This would probably work well for apps that are really really map heavy, and only have a slight bit of webUI.  I’m not sure what value PhoneGap brings to that type of app, though.  It also seems pretty complex.
  • or have the PhoneGap app transition from DroidGap activity to the MapActivity and then back.
I went with the second choice.  As I said, this was an exploration, so there are plenty of problems that I skipped that will need to be solved to have a robust plugin:
  • which activity/technology gets the points to display initially
  • which activity/technology gets points as the map is moved around
  • testing on a real device (what do you do when you are running an Android device without native Google maps)
  • passing full featured events back and forth between PhoneGap and the MapActivity

 

Nine years of blogging

Wow, it is hard to believe it has been nine years since my first post.  This is the 660th post!

When I started my blog, I was just back from a sabbatical in Australia, living in a rented basement.  Now I’m a family man with a house.  When I started, I was a contractor, happy to get $40/hr to do development, tracking time and invoicing using MS word docs.  Now I use google docs for almost everything, am an employee, and manage a department.

The benefits of blogging keep me going.  I encourage everyone I meet to start a blog, because I think the act of writing forces you to crystallize your thoughts.  It has certainly crystallized mine.  I also enjoy the historical record, much like a public journal, and the projects I can look back on.  Plus, it is fun to occasionally hear someone say ‘I ran across a post you wrote’.

My blog has been much more about broadcast than conversation.  I think that’s because it varies in content, and in quality, and in timeliness.  The couple of posts that have blown up were due to them turning into forums on a controversial topic (Yahoo Mail problems, Skadate review).  But I’m OK with that.

I wish I had twice the time to write, but am happy that I’ve had the time I’ve had.

Thanks for reading!

The trigger creator sends emails when a google form is submitted and email is sent

Google Forms are a great way to collect data.  You can have the form do any number of things using Google Apps Script when the form is submitted, including sending email.

If you want the email to come from a certain person, you can’t manipulate that in the script you write.  (There’s nothing in the mail API doc about a ‘from’ field.)  You can modify the reply to header, but if you want an email to come from one person, you need to have that person create the on form submit trigger, because they are then the active user.

Java address parsing gets an upgrade

I wrote last year about address parsing solutions in java, and how an open source project call JGeocoder had worked out well for us.  I wanted to announce that my company, 8z, has significantly improved the address parsing capability of JGeocoder based on data from a number of property listings.

My colleague, Karamjeet Khalsa, added this functionality as well as more than fifty unit tests.  An address that previously would have failed but now is parsed correctly is: 25266 Road 38.1 Dolores CO. Or try this one: 10 Black Bear Gypsum CO.  This code focuses on not just parsing address, city and state, but also breaking apart the address into components like street number, unit number, etc (for US style addresses).

Working with the current maintainer of the project, Karamjeet uploaded the new jar yesterday, and it is now ready to download.  This is the first release in four years, so if you need address parsing, go take a look!

A Tale of Two Mobile App Development Program Applications

I just can’t believe the difference in the application process between Google (for Google Play) and Apple (for the App Store).

For Google, I had to

  • sign in to a Google account
  • give them an email address and a phone number
  • agree to terms and conditions
  • pay $25 (but make sure you have a valid Google Wallet account!)
  • wait for the registration to be processed
  • invite other developers in my company

For Apple (where I need to register as a corporation) I had to

  • Upgrade a mac to Lion
  • Start the signup process
  • Realize that the company doesn’t have an updated Dun and Bradstreet profile
  • Call Dun and Bradstreet
  • Be sent to http://iupdate.dnb.com/ to update the profile
  • Find out who the executive officers of the company were
  • Get them to sign up to update the profile
  • Update the profile
  • Submit it
  • Wait for over 5 business days
  • Resubmit my application to Apple
  • Get rejected again because they didn’t recognize the company as a legal entity
  • Exchange a couple of emails with Apple employees
  • Determine what the rejection is possibly because I didn’t want for D&B to update the Apple database (up to 14 business days!)

And all that is before I can see (and agree to) the terms of use and pay the $99/year, and get my application processed.

Whew.

Running async tests with qunit and sinon

I ran into an issue running async tests with qunit and sinon.  For a primer on doing this, see this great article.

Basically, the asyncTest never returned.  This manifested itself in the html view of the tests like this (left is success, right is where the test never returns–note the white):

Turns out that sinon-qunit adapter has sinon fake the browser timer, so setTimeout doesn’t work as expected.

To fix, just turn off the timer faking for a single test: this.clock.restore() or sinon.config.useFakeTimers = false to disable this for all tests.

Google Analytics Goals and Forms on Google Sites

I recently put together a website for my father’s new book about World War II, and choosing Google Sites was a slam dunk.  I choose a neutral theme, set up a few pages, uploaded some images and logged into Go Daddy (where my father had purchased his domain name) and set up DNS.  Easy peasy.

Two issues came up.  One minor and one major.

First, there is no easy way to point the bare domain at google sites using Go Daddy’s tools.  So seesaw1942.com can’t be redirected to www.seesaw1942.com.  Minor bummer, but just make sure all the marketing contains www.seesaw1942.com

I set up a form to capture email addresses for people who wanted to be informed when the book was actually published (it is now!).  I was interested in playing around with PPC to drive people to the website, but wasn’t able to set up a goal in Google Analytics to measure signup success.  (So I didn’t end up setting up PPC.)

I looked around and didn’t find anything that would help with this.  Here’s an article about goals and Google Forms, but the writer’s form lives on their own server, which gives them more latitude than someone working with Google Sites.

Anyone have any idea how to do this?

Geolocation and the Android 2.3.3 emulator

Just so someone else doesn’t waste an afternoon banging their head against a wall, here’s how to make the Android 2.3.3 emulator work if you want to access geolocation.  This applies to the javascript apps I’m writing–I don’t know if a native app would have the same issue.

  1. Install an Android 2.2 AVD (2.3.3 doesn’t work with geolocation).  Make sure you enable the GPS in your hardware settings when setting up the AVD.  That’s right, the first step to making the Android 2.3.3 emulator work is to downgrade to Android 2.2.  Why would you want to target 2.3.3+?
  2. Make sure you add <uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” /> to your Android manifest.
  3. Add <uses-feature android:name=”android.hardware.location.gps” android:required=”false” /> just to be sure.
  4. Start your emulator and install your software.
  5. telnet localhost 5554 (if you don’t have telnet installed on Windows 7, here’s how to enable it).
  6. In the telnet window, type in “fix geo -101 50”.  Note that you can’t use the backspace, so cutting and pasting is your best option.  Also note that longitude is before latitude.
  7. Execute the action that requires a geolocation.  (If using phonegap, make sure to pass these options to the geolocation call: { enableHighAccuracy: true }.)

You should see a GPS satellite in the notification bar of your emulator.

Also, note that each time you execute the action that calls the geolocation service of your phone, you have to type the ‘fix geo…’ line in the telnet session.

I also found this page useful for testing.

Simple REST database solutions

I’ve been looking for a simple solution to generate a REST api for a mysql database, with minimal to no coding.  I need to be able to do simple inserts and updates, and some simple querying (including for number ranges and or clauses).

The options are few and none seems to entirely fit the bill.

  • RestSQL is a java layer that has a simple XML configuration.  It supports some advanced features (triggers for biz logic, table composition) but doesn’t yet have numeric comparisons for gets.
  • DBSlayer is a C program that doesn’t do REST, but does JSON results for SQL queries over HTTP
  • PHPRest is a RESTful interface.  From the docs, it is not clear if it supports JSON or any queries more complex than by primary key.

Small scale data migrations

So, I’ve recently been involved in another data migration, the second one in three years.  These are small migrations, with thousands records.  One person to take care of this size of data migration with some effort, but the amount of data is still large enough that manual data re-entry isn’t really an option–the error rate and the cost and the management difficulty mean that software is the better option.

Here are some lessons I learned from these data migrations.

Learn as much as you can about the data models–both the old and the new–as you can.  This includes, in preferred order, talkingto any people familiar with the old system, talking to any people familiar with the new system, looking at the databases via a sql client, reading documentation (if any is written), and looking at code.  I spent some time thrashing around in old system code for a while.  Then I asked the developer for a tour, and learned more in that hour than I had in the previous day of looking at code.

Map entities and concepts as early as you can.  Take special note of any that are in the old and not in the new (and what you are planning to do with them).  Those that are in the new and not in the old aren’t as big of an issue.  Also, attributes of entities are as important as entities, so note discrepancies there.  Early on I noticed that one of the two primary entities in the old system did not exist in the new system.  This led to some interesting conversations with the business users that saved me work.

As above, talk to people who are going to be using the new system, and who use the old system, throughout the migration process.  An entity or attribute that will be a royal pain to migrate may not be used anymore!  Or, the business person might have some good ideas on how to map something in the old system into the new system.  Someone who uses the software you are migrating has more domain expertise than you.  Let them try the new system with migrated data as soon as some data is moved. Make sure to guide their experience so they don’t spin their wheels looking in corners of the system that not yet migrated.

Start a spreadsheet of tasks, so that everytime you uncover something that needs to be done while you are in the process of doing something else, you can note it and keep on your original task.  My spreadsheets are simple; three columns are enough: task name, completed (with an X for completion, blank for still open) and notes (for possible implementation solutions, people to talk to, relevant urls, or any other text that will help me complete the task).

Document all the migration steps, preferably to the point you can cut and paste commands.  Include any discrepancies discovered, special commands to run, access to all needed systems, names of relevant people, areas that need further investigation, and basically anything else you would want handed to you if you were starting on this project.  This helps immensely if you need to pass off the project, or come back to it later (even just a few days), and provides documentation of entities on the old and new system.

Write scripts wherever possible, but don’t try to script the whole process–access to different servers can be hard to automate.  Use whatever language you feel is best for these scripts.  I’ve used bash, sql, perl, and awk/sed, but I don’t shy away from a compiled language like java, especially if a library exists that can save me time.  Make sure to put these scripts into version control, and document the purpose with comments at the top and a good name.  I wouldn’t worry too much about unit testing or refactoring this software, because chances are it will be seldom used once the migration occurs.

Get familiar with the concatenate function of your database.  Using queries to write DDL for the new system based on data from the old system can save you writing a script in an imperative language.  When migrating from Expression Engine to WordPress, I used a statement like <code>select concat(‘update wp_comments set comment_author_email = ”’,email,”’ where comment_author = ”’,name,”’;’) from exp_comments where name in (select distinct(name) from exp_comments);</code> to generate an update statement for WordPress for each comment author in the EE database.

Think about data types and representations.  Especially if you are moving from one database to another.  When I was moving from MSSQL to MySQL, date fields were particularly thorny.

Realize that these types of projects are typically difficult slogs.  There were moments where I despaired of ever getting through the migration in a timely fashion.  To do it right, you need a fantastic attention to detail, an understanding of the business needs, and an ability to drive things through to the finish.  All of this can be pretty draining–I find it far more draining than bug fixing or building new features.

Control the old and new systems–try to not have new capabilities added during the migration.  If you can’t guarantee that, can the migration wait until the new and old systems stabilize?  If not, checkpoint the migration against the new capabilities during the process, and realize that you are introducing a lot of extra work and complexity into an already complex process.

Have a staging system where you can practice your migrations without affecting anyone.  Plan to go through at least two or three of these new staging systems so that you can get the migration steps solid before you touch production.  Start from a clean slate each time so no time is spent chasing phantom bugs from a previous migration that didn’t finish or wasn’t entirely correct.  This is what makes the migration documentation you write so important.  Be aware that the new stage system and the new production system will not necessarily be the same.

Lastly, avoid committing to a schedule if at all possible.  And if you must, pad it and only commit after you’ve done a thorough analysis.  Because there are so many hidey holes and areas of the old system that you won’t understand, there is a high probability that you’ll be discovering new issues and data you need to migrate halfway through the project.  (This is a special case of the requirements nightmare known as ‘build system B that acts exactly like system A’.)  Communicate progress to the business.

While this is not my favorite type of project, when done well it can have tremendous business value.  Combining newer, more flexible systems with rich older data, without re keying the data, can make system users much happier.  In some cases, if there is no migration, the newer system simply can’t be used.