⌘K

Fallback Handling

Handle missing blocks and actions gracefully when they are not registered in the app binary.

When a frame is fetched from the server, it may reference a block type or action type that is not registered in the current version of your app. This can happen when:

  • A new block or action was added via the CLI but the user has not updated the app yet
  • A block or action was removed from the binary but old frame definitions still reference it
  • A frame is deployed to a version of the app that does not have the matching registration

Without a fallback, unrecognised types fail silently or cause a blank space in the UI. Registering fallback handlers lets you control exactly what happens in those cases.


Fallback Block

A fallback block is rendered in place of any block whose keyType is not found in the registry.

NativeblocksManager.getInstance().provideFallbackBlock { keyType, name ->
    Box(Modifier.padding(8.dp)) {
        Text(
            text = "Missing block: $keyType ($name)",
            color = Color.Red
        )
    }
}

Fallback Action

A fallback action is invoked whenever an action type is triggered that has no registered handler.

NativeblocksManager.getInstance().provideFallbackAction { keyType, name ->
    Log.w("Nativeblocks", "Unhandled action: $keyType ($name)")
}

Production pattern: prompt users to update

Show users they need to update rather than hiding content silently. For missing blocks, show an inline prompt. For missing actions, present an alert or bottom sheet.

Fallback block

App.kt
NativeblocksManager.getInstance().provideFallbackBlock { _, _ ->
    val context = LocalContext.current
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .clip(RoundedCornerShape(12.dp))
            .background(MaterialTheme.colorScheme.surfaceVariant)
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Text(
            text = "Update required",
            style = MaterialTheme.typography.titleSmall,
            color = MaterialTheme.colorScheme.onSurface
        )
        Text(
            text = "This content is not supported in your current app version. Update to see it.",
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
        TextButton(onClick = {
            val intent = Intent(
                Intent.ACTION_VIEW,
                Uri.parse("market://details?id=${context.packageName}")
            )
            context.startActivity(intent)
        }) {
            Text("Update now")
        }
    }
}

Fallback action

App.kt
NativeblocksManager.getInstance().provideFallbackAction { _, _ ->
    val context = LocalContext.current
    AlertDialog.Builder(context)
        .setTitle("Update required")
        .setMessage("To use this feature your app needs to be updated to the latest version.")
        .setPositiveButton("Update") {
            val intent = Intent(
                Intent.ACTION_VIEW,
                Uri.parse("market://details?id=${context.packageName}")
            )
            context.startActivity(intent)
        }
        .setNegativeButton("Cancel", null)
        .show()
}

Debug vs. production

Use BuildConfig.DEBUG / #if DEBUG to switch between a developer-visible error and the user-facing update prompt.

App.kt
if (BuildConfig.DEBUG) {
    NativeblocksManager.getInstance().provideFallbackBlock { keyType, name ->
        Box(
            Modifier
                .fillMaxWidth()
                .padding(8.dp)
                .border(1.dp, Color.Red, RoundedCornerShape(4.dp))
                .padding(8.dp)
        ) {
            Text("Missing block: $keyType ($name)", color = Color.Red, fontSize = 12.sp)
        }
    }
    NativeblocksManager.getInstance().provideFallbackAction { keyType, name ->
        Log.w("Nativeblocks", "Unhandled action: $keyType ($name)")
    }
} else {
    NativeblocksManager.getInstance().provideFallbackBlock { _, _ ->
        // inline update prompt (see above)
    }
    NativeblocksManager.getInstance().provideFallbackAction { _, _ ->
        // update alert (see above)
    }
}

Parameters

ParameterDescription
keyTypeThe unique type identifier of the missing block or action
nameThe specific name/key assigned to block/action in the frame definition