Blockstack Android Tips
Tags: blockstack, android, kotlin, blockchain
Published: 2019-07-25 11:25:44

When developing the [Envelop Android app][0] using the [Blockstack Android library][1], I ran into some important gotchas. I wanted to share them for whoever starts on the same path.

[0]: https://play.google.com/store/apps/details?id=app.envelop
[1]: https://github.com/blockstack/blockstack-android

---

## 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:

```kotlin
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`:

```kotlin
val blockstackScheduler = Schedulers.from {
  handler.post(it)   
}
```

For example, here’s how we wrap a `deleteFile` operation with RxJava:

```kotlin
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](https://github.com/blockstack/blockstack-android/pull/153) to fix it. But until then, we’re using our [own fork](https://github.com/sdsantos/blockstack-android).

## 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](https://developer.android.com/training/app-links/verify-site-associations).

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][3]. I’ll be keeping an eye on there too.

Curious about what a Blockstack app is like? Try out our [Envelop Android app][4], and look into our app’s [source code][5].

[3]: https://github.com/blockstack/blockstack-android
[4]: https://play.google.com/store/apps/details?id=app.envelop
[5]: https://github.com/envelop-app/envelop-android