一键导入
android-native-bridge
Expert in bridging native Android code (Kotlin/Java) with React Native and Flutter applications.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Expert in bridging native Android code (Kotlin/Java) with React Native and Flutter applications.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | android-native-bridge |
| description | Expert in bridging native Android code (Kotlin/Java) with React Native and Flutter applications. |
| source_type | agent |
| source_file | agents/android-native-bridge.md |
Migrated from agents/android-native-bridge.md.
references/... or workflow/..., are packaged beside this SKILL.md.agents/..., commands/..., scripts/..., resources/..., rules/..., hooks/..., or templates/..., are packaged at this plugin root.skills/orchestration/...) is packaged under source/skills/orchestration/... for exact-reference lookups; all other Telar skills exist here only as the generated adapters under the plugin-root skills/ directory.../.. when reading support files or running packaged scripts..codex/agents/ in the source repository.Expert in bridging native Android code (Kotlin/Java) with React Native and Flutter applications.
Follow the clean-code skill: reuse existing shared units before writing new ones; unify duplication only when sites change together for the same reason (do not force-merge coincidental similarity); keep to simplicity-first (no speculative abstraction). The Maintainability reviewer enforces this.
Kotlin Module Setup:
// CalendarModule.kt
package com.myapp.calendar
import com.facebook.react.bridge.*
import kotlinx.coroutines.*
import android.provider.CalendarContract
class CalendarModule(
private val reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
override fun getName() = "CalendarModule"
@ReactMethod
fun createEvent(
title: String,
startDate: Double,
endDate: Double,
promise: Promise
) {
scope.launch {
try {
val contentResolver = reactContext.contentResolver
val values = ContentValues().apply {
put(CalendarContract.Events.TITLE, title)
put(CalendarContract.Events.DTSTART, startDate.toLong())
put(CalendarContract.Events.DTEND, endDate.toLong())
put(CalendarContract.Events.CALENDAR_ID, 1)
put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id)
}
val uri = contentResolver.insert(
CalendarContract.Events.CONTENT_URI,
values
)
val eventId = uri?.lastPathSegment
promise.resolve(Arguments.createMap().apply {
putString("eventId", eventId)
})
} catch (e: Exception) {
promise.reject("CALENDAR_ERROR", e.message, e)
}
}
}
override fun onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy()
scope.cancel()
}
}
// CalendarPackage.kt
class CalendarPackage : ReactPackage {
override fun createNativeModules(
reactContext: ReactApplicationContext
): List<NativeModule> {
return listOf(CalendarModule(reactContext))
}
override fun createViewManagers(
reactContext: ReactApplicationContext
): List<ViewManager<*, *>> = emptyList()
}
Event Emitter (Kotlin):
class LocationModule(
private val reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {
override fun getName() = "LocationModule"
private fun sendEvent(eventName: String, params: WritableMap?) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit(eventName, params)
}
@ReactMethod
fun startTracking() {
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(reactContext)
val locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY,
10000L
).build()
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
result.lastLocation?.let { location ->
sendEvent("onLocationUpdate", Arguments.createMap().apply {
putDouble("latitude", location.latitude)
putDouble("longitude", location.longitude)
putDouble("accuracy", location.accuracy.toDouble())
})
}
}
}
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
@ReactMethod
fun addListener(eventName: String) {
// Required for RN event emitter
}
@ReactMethod
fun removeListeners(count: Int) {
// Required for RN event emitter
}
}
Kotlin Method Channel:
// MainActivity.kt
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.EventChannel
class MainActivity : FlutterActivity() {
private val BATTERY_CHANNEL = "com.myapp/battery"
private val BATTERY_STREAM = "com.myapp/battery_stream"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Method Channel
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, BATTERY_CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"getBatteryLevel" -> {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available", null)
}
}
else -> result.notImplemented()
}
}
// Event Channel for streams
EventChannel(flutterEngine.dartExecutor.binaryMessenger, BATTERY_STREAM)
.setStreamHandler(BatteryStreamHandler(this))
}
private fun getBatteryLevel(): Int {
val batteryManager = getSystemService(BATTERY_SERVICE) as BatteryManager
return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
}
}
// Stream Handler
class BatteryStreamHandler(
private val context: Context
) : EventChannel.StreamHandler {
private var eventSink: EventChannel.EventSink? = null
private var receiver: BroadcastReceiver? = null
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
eventSink?.success(level)
}
}
context.registerReceiver(receiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onCancel(arguments: Any?) {
receiver?.let { context.unregisterReceiver(it) }
eventSink = null
receiver = null
}
}
Encrypted SharedPreferences:
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
class SecureStorage(context: Context) {
private val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
private val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
fun saveToken(token: String) {
prefs.edit().putString("auth_token", token).apply()
}
fun getToken(): String? = prefs.getString("auth_token", null)
}
WorkManager for Background Tasks:
class SyncWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// Perform sync
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// Schedule work
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
15, TimeUnit.MINUTES
).setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"sync_work",
ExistingPeriodicWorkPolicy.KEEP,
syncRequest
)
End-to-end orchestrated execution. Takes a feature description and drives the entire pipeline — plan, plan review (3 fresh reviewers), WU decomposition, 4-phase execution loop per WU, final review, COMMIT-READY emit. Honors user's git policy (no auto-commit).
`--default-domain` comes from the project-detect framework signal (orchestrator Step 5b / project-context); it only decides how UI files with no strong path marker are classified. `--risk-tier` is the WU's `risk_tier` fi
**Capture the WU baseline ONCE per WU, before attempt 1 (NOT on retries).** This is what makes file-scope checks correct across a multi-WU run where the user has not yet committed prior WUs (per the `ben yapacagim` git p
This gate has **two interchangeable execution paths that MUST emit the identical aggregated verdict object** (Step 3). The prose path below is the canonical fallback and the single source of truth for reviewer prompts an
A baton-based system for building mobile features across multiple Claude Code sessions with persistent progress tracking and simulator verification between steps.
Set up end-to-end testing framework with CI integration