native_kit

pub package pub points CI 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, no Swift or Kotlin to write.

NativeKit.showActionSheet opening UIAlertController on iOS and a Material 3 bottom sheet on Android

final choice = await NativeKit.showActionSheet(
  context: context, // anchors the iPad popover + syncs your theme
  items: const [
    NativeMenuItem(id: 'share', title: 'Share', iosSymbol: 'square.and.arrow.up'),
    NativeMenuItem(id: 'delete', title: 'Delete', style: NativeActionStyle.destructive),
  ],
);

Why native_kit

Drawn by Flutter Drawn by the OS with native_kit
Date picker showDatePicker / CupertinoDatePicker look-alikes UIDatePicker on iOS, MaterialDatePicker on Android
Action sheet & menus Re-created widgets UIAlertController + UIEditMenuInteraction, Material 3 sheets + ListPopupWindow
Color picker Third-party widgets UIColorPickerViewController with the system eyedropper
OS redesigns (e.g. iOS 26 Liquid Glass) Wait for widgets to be re-implemented Picked up from the OS
Photos, contacts, documents Often require permissions Out-of-process system pickers, no permission prompts
Scanners, OCR, subject lift Camera plugin + ML wiring VisionKit / Vision and ML Kit in one call

One dependency covers photo / contact / document pickers, document saving, calendar events, a location picker, share sheet, QuickLook-style preview, in-app browser, printing, translation, dictionary, speech-to-text, biometrics, in-app review, haptics, system panels, document and barcode scanning, OCR, background removal, ink markup and video trimming.

See it run

The same Dart call on iOS (left) and Android (right), recorded from the example app by its UI test suites:

NativeKit.showAdaptiveSheet with detents on iOS and Android NativeKit.pickDateTime opening UIDatePicker and MaterialDatePicker NativeKit.showAlert destructive confirmation on iOS and Android

Highlights

  • 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.
  • Tested on real system UI — XCUITest and UI Automator suites drive every component on the iOS Simulator and an Android emulator.

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.

Missing a native component? Request it — new components are added to the shared Pigeon bridge for both platforms.

Libraries

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