Behind the Curtain: Inter-App Communication

I’ve been working on another Android app the past couple weeks. We’ve added a couple of features, included enhanced logging and a couple of night-mode themes.

One thing that has been often requested is a way to launch Scanner Radio from our app.
I got in contact with the developer of Scanner Radio and he gave me a snippet of code that allows Active911 to launch the Scanner Radio selector.
The main problem I’ve been working on overcoming today is how to store the Intent that is given back in the ActivityResult of the selector.

There’s not really a good way to serialize an Intent in Android, it seems that they are intended to be passed and immediately used.
The design pattern for most Inter-Process Communication is defining an Intent schema that can be used by external applications.
Another pattern used is exposing an external Service, which I haven’t looked into much.

Regardless, right now I have an Intent that, when used immediately, works as intended. However, I can only use that intent as long as the app is open, so I need to find a way to persist the Intent while maintaining all of its required information.

At first I tried just using the Intent.toUri() method. That gets me halfway there, as the URI still doesn’t contain any of the Extras in the Intent.
The next thing I tried was manually serializing the data into tab-delimited name value pairs. However, this doesn’t work as I don’t necessarily know if the extras are all Strings, as well as how many layers of nesting there are.

My final strategy is to take the Bundle and serialize it into a byte array, and then store that byte array as a UTF-8 string, then reversing the process to get it back out.
This stackoverflow answer was the most helpful in figuring out how to do so

The downside to this is that, since the class implementing Parcelable may change between platform versions, this is not guaranteed to work across system updates.
Also, after digging through the Parcel and Bundle source code, it seems that the Intent may be too large to serialize and deserialize in this way.

It looks as though the extras only has a single item, so instead I will be just serializing and deserializing this one item.
It contains a set of 3 name value pairs, so I will serialize that into JSON, though serializing it into byte data did work initially.

In the end, I ditched the Parceling and byte storing of the data, since that is highly discouraged, and just stored the name value pairs.
As long as the bundle doesn’t get deeper, have a change in the name of the extra, or use anything other than Strings in the sub-bundle it will work.

The Android update with a Scanner Radio setting is hitting our new Beta group today, and will likely be updated in the Google Play store next week.

Behind the Curtain: Goodbye TestFlight

With Apple’s acquisition of TestFlight’s parent company, we received notice that TestFlight will no longer serve up Android builds as of March 21st.

While unfortunate, we must persevere. I’ve begun looking at options for replacing TestFlight.

The first option I considered was switching over to just using Google Play for both Beta and Release versions.
This would allow all of our Android deployments to come from one place, though it would mean that users would have to choose between Beta and Release for all their devices, whereas they can have different devices using different versions currently.
Also, Google’s analytics are geared more towards user engagement and marketing rather than Beta testing.

The second option we are currently considering is a site called TestFairy. They immediately jumped on TestFlight’s recent announcement about discontinuing Android support by welcoming former TestFlight users, even providing hooks that allow apps which include the TestFlight SDK to not need any code change at all. A very smart move.
So far, in my 1 day of testing, I am fairly impressed with the polish and extensive metrics provided by TestFairy. Not only does it gather checkpoints that I’ve set, it is able to monitor memory, CPU, Network, Phone Signal Strength, Battery, and even allows for screencast recordings.

The one snafu that I encountered was Google Maps initially not working with our app. Sadly, the documentation is a bit lacking, though the interface is very clean and simple so it doesn’t matter so much for the most part.
In the end, I was able to figure out that, since TestFairy actually modifies our SDK to add in the metrics gathering, it has to sign itself with TestFairy’s signing key. There is a field under App > Settings > Signature that shows Facebook and Google API keys, which, upon mousing over, reminded me that I needed to add the TestFairy signed package to our Google Maps API allowed apps.

Overall, I am thoroughly impressed with TestFairy’s capabilities, if still a little weary of the fluffy name. Hopefully, unlike TestFlight, they won’t poof and disappear on us. I’ll be testing TestFairy for a couple more days, but expect us to switch over to using it for Beta next week.