Frame
Frame entry point, platform factories, and lifecycle hooks in the Nativeblocks DSL.
A frame is a single function that returns a NativeblocksFrame. The CLI locates it by the fixed name frame(). One frame function per file.
Entry point
fun frame(): NativeblocksFrame = androidFrame(name = "name", route = "/route") {
// variables, lifecycle, rootBlock
}
The frame file extension is .kt (Kotlin), .tsx (TypeScript), or .swift (Swift). Never add an entry point (main, @main), the CLI injects its own runner at deploy time.
Platform factories
| Platform | Kotlin | TypeScript | Swift |
|---|---|---|---|
| Android | androidFrame(name, route) { } | androidFrame({ name, route }) | androidFrame(name:route:) { f in } |
| iOS | iosFrame(name, route) { } | iosFrame({ name, route }) | iosFrame(name:route:) { f in } |
name: PascalCase. For example:"ProductDetail","CheckoutFlow"route: kebab-case path. For example:"/product-detail","/order/{orderId}"
The platform factory ties the frame to a platform, so its rootBlock and slots accept only that platform's blocks.
Lifecycle hooks
onAppear runs when the frame mounts; onDisappear runs when it unmounts. Both are optional and take actions.
androidFrame(name = "Home", route = "/home") {
onAppear {
script { _, updateVariable, _ -> updateVariable(loadingVar, "true") }
}
onDisappear {
script { _, updateVariable, _ -> updateVariable(loadingVar, "false") }
}
rootBlock { /* ... */ }
}
Full example
profile-android.kt
package com.example.app.frames
import com.example.app.generated.shared.*
import com.example.app.generated.integration.android.Script.script
import com.example.app.generated.integration.android.nativeblocks.button.nativeblocksButton
import com.example.app.generated.integration.android.nativeblocks.column.NativeblocksColumn
import com.example.app.generated.integration.android.nativeblocks.column.nativeblocksColumn
import com.example.app.generated.integration.android.nativeblocks.image.NativeblocksImage
import com.example.app.generated.integration.android.nativeblocks.image.nativeblocksImage
import com.example.app.generated.integration.android.nativeblocks.spacer.nativeblocksSpacer
import com.example.app.generated.integration.android.nativeblocks.text.nativeblocksText
fun frame(): NativeblocksFrame = androidFrame(name = "Profile", route = "/profile") {
val avatarUrl by remember("https://example.com/avatar.jpg")
val username by remember("John Doe")
val bio by remember("Mobile engineer")
val isFollowing by remember(false)
val followLabel by remember("Follow")
onAppear {
script { _, updateVariable, _ ->
updateVariable(followLabel, "Follow")
}
}
rootBlock {
nativeblocksColumn(
blockKey = "main",
width = NativeblocksColumn.WidthOptions.Match,
height = NativeblocksColumn.HeightOptions.Match,
horizontalAlignment = NativeblocksColumn.HorizontalAlignmentOptions.Center,
content = {
nativeblocksSpacer(blockKey = "topSpacer")
nativeblocksImage(
blockKey = "avatar",
imageUrl = avatarUrl,
width = NativeblocksImage.WidthOptions.Wrap,
scaleType = NativeblocksImage.ScaleTypeOptions.Fit,
)
nativeblocksText(blockKey = "nameText", text = username, fontSize = "20")
nativeblocksText(blockKey = "bioText", text = bio, fontSize = "14")
nativeblocksSpacer(blockKey = "gap")
nativeblocksButton(
blockKey = "followButton",
label = followLabel,
onClick = {
script { getVariable, _, _ ->
"""
let f = ${getVariable(isFollowing)} !== "true";
updateVariable("${isFollowing.key}", String(f));
updateVariable("${followLabel.key}", f ? "Unfollow" : "Follow");
""".trimIndent()
}
},
)
nativeblocksSpacer(blockKey = "bottomSpacer")
},
)
}
}
Deploy
# Development
nativeblocks frame deploy --file src/profile-android.kt --watch
# Production
nativeblocks frame deploy --file src/profile-android.kt --tag v1.0.0
--tag marks the deployed frame as a named release version; --tag and --watch are mutually exclusive.