native_kit

pub package pub points platforms license: MIT

One Dart call invokes the real OS-level UI. native_kit presents genuine system view controllers, sheets, zero-permission pickers and hardware scanners on iOS (UIKit / SwiftUI / VisionKit / PencilKit) and Android (Material 3 / Jetpack / ML Kit / system intents) — no Flutter look-alikes.

final result = await NativeKit.showAlert(
  context: context,
  title: 'Delete draft?',
  actions: const [
    NativeAlertAction.cancel(id: 'cancel', title: 'Cancel'),
    NativeAlertAction.destructive(id: 'delete', title: 'Delete'),
  ],
);
if (result?.actionId == 'delete') { /* … */ }
  • 30 unified components across 6 domains, 32 typed methods.
  • Clean Dart models — DateTime, Color, Rect, Uint8List and typed result classes. Transport DTOs are never exposed.
  • Context aware — pass a BuildContext and the native UI anchors on that widget (iPad-safe popovers) and follows the Flutter theme's brightness and primary color.
  • No hanging futures — swipe-to-dismiss, back and predictive-back gestures always resolve the call (with null, false or an empty list).
  • No MainActivity changes — Android activity results run through a headless fragment, even with a plain FlutterActivity.

Installation

flutter pub add native_kit
import 'package:native_kit/native_kit.dart';

Platform setup

iOS (16.0+)

Set platform :ios, '16.0' in ios/Podfile (Swift Package Manager is supported too). Add the usage descriptions for the components you use to ios/Runner/Info.plist:

Key Needed by
NSCameraUsageDescription scanDocument, scanCode, extractLiveText (camera)
NSMicrophoneUsageDescription, NSSpeechRecognitionUsageDescription listenSpeechPrompt
NSFaceIDUsageDescription authenticate on Face ID devices
NSCalendarsUsageDescription createCalendarEvent on iOS 16 only (iOS 17+ needs none)

Missing keys never crash the app: the call throws a NativeKitException with NativeKitErrorCode.missingUsageDescription.

Android (API 26+)

Set minSdk = 26 in android/app/build.gradle(.kts). That's it: the plugin ships its own manifest entries (a transparent host activity, a FileProvider, package-visibility queries and the install-time INTERNET, VIBRATE and USE_BIOMETRIC permissions). ML Kit models are downloaded by Google Play services on first use.

Architecture

            ┌──────────────────────── packages/native_kit ────────────────────────┐
 App code ─▶│ NativeKit.showAlert(context: …)  →  domain models → Pigeon DTOs     │
            └──────────────────────────────────┬──────────────────────────────────┘
                                               │ NativeKitPlatform (6 Pigeon host APIs)
            ┌──────────────── native_kit_platform_interface ──────────────────────┐
            │ pigeons/native_kit_api.dart → Dart / Swift / Kotlin                 │
            └───────────────┬─────────────────────────────────┬───────────────────┘
                            ▼                                 ▼
   native_kit_ios (Swift, @MainActor)              native_kit_android (Kotlin, coroutines)
   OverlaysHandler · ValuePickersHandler ·         same 6 handlers, Material 3 + Jetpack,
   ZeroPermPickersHandler · VisionAndMediaHandler  NativeKitResultFragment for every
   SystemUtilitiesHandler · SecurityAndHardware…   ActivityResultContract

Every call carries an optional NativeRect (the calling widget's global rect) and NativeThemeConfig (brightness + seed color) extracted from the BuildContext.

Components

Module 1 — Overlays

Dart method iOS Android
showAlert UIAlertController(.alert) + addTextField MaterialAlertDialogBuilder + TextInputEditText
showActionSheet UIAlertController(.actionSheet) (iPad popover) Material 3 BottomSheetDialog list
showContextMenu UIMenu via UIEditMenuInteraction ListPopupWindow at the anchor
showNativeTooltip .popover UIViewController with arrow Material 3 PopupWindow card with arrow
showAdaptiveSheet UISheetPresentationController detents BottomSheetDialog + BottomSheetBehavior

Module 2 — Value pickers

Dart method iOS Android
pickDateTime / pickDateRange UIDatePicker in a .medium() sheet MaterialDatePicker / MaterialTimePicker
pickColor UIColorPickerViewController (eyedropper, alpha) Material 3 sheet: preview, hex, ARGB / HSL sliders
pickValueWheel multi-column UIPickerView sheet NumberPicker row in a BottomSheetDialog
pickFont UIFontPickerViewController searchable system typeface sheet

Module 3 — Zero-permission pickers

Dart method iOS Android
pickMedia PHPickerViewController PickVisualMedia / PickMultipleVisualMedia
pickContact CNContactPickerViewController PickContact / ACTION_PICK + ContentResolver
pickDocument UIDocumentPickerViewController(forOpeningContentTypes:asCopy:) OpenDocument / OpenMultipleDocuments
saveDocument UIDocumentPickerViewController(forExporting:asCopy:) CreateDocument + stream write
createCalendarEvent EKEventEditViewController (.ics QuickLook on iOS 16) ACTION_INSERT on CalendarContract.Events
pickLocation MKMapView + MKLocalSearchCompleter sheet map sheet + android.location.Geocoder

Module 4 — Vision & media

Dart method iOS Android
scanDocument VNDocumentCameraViewController → JPEGs + PDFDocument ML Kit GmsDocumentScanner
scanCode DataScannerViewController / AVCaptureMetadataOutput GmsBarcodeScanner (no camera permission)
extractLiveText VNRecognizeTextRequest / DataScannerViewController(.text()) ML Kit Text Recognition + review sheet
extractImageSubject VNGenerateForegroundInstanceMaskRequest (iOS 17+) ML Kit Subject Segmentation
showMarkupSheet PKCanvasView + PKToolPicker low-latency Canvas full-screen dialog
trimVideo UIVideoEditorController trim sheet with MediaExtractor + MediaMuxer

Module 5 — System utilities

Dart method iOS Android
share UIActivityViewController Intent.createChooser + FileProvider
previewFile QLPreviewController PdfRenderer pager / ACTION_VIEW
openInAppBrowser SFSafariViewController (.pageSheet) CustomTabsIntent (Partial Custom Tabs)
printDocument UIPrintInteractionController (+ UIMarkupTextPrintFormatter) PrintManager + PrintDocumentAdapter / PrintHelper
showTranslationSheet SwiftUI .translationPresentation (iOS 17.4+) ACTION_PROCESS_TEXT / ACTION_TRANSLATE / TTS sheet
showDictionaryLookUp UIReferenceLibraryViewController ACTION_DEFINE / Partial Custom Tab search
listenSpeechPrompt SFSpeechRecognizer + AVAudioEngine sheet RecognizerIntent.ACTION_RECOGNIZE_SPEECH

Module 6 — Security & hardware

Dart method iOS Android
authenticate LAContext.evaluatePolicy BiometricPrompt / KeyguardManager
requestAppReview StoreKit AppStore.requestReview(in:) Play ReviewManager (+ store fallback)
triggerHaptic UIImpact/Notification/SelectionFeedbackGenerator, CHHapticEngine HapticFeedbackConstants, VibrationEffect
showSystemPanel AVRoutePickerView, NEHotspotConfigurationManager, MPVolumeView, RPScreenRecorder MediaRouter2 switcher, Settings.Panel.*, MediaProjectionManager

Usage

// Anchored, themed action sheet (popover on iPad).
final choice = await NativeKit.showActionSheet(
  context: buttonContext,
  items: const [
    NativeMenuItem(id: 'share', title: 'Share', iosSymbol: 'square.and.arrow.up'),
    NativeMenuItem(id: 'delete', title: 'Delete', style: NativeActionStyle.destructive),
  ],
);

// Zero-permission photo picker.
final List<PickedMedia> photos = await NativeKit.pickMedia(
  type: NativeMediaType.images,
  selectionLimit: 5,
);

// Native color picker returns a Flutter Color.
final Color? color = await NativeKit.pickColor(context: context);

// Document scanner returns page JPEGs and a combined PDF.
final DocumentScanResult? scan = await NativeKit.scanDocument();

// The instance API is the same surface, handy for dependency injection.
final NativeKitClient kit = NativeKit.instance;
await kit.triggerHaptic(HapticType.success);

Error handling

Cancellation is never an error. Real failures throw NativeKitException with a NativeKitErrorCode: noUiContext, unavailable (e.g. VisionKit on the simulator), invalidArgument, missingUsageDescription, permissionDenied, ioError or nativeError.

try {
  await NativeKit.scanCode();
} on NativeKitException catch (e) {
  if (e.code == NativeKitErrorCode.unavailable) showFallbackUi();
}

Platform notes

  • Files returned to Dart (media, documents, scans, cutouts, trimmed videos) are copies in the app's temporary / cache directory. Move what you keep.
  • pickLocation on Android renders OpenStreetMap tiles by default. Pass androidTileUrlTemplate to use your own tile server in production.
  • showSystemPanel(SystemPanel.screenCapture) records in-app on iOS (call it again to stop and receive the movie) and returns the MediaProjection consent result on Android.
  • showSystemPanel(SystemPanel.nfc) is Android only.

Packages

Package Purpose
native_kit App-facing API (this package)
native_kit_platform_interface Pigeon contract and NativeKitPlatform
native_kit_ios iOS implementation
native_kit_android Android implementation

License

MIT — see LICENSE.

Libraries

native_kit
One Dart call invokes the real OS-native UI on iOS and Android.