Kotlin Turbo Module

Implementing a Turbo Native Module in Kotlin

The module class extends the generated spec and overrides each method; the Kotlin is kept minimal here, and Android with Kotlin teaches the language properly:

native/android/share/BookShareModule.kt: the module (excerpt)Kotlin
class BookShareModule(context: ReactApplicationContext) : NativeBookShareSpec(context) {
  private val prefs = context.getSharedPreferences("book_share", Context.MODE_PRIVATE)
  override fun getName() = NAME
  // Promise<boolean> in the spec: the last parameter is a Promise to settle
  override fun shareBook(title: String, url: String, promise: Promise) {
    Log.d(NAME, "shareBook on thread ${Thread.currentThread().name}")
    val activity = reactApplicationContext.currentActivity
    if (activity == null) {
      promise.reject("E_NO_ACTIVITY", "BookNest is not in the foreground")
      return
    }
    val send = Intent(Intent.ACTION_SEND).apply {
      type = "text/plain"
      putExtra(Intent.EXTRA_TEXT, "$title $url")
    }
    activity.startActivity(Intent.createChooser(send, "Share $title"))
    prefs.edit().putInt("count", prefs.getInt("count", 0) + 1).apply()
    promise.resolve(true)                                  // the sheet opened
  }
  // A synchronous method; Codegen declared its Int32 result as a Java double
  override fun getShareCount(): Double {
    Log.d(NAME, "getShareCount on thread ${Thread.currentThread().name}")
    return prefs.getInt("count", 0).toDouble()
  }
  // ...companion object { const val NAME = "NativeBookShare" }

The two Log.d lines show where calls run. After one app start and one tap on a Share button (Calling Native Modules), logcat held:

Reading the module's log linesShell
adb -s emulator-5554 logcat -d -s NativeBookShare:D
Output
--------- beginning of main
09-25 01:44:15.804  2824  3220 D NativeBookShare: getShareCount on thread mqt_v_js
09-25 01:44:41.392  2824  3221 D NativeBookShare: shareBook on thread mqt_v_native
09-25 01:44:41.654  2824  3220 D NativeBookShare: getShareCount on thread mqt_v_js

The synchronous method ran on the JavaScript thread itself (mqt_v_js), so a slow one freezes the whole UI's logic; the promise-returning one ran on React Native 36,878 's native-modules thread (mqt_v_native). Neither is Android's main thread, so touching views needs runOnUiThread; starting an activity is allowed from any thread. Settle every promise exactly once: a forgotten one leaves an await hanging forever, and reject's first argument becomes the JavaScript error's code. And true only means the chooser opened: Android does not tell the app whether the user finally shared, so the count really means "share sheets opened".