Blockstack Android Tips
When developing the Envelop Android app using the Blockstack Android library, I ran into some important gotchas. I wanted to share them for whoever starts on the same path.
Starting out
The library is still pre-release, but it’s built upon the more stable blockstack.js library. That means is also not a native library. It uses the j2v8 engine to interpret and interact with the javascript library.
The two main consequences are:
- Your app will weight around 20Mb more due to the blockstack library
- You need to be careful when you initialize a
BlockstackSession
. It takes a while for it to be ready to use.
Threading
The library threading is configured by an Executor
. It defines 3 threads, the main thread, the background thread and the V8 thread that runs the javascript library.
By default, the V8 thread uses the main thread. But for a production app, that means blocking the main thread on every operation, something definitely not recommended. To avoid this, you should define a new Executor
and set it on the BlockstackSession
. Here’s an example:
class BlockstackExecutor(
private val context: Context
) : Executor {
private val handlerThread = HandlerThread("BlockstackV8").apply { start() }
private val handler = Handler(handlerThread.looper)
override fun onV8Thread(function: () -> Unit) {
handler.post {
function.invoke()
}
}
override fun onMainThread(function: (ctx: Context) -> Unit) {
GlobalScope.launch(Dispatchers.Main) {
function(context)
}
}
override fun onNetworkThread(function: suspend () -> Unit) {
GlobalScope.launch(Dispatchers.IO) {
function()
}
}
}
But now you need to make sure you’re calling the blockstack operations for the thread you just created. If, for example, you’re using RxJava, that means building a custom Scheduler
for that thread, and using it in subscribeOn
:
val blockstackScheduler = Schedulers.from {
handler.post(it)
}
For example, here’s how we wrap a deleteFile
operation with RxJava:
fun deleteFile(fileName: String) =
Completable
.create { emitter ->
try {
blockstack.deleteFile(fileName, DeleteFileOptions()) {
if (it.hasErrors) {
emitter.onError(Exception(it.error))
} else {
emitter.onComplete()
}
}
} catch (t: Throwable) {
emitter.onError(t)
}
}
.subscribeOn(blockstackScheduler)
Network Errors
In the current library version (0.4.3), there’s a bug that hides network errors. They become indistinguishable from requests that are taking too long. There’s a pending PR to fix it. But until then, we’re using our own fork.
Context
In the examples given, BlockstackSession
is initialized with an Activity Context
. But for almost all Blockstack operations, the Application Context
. This is useful for taking that logic out of the Activity
classes and properly architecture your code.
But the login call redirectUserToSignIn
requires a BlockstackSession
with an Activity Context
. That’s because it opens a WebView from the inside. If you still want to use the Application Context
for all the other calls, just make sure the different BlockstackSession
instances share the same SessionStore
. That way, all BlockstackSession
instances read and store the session data from the same location.
APK signing
This one is not directly related with Blockstack, but something to keep an eye on. During login, users first sign in on Blockstack inside a WebView. Then the authentication response comes back to the Android app through an app link. For that process to be seamless, the app link should be automatically verified.
Google Play now encourages delegating the APK signing process to them. But that means that the sha256_cert_fingerprints
that ends up in the server assetlinks.json
file will not be the one you would expect. Your upload key signing gets removed from the APK. You need to fetch the correct fingerprint from your Google Play Dashboard under Release management > App signing
.
And that’s what I’ve got. Hope I didn’t scare you too much, it’s not that bad actually. Just some details that will likely be ironed out in the future. Any other issue, you can reach out on the library’s Github. I’ll be keeping an eye on there too.
Curious about what a Blockstack app is like? Try out our Envelop Android app, and look into our app’s source code.