← Back to Finn
AgentFinn

Skill · Version 1.0.0

Mobile native integration

Defines reliable boundaries between cross-platform application code and platform-specific native capabilities.

mobile-native-integration

See how it helps

When is it useful?

Use when a feature needs an SDK or device function beyond existing framework APIs.

What does it help you do?

  • Chooses the integration mechanism supported by the actual project.
  • Specifies typed requests, threading, cancellation and error propagation.
  • Updates native manifests and build configuration without losing existing setup.

Try asking this

Integrate a native document scanner with cancellation and explicit errors when the capability is unavailable.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Native Platform Integration

Encapsulate iOS (Swift / Objective-C / SwiftUI) and Android (Kotlin / Jetpack Compose) platform APIs behind narrow, type-safe interfaces so application screens and domain logic remain portable and testable.

1. Choose the right native integration mechanism

  • Check existing SDK & community modules first: before writing custom native code, verify whether an official Expo SDK module, RN community package or Flutter plugin already supports the capability.
  • When custom native code is required:
    • Expo / React Native:
      • Prefer the Expo Modules API (Module DSL in Swift and Kotlin with Function, AsyncFunction, Events, View) for clean lifecycle hooks and automatic type bridging.
      • In bare React Native on the New Architecture, define typed Codegen specs (specs/Native<Name>.ts extending TurboModule with TurboModuleRegistry.getEnforcing<Spec>) and Fabric view components.
    • Flutter:
      • Prefer Pigeon (@HostApi() / @FlutterApi()) to generate type-safe Dart, Swift and Kotlin contracts without untyped dictionary casting.
      • When using MethodChannel or EventChannel directly, namespace channel names (com.example.app/<feature>), validate argument maps, and handle PlatformException and MissingPluginException.
    • Pure Native (SwiftUI / Jetpack Compose):
      • On iOS, isolate hardware/OS frameworks (AVFoundation, CoreLocation, LocalAuthentication, StoreKit, BackgroundTasks) in @MainActor or actor-isolated service protocols injected into @Observable view models.
      • On Android, isolate Context-bound system services, ActivityResultLauncher contracts and BroadcastReceiver registrations behind repository/controller interfaces injected via Hilt/Koin/manual DI.

2. Design a resilient boundary contract

  • Single cross-platform wrapper: expose one domain-level TypeScript or Dart module (biometricVault.ts, documentScanner.dart). UI components must never branch on raw iOS NSError domains or Android Intent extras.
  • Capability & simulator fallback: expose an explicit availability check (isAvailableAsync()) and degrade gracefully on iOS Simulator, Android Emulator without Google Play Services, or older OS versions (if #available(iOS 17, *), Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE).
  • Threading & lifecycle discipline:
    • Never block the iOS main thread (DispatchQueue.main) or Android main looper (Dispatchers.Main) with file I/O, image transcoding, encryption or synchronous IPC.
    • Clean up native event emitters, NotificationCenter observers, BroadcastReceiver instances and hardware sessions when the JS/Dart listener detaches or the host Activity / UIViewController pauses.

3. Native project configuration, manifests and build safety

  • iOS (Info.plist, *.entitlements, Podfile, Xcode):
    • Add specific NS...UsageDescription keys for every protected capability, required UIBackgroundModes, Associated Domains (applinks:) and Privacy Manifest declarations (PrivacyInfo.xcprivacy required reason APIs).
  • Android (AndroidManifest.xml, build.gradle(.kts), proguard-rules.pro):
    • Declare minimal <uses-permission> entries, <uses-feature android:required="false" /> when hardware is optional (so Google Play does not hide the app on tablets/devices without that sensor), Android 14+ android:foregroundServiceType attributes, and @Keep / ProGuard rules for classes serialized across the bridge in release builds.
  • Expo CNG rule: in managed/prebuild projects, encode all Info.plist, entitlement and AndroidManifest.xml changes in app.json / app.config.ts or a Config Plugin (withInfoPlist, withAndroidManifest) so npx expo prebuild --clean stays reproducible.
  • Release impact: any native code, Podfile, Gradle or manifest change requires a new binary build (and a runtimeVersion bump for OTA updates).

Before you finish

  • Native bridge wrapped behind a single typed service with simulator and OS fallbacks.
  • Heavy native work runs off the main thread; native observers and hardware sessions cleaned up.
  • iOS (Info.plist, PrivacyInfo.xcprivacy, entitlements) and Android (AndroidManifest.xml, foregroundServiceType, ProGuard/R8) configs complete.
  • Requirement for a new native binary build documented in the handoff.

Included files 2

  • LICENSE.txt
  • SKILL.md