DEV Community

Nathan Epstein
Nathan Epstein

Posted on

My experience bringing an HTML5 game to Android via Cordova

Last year I made a little html5 game in a style similar to 2048, with some key differences. You can play it here. https://aeium.github.io/729/ This post is going to be about my experience porting that game to android, and publishing it on the play store. For the purposes of this post I think it makes sense to focus more on the underlying technology than the specific UI/design of the game, which might be better to save for another post if I do an update.

729 game

When I first posted the web version of the game on facebook, I noticed that some of my friends were posting scores and screenshots, so it seemed like a leaderboard would be a natural addition to the game.

The most straightforward way to proceed, given what I already know, would probably be to provision some kind of ec2 instance in AWS, and configure a back end for the page in either nodeJS or flask. However, this would have been expensive, and it seemed unlikely that donations to the game would cover the cost of constantly keeping that server online.

The next choice would be to use just a database, and define some AWS lambda routes to update and query a leaderboard database that way. This route seemed to be a great choice because I would not need to pay for the downtime when the ec2 instance would be doing nothing. It'd also be a chance to learn a new technology, which seems to be pre-eminently useful for this kind of task.

This was the option I was favoring, when a friend reminded me to consider the apple app store and google play store. Both stores have free services for games, including exactly the kind of leaderboard features I was gearing up to build myself. Nice. Also, the app stores had a unique sort of property where they would (potentially) pay me instead of me paying them for that service. That is also pretty nice.

The downside for that was the game is was mainly javascript, but also had some basic DOM based html and css. I knew that react native was a popular framework for building apps with web technology, but I did not use react to build the game so that would mean a refactor, which I wanted to avoid.

I promised my friend that I would take a look for lightweight solutions to port the game over to Android. If I could avoid a total refactor, it seemed like it was worth a try.

One thing that I found was the Phonegap build service, which was based on Cordova. It was an free service that can compile phone executables from webpages, and the first project is free. I was honestly sort of skeptical that it would work. I added their default config.xml file to the repository, and clicked the button to receive my .apk file (compiled android executable).

https://github.com/Aeium/729/blob/master/config.xml

I was actually shocked that it worked right way. I just added a boilerplate config.xml for an android app, and the build service gave me QR code URL to download the apk to my phone. I had a working version compiled literally minutes after deciding to try to port the webpage to the phone, something that I did not expect at all.

Some minor things had broken, like the links at the bottom, but the game itself is pretty simple and had been designed to display properly on the phone originally and that same formatting was still working. All that the Phonegap/Cordova software seemed to be doing was launching a little mini-browser app that just only displayed a local version of the game’s webpage, which was basically exactly what I needed.

Next I just needed to make some tweaks, connect the leaderboard game services plugin, submit the compiled apk to google, and it seemed like I might be done with the project in one day. From this point the finished product seemed tantalizingly close, which is always a nice way to start. Seldom do things really turn out to be that way, but even when things get more complicated and there are setbacks, having that clear sense of where you going is always good.

Between that point and actually publishing the game on the play store, there were two major and somewhat inter-related problem to overcome, related to getting the debugger and also google play game services leaderboards to work.

Roadblock #1:

Native Webview Debugger

The first problem to solve was simply establishing a working development environment where I could access the console output when my javascript code executed on the phone. Normally this is as simple as opening the page in a browser and then opening the console in the browser.

There is a phone “emulator” built in to chrome which you can use to preview the webpage before sending it through the Cordova toolchain. This is sufficient for much of the development you need to do, because Cordova does a pretty good job of faithfully displaying the same page once it goes through the toolchain.

simulated chrome mobile view

That is not completely sufficient for this project though. I’m putting “emulator” in quotes, because it’s not really emulating the phone, but more so simulating the kind of webviews that a phone would have. This is really useful for most of what you need to do but it’s not possible to access the native features of the phone through that sort of simulation. They simply are not there.

I wanted to integrate the Google Play Games services plugin, and that plugin uses native features of the phone. For that, the development would need to take place in a real (or fully emulated) phone.

Doing some research, I found that google chrome has another tool that can assist with this as well. Under developer tools, if you go to “more tools” then “remote devices”, it’s possible to connect to your phone and access the developer tools menu for webviews as they are running inside the phone, including Cordova applications. Pretty cool!

remote device webview debugging tool in Chrome

But this was where I ran into my first big roadblock. The phone was showing up, and its browser webviews were showing up, but my application’s webview was not. The problem was that the executable I got from phonegap build service was in production mode. Cordova has two modes, debug and production. In the production mode, connecting to the internal webview is disallowed. This is actually a good thing, because the debugger javascript console is very powerful. If that was allowed to connect to any production Cordova application, it would be very easy to hack them to pieces. I.e. for my game that would mean editing the board or submitting bogus scores to the leaderboard.

The phonegap build service did have a “debug” option, but even when that option was checked the application still did not show up as a webview for my device. I still don’t know why, but because I could not open the hood for the build service and figure out what was going on, this was a showstopper.

So, I have the Phonegap build service to thank for putting me tantalizingly close to my objective and motivating me, but I found that I could not quite go the distance using that build service alone.

What I ultimately decided to do was install the Cordova command line, and configure a project where I would be able to compile the .apk files locally, and thereby open up the hood a bit and see if I could get debuggable phone executables (.apk files) that way.

The simplest way to do this is install android studio. I, like some of you probably, have no interest in learning a specialized IDE for this specific task. All I wanted was a project folder that I can configure properly file by file, and build my apk from there via the command line. In my experience, this is a general and effective way to make sense of multiple different kinds of software projects. To me that seems much simpler to edit parameters in configuration files than watching videos about how to navigate graphical idiosyncrasies of Android Studio.

The Cordova command line was great for creating that workflow that I wanted, but installing android studio is still the easiest way to get the android SDK. The android SDK has tools required for Cordova to work, and it also has some tools you need as well, like adb (in the platform tools folder).

So, after installing a recent jdk, the android sdk (via installing android studio, which you don’t actually need to use), and the Cordova command line, once that environment is established building the executables yourself is not difficult.

Solution 1:

Use Cordova CLI instead of phonegap build service.

This solved the problem I was experiencing with the Phonegap build service where I could not connect to my applications webview via the remote devices debugger. I don’t really know what was different, but the debug mode worked when I compiled them locally. Getting access to that felt really nice.

My workflow for developing on the phone was still not ideal, I would compile an apk via the cordova command line, uninstall the old version from my phone, which would disconnect my remote debugger, and then re-install it via adb, open it, and then I would need to connect the debugger again. That to me seems like a lot of legwork, and not the kind of process I want if I need to iterate on a problem.

However, the flipside of that is for most of the development you need to do with this kind of technology, you don’t even need to bring to the phone at all. Most of what you need to do you are just building a phone-formatted webpage, for which the chrome pseudo-emulator works great. This tedious workflow only needed to integrate the native cordova plugins.

RoadBlock #2:

Signatures and Auth for Game Services

After establishing this process, I felt ready to integrate the google play game services plugin, and add the leaderboards to my game. Here I ran into a second problem. The game services plugin could not connect to the service. I had my debugger, so I knew that the function call to connect to google game services was failing inside the module, and returning it’s default failure callback when I tried to connect.

Ultimately this ended up being an auth problem. In order to configure google play game services, there are a few things you need to sort out inside various google developer consoles.

First, you need to create the application in the google play developer console. From here you can navigate your game services and get an app ID number and feed this number to the Cordova game services plugin in the config.sml file. This I had done.

Also, in order to upload the apk to google play, you need to sign it. This means generating a private key. I used the keytool program for this, which comes with the java SDK. With this private key, you are able to give your compiled apk a particular signature, and then google will be able to recognize this signature later on future versions. Great, that is what we want.

However, I ran into a very curious obstacle here, that was very reminiscent of the problem I had previously getting the remote debugger to connect. When you build an executable (.apk in this case) with cordova, there are two different modes, debug and production. The debug mode will allow the connection to the remote debugger, and the production one will not.

When you are compiling the apk, it’s possible to provide a private key for it to use to sign the compiled output. Generally your production version will be signed with your personal private key, and the debug version will be signed with a standard debug key. It's also possible to build an unsigned production version and add the signature afterwards, both methods work fine.

I wanted to connect to google play game services while in debug mode. The reason why my play game services plugin could not connect is because google was expecting to see my unique production signature, and not the debug signature.

I researched this a bit, and found that it was possible to configure Cordova to use a different key to sign the debug mode executable. Strangely, this simply did not work for me. Regardless of how I configured the project, I found the debug executable was still getting signed by the debug key. I’m actually still not exactly sure what happened here, maybe a bug.

So, as a result of that I was stuck again. I could compile a production version that could connect to google play services signed with the proper key, or I could compile a debug version with the debug key and connect to my debugger. I could not do both.

Solution 2:

Edit expected signature in credentials via Google Developer Console.

The breakthrough that I had was I remembered that it’s possible to change the expected signature in the google API developer console. So, instead of compiling the debug mode with the production key, I simply changed the expected key on the other side to the debug one.

It's critical to understand here that this is an altogether different console from the google play developer console. The console you need to edit the expected signature is the google developer console console, not the google play console you need to use to before this step.

Ensure that you have the right project selected, navigate to credentials, and then you can tell it (paste in) what SHA-1 signature it should expect for the existing credential, or add a new credential.

If you don't know what the debug signature is, it's possible to unzip your debug APK and use keytool to read the sigature. For that I'll refer you to this.

Once I did this, I was able to connect to google play game services while the phone was also connected to the remote debugger. Hooray!

I actually ran into a very similar problem again right before I was ready to publish the game. As I did some final testing, I switched google play game services API credential to expect the production key instead of the debug key. However I made an oversight here. The signature that you send with the apk is how you identify yourself to the play store when you submit the your executable to the play store, but it's not the signature that google sends out with your executable when they go to the end users.

There is a third key that signs the executables that get distributed, and google removes the signature of your private key. So there are three signatures involved. First, there was the debug signature which I was stuck with for my debug version. Second, there was my signature that identified to the play store that I was really the author of what I was submitting. Third, there is google's signature that verifies that it's apps really were distributed by google. This is the signature that the end user apps will be signed with, and the one the API should be expecting ends users to have after release.

I was basically just completely roadblocked again by this issue, and was just clicking around in the console until I found the “App Signing” tab under release management. In this tab it detailed two certificates, the app signing certificate and the upload certificate. As soon as I saw that, I knew switching the api to expect the "end user" app signing signature instead of the my personal "production" upload signature would fix the problem.

To be clear, I will include an image detailing where you need to find this key.

Where the key lives

This is the signature that must match one of the credentials you defined in the google developer console for your API of choice, (game services in my case) to connect, much the same way the debug signature was needed to connect with the debug version.

It might also be a good idea to remove the debug key authorization after you have released the game.

In hindsight it makes sense that there is a separate certificate on outbound vs inbound apps so to speak, but it certainly surprised me nevertheless.

Those are the major roadblocks I hit publishing this app, and how I got over them. There were a few more minor problems I needed to solve, but this post is long enough just covering the big issues I ran into.

Overall I had a good experience with Cordova. It's difficult to compare and contrast this with completely native app development, since I don't have experience doing that, but I really appreciate that there is a workable and fairly lightweight tool that can transform webpages into native phone apps.

You can find the Android version here or via the QR code below if you want test your mettle on the leaderboards. Thanks for reading.

729 link

Top comments (0)