You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/ff-concepts/existing-flutter/method-channels.md
+60-64Lines changed: 60 additions & 64 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ With MethodChannels, you can:
21
21
* Perform operations that need native performance or device-specific access.
22
22
* Return data from the native side into Flutter with low latency.
23
23
24
-
### Why this matters for native engineers {#why-this-matters-for-native-engineers}
24
+
**Why this matters for native engineers**
25
25
26
26
| What you need | How MethodChannel helps |
27
27
| :---- | :---- |
@@ -33,7 +33,7 @@ With MethodChannels, you can:
33
33
You’re not limited by what Flutter provides out of the box. MethodChannels lets you plug in your native knowledge exactly where needed, so you don’t lose years of platform experience when moving to Flutter.
34
34
35
35
36
-
## **What is a MethodChannel?** {#what-is-a-methodchannel?}
36
+
## What is a MethodChannel?
37
37
38
38
A **MethodChannel** is Flutter’s core mechanism for integrating platform-specific functionality. It allows Dart code to send messages to, and receive responses from, the host platform’s native code \- Android (written in Kotlin or Java) or iOS (written in Swift or Objective-C). This enables your Flutter app to access device features and third-party native libraries that are outside the scope of the Flutter framework or its plugin ecosystem. Here is an example of MethodChannel.
39
39
@@ -378,7 +378,6 @@ After implementing and testing your plugin:
378
378
379
379
Ensure your `pubspec.yaml` is correctly configured, and consider tagging releases for versioning.
380
380
381
-
---
382
381
383
382
**Step 2: Add the Plugin as a Dependency in FlutterFlow**
384
383
@@ -389,19 +388,22 @@ To integrate your custom plugin into a FlutterFlow project:
389
388
3. In the **Settings** panel on the right, scroll to **Dependencies**.
6. Implement the desired functionality using the plugin's API.
401
404
402
405
For detailed guidance, refer to FlutterFlow's documentation on [using unpublished or private packages](https://docs.flutterflow.io/concepts/custom-code/#using-unpublished-or-private-packages).
403
406
404
-
---
405
407
406
408
**Step 3: Utilize the Plugin via Custom Actions in FlutterFlow**
407
409
@@ -410,17 +412,20 @@ With the plugin integrated, you can now create Custom Actions to leverage its fu
410
412
1. Define a new Custom Action in FlutterFlow.
411
413
2. In the code editor, implement the action using your plugin. For example:
final batteryLevel =awaitMyCustomPlugin.getBatteryLevel();
418
+
return batteryLevel;
419
+
}
420
+
421
+
```
422
+
417
423
418
424
3. Compile the custom code to ensure there are no errors.
419
425
4. Use this Custom Action within your FlutterFlow project's action flows, just like any built-in action.
420
426
421
427
This approach allows you to encapsulate complex logic within reusable actions, enhancing modularity and maintainability.
422
428
423
-
---
424
429
425
430
### Managing Private Repositories
426
431
@@ -432,56 +437,52 @@ If your plugin repository is private, FlutterFlow needs access to it. As per Flu
432
437
433
438
MethodChannels are powerful but require careful implementation. When the Dart and native sides are not aligned, or error handling is overlooked, it often leads to runtime issues or silent failures. This section outlines the most common problems developers face with MethodChannels—especially in projects generated by tools like FlutterFlow—and provides actionable solutions to help you debug effectively and write resilient platform-channel integrations.
434
439
435
-
---
436
440
437
-
-**MissingPluginException**
441
+
### MissingPluginException
438
442
439
-
**Symptom:** Flutter throws a `MissingPluginException`, typically saying the plugin or method is not implemented.
443
+
**Symptom:** Flutter throws a `MissingPluginException`, typically saying the plugin or method is not implemented.
440
444
441
-
**What it means:** Flutter tried to invoke a method on the MethodChannel, but the native side did not recognize the channel or method name.
445
+
**What it means:** Flutter tried to invoke a method on the MethodChannel, but the native side did not recognize the channel or method name.
442
446
443
-
**Common causes:**
447
+
**Common causes:**
444
448
445
-
* Dart `MethodChannel` name does not match the native channel name.
446
-
* Native code handler (`setMethodCallHandler`) was never set up or was incorrectly placed.
447
-
* Custom native code was overwritten when re-downloading a FlutterFlow project without preserving changes.
448
-
* The method was invoked before the Flutter engine or the channel was fully initialized.
449
-
* Hot reload only updates Dart code, but not with native channel implementations.
449
+
* Dart `MethodChannel` name does not match the native channel name.
450
+
* Native code handler (`setMethodCallHandler`) was never set up or was incorrectly placed.
451
+
* Custom native code was overwritten when re-downloading a FlutterFlow project without preserving changes.
452
+
* The method was invoked before the Flutter engine or the channel was fully initialized.
453
+
* Hot reload only updates Dart code, but not with native channel implementations.
450
454
451
-
**How to fix:**
455
+
**How to fix:**
452
456
453
-
* Confirm that the channel name is **identical**in Dart and native code (case-sensitive).
454
-
* On Android, ensure the channel is registered inside `configureFlutterEngine()`.
455
-
* On iOS, set up the `FlutterMethodChannel` inside `didFinishLaunchingWithOptions()`.
456
-
* Log the available channels/methods to confirm registration during app startup.
457
-
* Native channel implementations require a full restart because the platform-specific code must be recompiled and relinked.
457
+
* Confirm that the channel name is **identical** in Dart and native code (case-sensitive).
458
+
* On Android, ensure the channel is registered inside `configureFlutterEngine()`.
459
+
* On iOS, set up the `FlutterMethodChannel` inside `didFinishLaunchingWithOptions()`.
460
+
* Log the available channels/methods to confirm registration during app startup.
461
+
* Native channel implementations require a full restart because the platform-specific code must be recompiled and relinked.
458
462
459
-
---
460
463
461
-
###
462
464
463
-
-**Incorrect Argument or Result Types** {#2.-incorrect-argument-or-result-types}
465
+
### Incorrect Argument or Result Types
464
466
465
-
**Symptom:** App crashes with type casting errors or returns `null` unexpectedly.
467
+
**Symptom:** App crashes with type casting errors or returns `null` unexpectedly.
466
468
467
-
**What it means:** The data passed between Dart and native does not match expected formats.
469
+
**What it means:** The data passed between Dart and native does not match expected formats.
468
470
469
-
**Common causes:**
471
+
**Common causes:**
470
472
471
-
* Dart sends an argument as a Map but native expects a String, or vice versa.
472
-
* Native code returns a platform object that can't be serialized by Flutter.
473
-
* The return value is not compatible with `StandardMessageCodec`.
473
+
* Dart sends an argument as a Map but native expects a String, or vice versa.
474
+
* Native code returns a platform object that can't be serialized by Flutter.
475
+
* The return value is not compatible with `StandardMessageCodec`.
474
476
475
-
**How to fix:**
477
+
**How to fix:**
476
478
477
-
* Only use standard types: `int`, `double`, `String`, `bool`, `List`, or `Map` with JSON-safe contents.
478
-
* On Dart side, specify the expected return type with generics: `invokeMethod<int>(...)`.
479
-
* On native side, validate input types before using them. Consider using try/catch or safe casting.
480
-
* Avoid sending complex objects like native SDK responses directly—convert to a simple dictionary or string.
479
+
* Only use standard types: `int`, `double`, `String`, `bool`, `List`, or `Map` with JSON-safe contents.
480
+
* On Dart side, specify the expected return type with generics: `invokeMethod<int>(...)`.
481
+
* On native side, validate input types before using them. Consider using try/catch or safe casting.
482
+
* Avoid sending complex objects like native SDK responses directly—convert to a simple dictionary or string.
481
483
482
-
---
483
484
484
-
### **3\.No Response or App Hangs** {#3.-no-response-or-app-hangs}
485
+
### No Response or App Hangs
485
486
486
487
**Symptom:** The Dart call to `invokeMethod()` never returns, or the UI freezes.
487
488
@@ -500,9 +501,7 @@ MethodChannels are powerful but require careful implementation. When the Dart an
500
501
* Offload slow operations to a background thread or coroutine (Kotlin) or dispatch queue (Swift).
501
502
* Use Dart timeouts or loading indicators to keep the UI responsive while waiting.
* Use `print()` or `NSLog()` to trace handler execution.
544
542
* Watch the Xcode console for startup logs or channel registration issues.
545
543
* Ensure you're calling `result(...)` correctly and only once.
546
544
* Check if the `AppDelegate` is properly casting `window?.rootViewController` to `FlutterViewController`.
547
545
548
-
---
549
546
550
547
By understanding and anticipating these pitfalls, developers can avoid common errors that derail Flutter-to-native communication. MethodChannels are extremely reliable when implemented correctly, and with structured debugging, most issues can be diagnosed and resolved quickly—even in FlutterFlow-generated apps where visibility into the build system may be limited.
551
548
552
-
## **Performance and Architecture Best Practices** {#performance-and-architecture-best-practices}
549
+
## Performance and Architecture Best Practices
553
550
554
551
Integrating native functionality through MethodChannels can bring significant value to your app \- but only if it’s done with performance and maintainability in mind. Below are the five most important best practices engineers should apply in real-world production apps, along with deeper insights into why each one matters.
555
552
556
553
**Important Context for FlutterFlow Users:** FlutterFlow generates clean Dart code and supports Custom Actions for inserting Dart logic, but it does not currently support inline native (Kotlin/Swift) editing.
557
554
558
-
### **1\. Don’t Block the Main Thread** {#1.-don’t-block-the-main-thread}
555
+
### Don’t Block the Main Thread
559
556
560
557
* By default, all MethodChannel calls are handled on the **main UI thread**, which is also responsible for rendering the app.
561
558
* Native operations like database access, file I/O, Bluetooth scanning, or network requests **must** be moved off the main thread.
@@ -566,7 +563,7 @@ Blocking the UI thread for even a few milliseconds can cause dropped frames, jan
566
563
567
564
**FlutterFlow Tip:** While UI interactions and workflows look smooth inside FlutterFlow, once you export and test the app on a real device, slow operations in Kotlin or Swift can still freeze the app. Always delegate those tasks to background threads before calling back into Dart.
* Your MethodChannel handler should act like a **controller**, not a service. It should delegate execution to well-structured, modular native components.
572
569
* This keeps the interface between Dart and native thin and easy to maintain.
@@ -575,9 +572,9 @@ Blocking the UI thread for even a few milliseconds can cause dropped frames, jan
575
572
576
573
Clean separation of concerns leads to better test coverage, easier onboarding, and avoids hard-to-debug cross-layer bugs.
577
574
578
-
###
579
575
580
-
### **3\. Use Only JSON-Compatible Data** {#3.-use-only-json-compatible-data}
576
+
577
+
### Use Only JSON-Compatible Data
581
578
582
579
* The Flutter engine uses `StandardMessageCodec` for MethodChannel communication.
583
580
* It supports only a limited set of Dart-native types: `int`, `double`, `bool`, `String`, `List`, `Map`, and `null`.
@@ -588,13 +585,13 @@ Type mismatches across the bridge don’t fail at compile time—they crash at r
588
585
589
586
**FlutterFlow Tip:** When using Dart Custom Actions that invoke MethodChannels, ensure the return values can be used in FlutterFlow bindings. Only supported types (like `String` or `int`) can be stored in App State or used in conditions or widgets.
590
587
591
-
### **4\. Validate and Sanitize Dart Inputs** {#4.-validate-and-sanitize-dart-inputs}
588
+
### Validate and Sanitize Dart Inputs
592
589
593
590
* Treat incoming Dart method calls like external API requests. Assume they can be malformed.
594
591
* Use pattern matching (switch/case or `when`) to route and verify each method call.
595
592
* Validate presence and type of arguments before using them. For example:
596
593
597
-
```
594
+
```js
598
595
val timeout =call.argument<Int>("timeout") ?:returnresult.error("INVALID", "Missing timeout", null)
599
596
```
600
597
@@ -604,7 +601,7 @@ Dart developers might call your method incorrectly. Native code must fail safely
604
601
605
602
**FlutterFlow Tip:** Custom Actions in FlutterFlow can include parameters from the UI, but if the parameter isn’t set or passed correctly in a workflow, the Dart code will still execute. Validate these inputs natively before use.
606
603
607
-
### **5\. Log Clearly on Both Sides** {#5.-log-clearly-on-both-sides}
604
+
### Log Clearly on Both Sides
608
605
609
606
* Add logging on both Dart and native layers for every MethodChannel call:
610
607
* What method was called?
@@ -617,11 +614,10 @@ When something goes wrong in production, good logs make the difference between a
617
614
618
615
**FlutterFlow Tip:** Use `debugPrint()` inside Dart Custom Actions to log output alongside platform logs. In test builds, these logs help verify whether native results are arriving as expected.
619
616
620
-
---
621
617
622
618
By applying these best practices, you can ensure your MethodChannel integrations remain robust, secure, and maintainable across app updates and platform development.
623
619
624
-
## **Summary & Guidance** {#summary-&-guidance}
620
+
## Summary & Guidance
625
621
626
622
MethodChannels are a foundational tool for extending the power of your app beyond what plugins alone can provide. They allow direct access to platform-native APIs and SDKs, enabling teams to solve tough integration challenges and deliver production-grade features with full control.
0 commit comments