I'm working on a Flutter app with some native kotlin code. It's straightforward to call native methods from Flutter through the MethodChannel, and vice-versa (from MainActivity).
However, I also want a way to trigger Flutter code triggered from a native Broadcast receiver, where I don't have the original MethodChannel. The problem is, I'm not sure how to create a FlutterEngine with the right arguments to get access to the same MethodChannel.
Is there a way to construct the same FlutterEngine that can be used to call back into Flutter code? What I want to do:
var flutterEngine = FlutterEngine(XXX)
var flutterChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, FLUTTER_CHANNEL)
flutterChannel.invokeMethod(...)
I'm not sure what XXX should be here to get the same Channel I have in MainActivity. If there's some info I need to pass from MainActivity, I could use intents to pass it to my broadcast receiver, but it's not clear what is needed.
Flutter Engine and Channels work with named scopes, if you uses the same engine name end channel is the same channel in Flutter side.
Related
I receive data from a BLE unit and have a broadcast stream exposed by a singleton locator (Get_It) to my application.
From the data, I want to build several small display widgets that need to display different information based on the same data stream, however, only the last of my 3 widgets listens to, and receives the stream information.
I was under the impression that, a broadcast stream makes itself available to more than one listener, however, this is clearly not the case, unless I have it wrong.
For reference, here's the exposure via my sessionManager:
Stream<dynamic> get pairAndListen => AppSDK.unit
.pair()
.asBroadcastStream()
AppSDK.unit is a call to a Flutter plugin, that exposes the BLE's characteristics by the manufacturer's supplied SDK for both Android and iOS (reactive_ble and the likes will not work here as it's IP locked behind their SDK's).
As per my understanding setting it up as a broadcast stream should allow multiple listeners receive the feedback?
An example of my widgets:
widget_1.dart
Widget1(stream: sessionManager.pairAndListen)
widget_2.dart
Widget2(stream: sessionManager.pairAndListen)
What I'm actually doing, the widgets are on a dashboard, wrapped in a Column(), each receiving the stream from the sessionManager, however, only the last one of the 3 widgets work; the other two is completely ignored.
If I wrap my Column() with a single StreamBuilder and pass the result from the callback to each of the widgets, it obviously works as there's only one listener, however, I want each of my widgets to manage the response differently within themselves.
Am I missing something in regards to the use of asBroadcastStream?
Is there a way to ensure the bindings are initialized between Flutter and Host/ Platform (Android, iOS)? I want to do this because I want to invoke methods from host to dart.
For example, in Android (java), I create a flutter engine, register plugins, and create a method channel, and launch the application:
FlutterEngine flutterEngine = new FlutterEngine(context, null);
// Remember to register plugins
GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
DartExecutor executor = flutterEngine.getDartExecutor();
methodChannel = new MethodChannel(executor.getBinaryMessenger(), "my background method channel");
methodChannel.setMethodCallHandler(this);
// Launch app
DartExecutor.DartEntrypoint appEntrypoint = DartExecutor.DartEntrypoint.createDefault();
executor.executeDartEntrypoint(appEntrypoint);
I'd like to use methodChannel.invokeMethod, but the application might not be ready for me yet, even though in appEntrypoint, the same MethodChannel is created on the dart side. If I call methodChannel.invokeMethod too early, I get:
2021-09-14 16:41:01.102 30103-30425/com.example.app E/flutter:
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception:
MissingPluginException
(No implementation found for method MethodName on channel com.example.app.package)
A solution would be to ask the Dart side to call a PlatformMethod when it's ready initializing, which would inform me that it's ready to receive messages. But I would prefer to avoid having to set up 2 way communication if I only need to send one message to the Dart side.
I have a feeling it's not possible. If so, could someone still explain why the binding has to be awaited from the Dart side? Something to do with no listeners available on the Platform side?
The methods were actually being called.
It was working. This was a bad idea, but the actual methods were being called: the 2 Method Channels on dart side and 2 method channels on Platform side were calling each other just fine. They all had the same channel name. Probably not a good idea for complexity reasons (see below), but it worked. 😅
My specific issue:
The reason I was getting No implementation found for method MethodName was exactly because I had two MethodChannels on the dart side, and two on Platform side. I was recreating the same isolate, so I had 2 Flutter applications running simultaneously. When one Isolate called a dart method I did not implement on on Method Call Handler on Platform side, I got this error.
Lesson learnt
If you have separate components on your app (Android components: Activity, Service, Broadcast Receiver or Dart Isolates):
Don't re-create the main application entrypoint. Create a new separate DartEntrypoint.
Use unique channel names for the MethodChannel.
I am currently developing a flutter web app, and would like to implement a feature to broadcast json data to any listeners/subscribers.
To give more detail:
The web app has a flutter front end server running on localhost. A user will be able to fetch some JSON data from an external backend server using a simple GET request.
Once the app has loaded the JSON data, it will need to broadcast it down an SSE stream to any listeners. This listener will be a seperate flutter application.
Now, I understand that there a few problems with this.
Firstly, Flutter web doesn't support dart:io... Fine - I have managed to get round this by using the universal_io dart package instead of dart:io. The api is the same, and after solving a few CORS errors, works a charm for the GET requests in the first bullet above. This means that the json data can be successfully loaded into the Flutter app.
(universal_io dart package -> https://pub.dev/packages/universal_io).
The next issue is with SSE. Part one of this is that there is not much documentation on implementing an SSE server in Flutter - only a client that can listen. However, I have managed to find a solution in the sse dart package example app...
import 'package:shelf/shelf_io.dart' as io;
import 'package:sse/server/sse_handler.dart';
/// A basic server which sets up an SSE handler.
///
/// When a client connnects it will send a simple message and print the
/// response.
void main() async {
var handler = SseHandler(Uri.parse('/sseHandler'));
await io.serve(handler.handler, 'localhost', 0);
var connections = handler.connections;
while (await connections.hasNext) {
var connection = await connections.next;
connection.sink.add('foo');
connection.stream.listen(print);
}
}
(sse dart package -> https://pub.dev/packages/sse)
(continued) Usually, this would be a fine solution, and it could probably be modified a little for implementation within a flutter app. However, the shelf_io.dart package, used to spin up the server, depends on the dart:io package, which doesn't work with Flutter Web.
The other thought is - why do we need to set up a new server connection (with io.server(...)) when the flutter web app is already running on its own localhost server? This begs the question: Is there a way to add this sseHandler endpoint onto the localhost server that the Flutter Web app is running on?
All in all, what i'm trying to ask is:
Is there a way for a Flutter Web App to send SSE messages to a collection of listeners?
At the moment I've hit a bit of a deadend with research on this so if anyone had any bright ideas on a potential solution then the help would be greatly appreciated. Thanks :)
Side Note: Obviously this is something that could very easily be done with Java, J2Html and so on, but wheres the fun in giving up just like that... On the other hand, maybe flutter web is still just too new to support stuff like this?
Within our flutter app we are doing some background processing. For that, we need to create new flutter isolate in our native code so we can run code when activity is not open, based on this guide: https://medium.com/#chetan882777/initiating-calls-to-dart-from-the-native-side-in-the-background-with-flutter-plugin-7d46aed32c47
Now, to not duplicate code and to not cause any concurrency issues, we would also like to have access to that background processing isolate from main flutter UI isolate. That way we can begin processing from both native code and from flutter UI code.
However, there does not seem to be a way for native to pass this Isolate / ControlPort to the main UI side so it can communicate with it. Is there a way I can achieve this (communicate to the same Isolate from both native and UI side)?
From what I see, only way to do this would require native to be the broker between the two sides (send the task to native and then native sends it back to the other side), but it seems like a lot of hassle for one flutter talking to another flutter.
Solution to this is the IsolateNameServer.
One side can call IsolateNameServer.registerPortWithName() and other side can then send messages to that port via IsolateNameServer.lookupPortByName()
In Flutter, there are three types of platform channels, and I want to know about the difference between them.
These channels are used to communicate between native code (plugins or native code inside of your project) and the Flutter framework.
MethodChannel
A MethodChannel is used for "communicating with platform plugins using asynchronous method calls". This means that you use this channel to invoke methods on the native side and can return back a value and vise versa.
You can e.g. call a method that retrieves the device name this way.
EventChannel
An EventChannel is used to stream data. This results in having a Stream on the Dart side of things and being able to feed that stream from the native side.
This is useful if you want to send data every time a particular event occurs, e.g. when the wifi connection of a device changes.
BasicMessageChannel
This is probably not something you will want to use. BasicMessageChannel is used to encode and decode messages using a specified codec.
An example of this would be working with JSON or binary data. It is just a simpler version because your data has a clear type (codec) and you will not send multiple parameters etc.
Here is a link to a good explanation for you https://medium.com/flutter-io/flutter-platform-channels-ce7f540a104e
Basically there are two main types:
Method Channels: designed for invoking named pieces of code across Dart and Java/Kotlin or Objective-C/Swift. (From flutter to the platform)
Event Channels: specialized platform channel intended for the use case of exposing platform events to Flutter as a Dart stream. (From the platform to flutter)
#creativecreatorormaybenot answer clears the things, let me add more to this.
Method Channel
This is more like RPC call. You invoke a method from your Flutter app to the native code, the native code does something and finally responds with a success or error. This call could be to get the current battery status, network information or temperature data. Once the native side has responded, it can no longer send more information until the next call.
Method Channel provides platform communication using asynchronous method calls.
Note:- If desired, method calls can also be sent in the reverse
direction, with the platform acting as client to methods implemented
in Dart.
Event Channel
This is more like reactive programming where platform communication using asynchronous event streams. These events could be anything that you need streamed to your Flutter application.Streaming data from the native code to Flutter app like continuously updating BLE or WiFi scanning results, accelerometer and gyro, or even periodic status updates from intensive data collection.
Basic Message Channel
It provides basic messaging services similar to BinaryMessages, but with pluggable message codecs in support of sending strings or semi-structured messages. Messages are encoded into binary before being sent, and binary messages received are decoded into Dart values. The MessageCodec used must be compatible with the one used by the platform plugin.