安裝
- Add InsForge dependencies to your project
- Maven Central
- GitHub Packages
build.gradle.kts:
repositories {
mavenLocal() // For local development
mavenCentral()
}
dependencies {
implementation("dev.insforge:insforge-kotlin:0.1.6")
}
First, create a GitHub Personal Access Token:
- Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Select permission:
read:packages
Option A: Environment Variables
Option A: Environment Variables
settings.gradle.kts (or build.gradle.kts):build.gradle.kts:Set environment variables before building:
repositories {
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/InsForge/insforge-kotlin")
credentials {
username = System.getenv("GITHUB_USER") ?: ""
password = System.getenv("GITHUB_TOKEN") ?: ""
}
}
}
dependencies {
implementation("dev.insforge:insforge-kotlin:0.1.6")
}
export GITHUB_USER="your-github-username"
export GITHUB_TOKEN="your-personal-access-token"
Option B: gradle.properties (Local Development)
Option B: gradle.properties (Local Development)
Add credentials to your global Gradle properties file:~/.gradle/gradle.properties:settings.gradle.kts:build.gradle.kts:
gpr.user=your-github-username
gpr.token=ghp_xxxxxxxxxxxx
repositories {
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/InsForge/insforge-kotlin")
credentials {
username = providers.gradleProperty("gpr.user").orNull ?: ""
password = providers.gradleProperty("gpr.token").orNull ?: ""
}
}
}
dependencies {
implementation("dev.insforge:insforge-kotlin:0.1.6")
}
The
~/.gradle/gradle.properties file is stored outside your project, so credentials won’t be accidentally committed to version control.- Initialize InsForge SDK
import dev.insforge.createInsforgeClient
import dev.insforge.auth.Auth
import dev.insforge.database.Database
import dev.insforge.storage.Storage
import dev.insforge.functions.Functions
import dev.insforge.realtime.Realtime
import dev.insforge.ai.AI
val client = createInsforgeClient(
baseUrl = "https://your-app.insforge.app",
anonKey = "your-api-key"
) {
install(Auth)
install(Database)
install(Storage)
install(Functions)
install(Realtime) {
autoReconnect = true
reconnectDelay = 5000
}
install(AI)
}
- Enable Logging (Optional)
import dev.insforge.InsforgeLogLevel
val client = createInsforgeClient(
baseUrl = "https://your-app.insforge.app",
anonKey = "your-api-key"
) {
// DEBUG: logs request method/URL and response status
// VERBOSE: logs full headers and request/response bodies
logLevel = InsforgeLogLevel.DEBUG
install(Auth)
install(Database)
// ... other modules
}
| Log Level | Description |
|---|---|
NONE | No logging (default, recommended for production) |
ERROR | Only errors |
WARN | Warnings and errors |
INFO | Informational messages |
DEBUG | Debug info (request method, URL, response status) |
VERBOSE | Full details (headers, request/response bodies) |
Use
NONE or ERROR in production to avoid exposing sensitive data in logs.Android Initialization
- Add Chrome Custom Tabs dependency to your
build.gradle.kts:
dependencies {
implementation("androidx.browser:browser:1.9.0")
}
- Initialize InsForge SDK (With Chrome Custom Tabs and Session Storage)
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import dev.insforge.createInsforgeClient
import dev.insforge.ai.AI
import dev.insforge.auth.Auth
import dev.insforge.auth.BrowserLauncher
import dev.insforge.auth.ClientType
import dev.insforge.auth.SessionStorage
import dev.insforge.database.Database
import dev.insforge.functions.Functions
import dev.insforge.realtime.Realtime
import dev.insforge.storage.Storage
class InsforgeManager(private val context: Context) {
val client = createInsforgeClient(
baseUrl = "https://your-app.insforge.app",
anonKey = "your-anon-key"
) {
install(Auth) {
// 1. Chrome Custom Tabs - opens in-app, similar to iOS ASWebAuthenticationSession
browserLauncher = BrowserLauncher { url ->
val customTabsIntent = CustomTabsIntent.Builder()
.setShowTitle(true)
.build()
// Handle non-Activity context safely
if (context is Activity) {
customTabsIntent.launchUrl(context, Uri.parse(url))
} else {
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
customTabsIntent.launchUrl(context, Uri.parse(url))
}
}
// 2. enable session persistence
persistSession = true
// 3. config SessionStorage (use SharedPreferences)
sessionStorage = object : SessionStorage {
private val prefs = context.getSharedPreferences(
"insforge_auth",
Context.MODE_PRIVATE
)
override suspend fun save(key: String, value: String) {
prefs.edit().putString(key, value).apply()
}
override suspend fun get(key: String): String? {
return prefs.getString(key, null)
}
override suspend fun remove(key: String) {
prefs.edit().remove(key).apply()
}
}
// 4. set client type for mobile
clientType = ClientType.MOBILE
}
// Install Database module
install(Database)
// Install Realtime module for real-time subscriptions
install(Realtime) {
debug = true
}
// Install other modules
install(Storage)
install(Functions)
install(AI)
}
}
- Use Jetpack DataStore for Session Storage (Optional)
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
val Context.authDataStore: DataStore<Preferences> by preferencesDataStore(name = "insforge_auth")
class DataStoreSessionStorage(private val context: Context) : SessionStorage {
override suspend fun save(key: String, value: String) {
context.authDataStore.edit { prefs ->
prefs[stringPreferencesKey(key)] = value
}
}
override suspend fun get(key: String): String? {
return context.authDataStore.data.map { prefs ->
prefs[stringPreferencesKey(key)]
}.first()
}
override suspend fun remove(key: String) {
context.authDataStore.edit { prefs ->
prefs.remove(stringPreferencesKey(key))
}
}
}
// Then use it in your InsForge client
install(Auth) {
browserLauncher = ...
persistSession = true
sessionStorage = DataStoreSessionStorage(context)
}
心智模型
Kotlin SDK 透過 Socket.IO 連線到 InsForge 即時系統。訂閱頻道名稱(如order:123 或 chat:room-1),然後監聽發佈到這些頻道的事件名稱。
事件由資料庫觸發程式發佈,這些觸發程式呼叫 realtime.publish(...) 或由已加入頻道的用戶端發佈。有關頻道和 RLS 模型,請參閱即時概述。
快速開始
import dev.insforge.realtime.models.SocketMessage
client.realtime.connect()
val response = client.realtime.subscribe("order:$orderId")
if (!response.ok) {
println("Subscribe failed: ${response.error?.message}")
return
}
client.realtime.on<SocketMessage>("status_changed") { message ->
message?.let {
println("Status changed: ${it.payload}")
}
}
connect()
建立即時連線。client.realtime.connect()
println("Connected: ${client.realtime.isConnected}")
println("Socket ID: ${client.realtime.socketId}")
client.realtime.connectionState.collect { state ->
when (state) {
is Realtime.ConnectionState.Connected -> println("Connected")
is Realtime.ConnectionState.Connecting -> println("Connecting")
is Realtime.ConnectionState.Disconnected -> println("Disconnected")
is Realtime.ConnectionState.Error -> println("Error: ${state.message}")
}
}
subscribe()
訂閱頻道並接收目前在線狀態快照。val response = client.realtime.subscribe("chat:room-1")
if (response.ok) {
println("Subscribed to: ${response.channel}")
println("Members: ${response.presence?.members}")
} else {
println("Error: ${response.error?.message}")
}
publish()
將事件發佈到頻道。client.realtime.publish(
channel = "chat:room-1",
event = "new_message",
payload = mapOf(
"text" to "Hello from Kotlin",
"sentAt" to System.currentTimeMillis()
)
)
用戶端必須訂閱頻道才能向該頻道發佈。
realtime.messages 上啟用了 RLS,發佈也會根據 INSERT 原則進行檢查。
on()
註冊事件接聽程式。client.realtime.on<SocketMessage>("new_message") { message ->
message?.let {
println("Message: ${it.payload}")
}
}
| 事件 | 說明 |
|---|---|
presence:join | 邏輯成員在頻道中變為在線。 |
presence:leave | 邏輯成員不再在頻道中在線。 |
realtime:error | 訂閱或發佈失敗。 |
once()
僅監聽一次事件。client.realtime.once<SocketMessage>("checkout_completed") { message ->
println("Checkout completed: ${message?.payload}")
}
off()
移除事件接聽程式。val callback = Realtime.EventCallback<SocketMessage> { message ->
println("Event received: $message")
}
client.realtime.on("status_changed", callback)
client.realtime.off("status_changed", callback)
unsubscribe()
離開頻道。client.realtime.unsubscribe("chat:room-1")
disconnect()
關閉即時連線。client.realtime.disconnect()
getSubscribedChannels()
傳回本機訂閱的頻道。val channels = client.realtime.getSubscribedChannels()
println(channels)
在線狀態
成功的訂閱會傳回在線狀態快照。監聽presence:join 和 presence:leave 以更新本機在線狀態。
在線狀態是暫時的。它不是一個持久的房間成員身份表。