Everything that Flutter communicates with native
Introduction to Flutter
Introduction to the
Communication between Flutter and native relies on flexible messaging:
- The Flutter part of an application sends messages to the host (iOS or Android) application (native app) of its application via a platform channel.
- The host listens on the platform channel and receives the message. It then invokes the platform’s API and sends the response back to the client, the Flutter part of the application.
- MethodChannel // The Flutter calls the native method for method abandonment
- BasicMessageChannel // The Flutter sends messages to each other with the native for data transfer
- EventChannel natively sends messages that are received by Flutter for data flow messages
Data structures that can be passed
Dart | Android | iOS |
---|---|---|
null | null | nil(NSNull when nested) |
bool | Java.lang.Boolean | NSNumber numberWithBool: |
int | Java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | Java.lang.Long | NSNumber numberWithLong: |
int, if 64 bits not enough | Java.lang.BigInteger | FlutterStandardBigInteger |
double | Java.lang.Double | NSNumber numberWithDouble |
String | java.lang.String | NSString |
Unit8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | Java.util.ArrayList | NSArray |
Map | Java.util.HashMap | NSDictionary |
MethodChannel (calling methods to each other)
Android calls the Flutter method:
Android:
- Initialize MethodChannel
FlutterView (getFlutter in MainActivity); 2. Name constant, used in Flutter with the same name
MethodChannel methodChannel = newMethodChannel (flutterView, "testflutter");Copy the code
- Call the Flutter method
private void invokeFlutterMethod(a) {
if (this.mMethodChannel ! =null) {
this.mMethodChannel.invokeMethod("flutterMethod"."Native parameters".new MethodChannel.Result() {
@Override
public void success(Object o) {
Toast.makeText(mContext, o.toString(), Toast.LENGTH_LONG).show();
}
@Override
public void error(String s, String s1, Object o) {}@Override
public void notImplemented(a) {}}); }}Copy the code
Call invokeMethod with MethodChannel (” method name “,” pass parameters “,[Flutter returns parameter callback, optional]);
Flutter:
- Initialize MethodChannel
static const methodChannel = const MethodChannel('testflutter');
Copy the code
- Add processing methods to MethodChannel
methodChannel.setMethodCallHandler(_addNativeMethod);
Copy the code
- Handles the method called by Android, according to the method name
Future<dynamic> _addNativeMethod(MethodCall methodCall) async {
switch (methodCall.method) {
case 'flutterMethod':
setState(() {
_calledFromNative = 'flutter method called from native with param ' + methodCall.arguments;
});
return 'flutter method called from native with param ' + methodCall.arguments;
break; }}// Where, the data returned by return is received in the Android callback
Copy the code
Flutter calls the Android method:
Android:
- Initialize the MethodChannel and add a custom plugin
MethodChannel methodChannel = new MethodChannel(flutterView, METHOD_CHANNEL);
methodChannel.setMethodCallHandler(plugin);
Copy the code
- A custom plugin implementation MethodChannel. MethodCallHandler onMethodCall method of interface
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
// the method of Flutter calls Native
if (methodCall.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
if(batteryLevel ! = -1) {
result.success(batteryLevel);
} else {
result.error("UNAVALIABLE"."battery level unavaliable".null); }}else{ result.notImplemented(); }}// Listen in onMethodCall for a method called by the name of the Flutter (here getBatterLevel), and return the result of the method execution via result.
Copy the code
Flutter:
- Initialize MethodChannel
static const methodChannel = const MethodChannel('testflutter');
Copy the code
- Call the Android method and receive the returned data
// The methods of the method channel are asynchronous
Future<Null> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await methodChannel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level $result .';
} on PlatformException catch (e) {
batteryLevel = 'Battery level unknown ${e.message}';
}
setState(() {
_batteryLevel = batteryLevel;
});
}
Copy the code
BasicMessageChannel
Android messages to Flutter:
Android:
- Initialize BasicMethodChannel
BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, "messageChannel", StandardMessageCodec.INSTANCE);
Copy the code
- Call the method that sends the message
private void sendMessageToFlutter(a) {
if (this.mBasicMessageChannel ! =null) {
this.mBasicMessageChannel.send("Message From Native"); }}Copy the code
Flutter:
- Initialize BasicMessageChannel
static const basicMessageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
Copy the code
- Add received message processing methods
void _listenMessageFromNative() {
basicMessageChannel.setMessageHandler(_receiveMessageFromNative);
}
Copy the code
- Process the received data
//Flutter receives messages from Native
Future<dynamic> _receiveMessageFromNative(Object result) async {
setState(() {
_messageFromNative = result.toString();
});
}
Copy the code
Flutter sends a message to Android:
Android:
- Initialize BasicMessageChannel and add plugin to handler
BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, "messageChannel", StandardMessageCodec.INSTANCE);
messageChannel.setMessageHandler(plugin);
Copy the code
- The plugin implementation BasicMessageChannel MessageHandler interface onMessage method, processing the received information
@Override
public void onMessage(Object o, BasicMessageChannel.Reply reply) {
Toast.makeText(mContext, o.toString(), Toast.LENGTH_LONG).show();
reply.reply(o.toString()+" back from native");
}
// Reply returns data to the Flutter
Copy the code
Flutter:
- Initialize BasicMessageChannel
static const basicMessageChannel = BasicMessageChannel('messageChannel', StandardMessageCodec());
Copy the code
- Send a message to Android and receive the returned data
Future<dynamic> _sendMessageToNative(String message) async {
String reply = await basicMessageChannel.send(message);
print(reply);
setState(() {
_replayFromNative = reply;
});
return reply;
}
Copy the code
EventChannel (native message sending, Flutter receiving)
Android:
- Initialize EventChannel and add plugin to handler
EventChannel eventChannel = new EventChannel(flutterView, EVENT_CHANNEL);
eventChannel.setStreamHandler(plugin);
Copy the code
- The plugin implementation EventChannel. StreamHandler interface and onListen and onCancel method
- Send messages to Flutter in onListen via an instance of eventChannel. EventShink
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
BroadcastReceiver chargingBroadcastReceiver = createChargingBroadcaseReceiver(eventSink);
mContext.registerReceiver(chargingBroadcastReceiver,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
@Override
public void onCancel(Object o) {}private BroadcastReceiver createChargingBroadcaseReceiver(EventChannel.EventSink eventSink) {
return new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
eventSink.error("UNAVALIABLE"."charging status is unavailable".null);
} else {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING;
eventSink.success(isCharging ? "charging" : "disCharging"); }}}; }Copy the code
Flutter:
- Initialize the EventChannel
static const _eventChannel = const EventChannel('charging');
Copy the code
- Add a method to receive data
void listenNativeEvent() {
_eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
}
// Receive the returned data
void _onEvent(Object object) {
String s = "Battery is ${object == 'charging' ? ' ' : 'dis'}Charging";
setState(() {
_batteryStatus = s;
});
}
Copy the code
Bridge View for use by Flutter
Android:
- Custom View, inherited from PlatformView
public class MyTextview implements PlatformView {
TextView t;
public MyTextview(Context context, MessageCodec<Object> messenger, int id, Map<String, Object> params){
TextView textView = new TextView(context);
// Get parameters, if any parameters are passed
if (params.containsKey("text")){
textView.setText(params.get("text").toString());
}
this.t = textView;
}
@Override
public View getView(a) {
return t;
}
@Override
public void dispose(a) {}}Copy the code
- Implement PlatformViewFactory
public class TextViewFactory extends PlatformViewFactory {
private MessageCodec<Object> messageCodec;
public TextViewFactory(MessageCodec<Object> createArgsCodec) {
super(createArgsCodec);
this.messageCodec = createArgsCodec;
}
@Override
public PlatformView create(Context context, int i, Object o) {
return newMyTextview(context, messageCodec, i, (Map<String, Object>) o); }}Copy the code
- Register a View for Flutter
registrar.platformViewRegistry().registerViewFactory("TextView".new TextViewFactory(new StandardMessageCodec()));
// Call the Flutter TextView and use it as a viewType
Copy the code
Flutter:
- Use a bridged View
AndroidView(
viewType: 'TextView',
creationParams: {'text': 'TTTeeeXXXttt'},
creationParamsCodec: new StandardMessageCodec(),
),// creationParams and creationParamsCodec must exist together or not
Copy the code
Above, the end of the text;
Officials have other suggestions
Publish pub using:
-
Hosted Packages (posted to pub.dartlang.org)
$flutter packages pub publish --dry-run $flutter packages pub publish Copy the code
Use in the YAML file like other dependencies.
-
Git packages
Upload the code to Git and tag it
Yaml file references
dependencies: flutter_remote_package: git: url: git@gitlab. ref:0.01. // Can be commit, branch, or tag Copy the code
-
local
Create the plugins folder under the root of the Flutter App and move the plugin to the plugins folder.
Dependencies: Flutter_plugin_batterylevel: path: plugins/flutter_plugin_batterylevelCopy the code
This is limited to creating projects using plugins. Sometimes they are developed in their own Android or iOS projects, so it is not so convenient to release them separately.
Sometimes you need to run channelMethod to the UI Thread. On Android, you need to post a Runnable to the Android UI thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run(a){
// call the desired channel message here.}})Copy the code
-
The essence of “passing View” is to pass texture ID. We only need to understand that Flutter realizes external texture through Presentation. When creating the Presentation, we pass in the corresponding Context of FlutterView and create a virtual display object. Enable Flutter to find texture data created by Native using ID directly.
-
Event processing: At the stage of transferring from Native to Flutter, the Flutter processes the event according to its own rules. If the Event is captured by AndroidView, it will be encapsulated into the corresponding event at the Native end and sent back to The Native end through the method channel, where the event will be processed by the Native end.
For possible sliding-time conflicts, please refer to the official notes:
/// For example, with the following setup vertical drags will not be dispatched to the Android view as the vertical drag gesture is claimed by the parent [GestureDetector]. /// /// GestureDetector( /// onVerticalDragStart: (DragStartDetails d) {}, /// child: AndroidView( /// viewType: 'webview', /// gestureRecognizers: <OneSequenceGestureRecognizer>[]. / / /), / / /) /// /// To get the [AndroidView] to claim the vertical drag gestures we can pass a vertical drag gesture recognizer in [gestureRecognizers] e.g: /// /// GestureDetector( /// onVerticalDragStart: (DragStartDetails d) {}, /// child: SizedBox( / / / width: 200.0. / / / height: 100.0. /// child: AndroidView( /// viewType: 'webview', /// gestureRecognizers: <OneSequenceGestureRecognizer>[new VerticalDragGestureRecognizer()], / / /), / / /), / / /) Copy the code
[making] github.com/damengzai/f…
Reference:
The correct position to embed Native components in a Flutter is… — Idle fish technique