FlutterFlutter interacts with Android native activities and delivers data

Recommended reading

Flutter (2) Android integrates Flutter projects and jumps to the Flutter interface

Flutter (1) Installation, deployment and understanding of Dart language

Catalog

Preface

1. Platform Channel

2. MethodChannel

3. Flutter returns to the previous page

Preface

In the previous article, you learned about Android's native integrated Flutter and implemented page jumping. In this article, you will learn about data interaction between Flutter and Activity.

1. Platform Channel

Flutter defines three different Channel s; however, whether it is a delivery method or an event, it is essentially a transfer of data.

  • MethodChannel: Used to pass method calls.
  • EventChannel: Used for communication of data streams; used for event monitoring, cancellation, etc. on Flutter and platform.
  • BasicMessageChannel: Used to convey string and semi-structured information; used for message data exchange between Flutter and the platform.

Each Channel contains three member variables;

  • Name: Represents the Channel unique identifier. Channel can contain more than one, but name is unique;
  • messager: A tool that represents the sending and receiving of messages, BinaryMessenger;
  • Codec: a codec that represents a message;

Here I'm going to focus on the use of MethodChannel, which is also the most commonly used in our development.

 

2. MethodChannel

Call the invokeMethod method of MethodChannel in Flutter to jump and pass parameters to the native activity page.The native Activity page calls the MethodChannel's setMethodCallHandler method to implement a method callback that accepts the message passed by Flutter.

 

1. Android Code

Creating a MethodChannel on the Android side requires passing two parameters.The first is the BinaryMessenger interface, which represents the messenger and is the tool for sending and receiving messages; the second parameter is name, which represents the name of the Channel, defines the final type guarantees uniqueness, and corresponds to Flutter's MethodChannel.

private static final String CHANNEL_NATIVE = "com.example.flutter/native";
private FlutterEngine flutterEngine;

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_takeout);
        
        flutterEngine = new FlutterEngine(this);
        flutterEngine.getNavigationChannel().setInitialRoute("route1");
        flutterEngine.getDartExecutor().executeDartEntrypoint(
                DartExecutor.DartEntrypoint.createDefault()
        );

        flutterView = new FlutterView(this);
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        FrameLayout flContainer = findViewById(R.id.flutter_view);
        flContainer.addView(flutterView, lp);

        if (flutterEngine!=null){
            flutterView.attachToFlutterEngine(flutterEngine);
        }

        MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor()
                                      .getBinaryMessenger(), CHANNEL_NATIVE);
        nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                switch (methodCall.method) {
                    case "jumpToNative":   // Jump to Native Page
                        if (methodCall.arguments != null) {
                            ToastUtil.show(TAG,  methodCall.argument("message"));
                        } else {
                            ToastUtil.show(TAG,"Callback parameter is empty");
                        }
                        startActivity(new Intent(TAG, MainPageActivity.class));

                        result.success("Activity -> Flutter Receive callback return value successfully");
                        break;
                    default:
                        result.notImplemented();
                        break;
                }
            }
        });
}
    @Override
    protected void onResume() {
        super.onResume();
        if (flutterEngine!=null){
            flutterEngine.getLifecycleChannel().appIsResumed();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (flutterEngine!=null){
            flutterEngine.getLifecycleChannel().appIsInactive();
        }

    }

    @Override
    protected void onStop() {
        super.onStop();
        if (flutterEngine!=null){
            flutterEngine.getLifecycleChannel().appIsPaused();
        }
    }

2. Flutter Code

A MethodChannel also needs to be defined on the Flutter side, and it needs to be introduced using MethodChannelServices.dartPackage, Channel name should be the same as defined on Android side.Click the button to execute the call invokeMethod(), which has two parameters.The first one corresponds to the Android sideMethodCall.methodGet the method name.The second is the method's parameter, which is passed on the Android sideMethodCall.arguments()/argument() gets all the parameters or the parameters with the specified name.

class _MyHomePageState extends State<MyHomePage> {
  static const nativeChannel = const MethodChannel('com.example.flutter/native');
  String _result = '';
  Future<void> _incrementCounter() async {
    Map<String, dynamic> result = {'message': 'From Flutter Page back'};
    try {
      _result = await nativeChannel.invokeMethod('jumpToNative', result);
    } on PlatformException catch (e) {
      _result = "Failed: '${e.message}'.";
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title), ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Delivery results: $_result',),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

 

3. Flutter returns to the previous page

A nested FlutterView page in a native Activity is similar to a nested WebView, where each Flutter page corresponds to a route routing address, which is equivalent to a Url link address.We know that WebView has a goBack() method to return to the previous page; so how do you implement a return to the previous page on a Flutter page?

The ideas are as follows:

Flutter Call Navigator.canPop(context) To determine if it is possible to return, true callsNavigator.of(context). pop() returns, while false indicates that it is the first page and returns to Activity.

First, add a button to the Flutter page and click it to jump to the SecondPage page.

RaisedButton(
    child: Text('Jump Flutter page'),
    onPressed: () {
      Navigator.of(context).push(MaterialPageRoute(builder: (context) {
        return SecondPage();
      }));
    }
),

Then, define MethodChannel and MethodCallHandler callbacks, call Navigator.canPop(context) to determine whether Flutter returns to the previous page or the Activity native page.

static const nativeChannel =const MethodChannel('com.example.flutter/native');
static const flutterChannel =const MethodChannel('com.example.flutter/flutter');

@override
void initState() {
  super.initState();
  Future<dynamic> handler(MethodCall call) async {
    switch (call.method) {
      case 'goBack':
        if (Navigator.canPop(context)) {  // Return to the previous page
          Navigator.of(context).pop();
        } else {
          nativeChannel.invokeMethod('goBack');
        }
        break;
    }
  }
  flutterChannel.setMethodCallHandler(handler);
}

On the Android side, override the onBackPressed() method to give the Flutter side the event handling for the return key.

private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";

@Override
public void onBackPressed() {
    MethodChannel flutterChannel = new MethodChannel(flutterView, CHANNEL_FLUTTER);
    flutterChannel.invokeMethod("goBack", null);
}

Finally, write a native MethodCallHandler callback that finish es the Activity directly if the current Flutter page is the first.

nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
switch (methodCall.method) {
    case "goBack":
        // Return to the previous page
        finish();
        break;
    default:
        result.notImplemented();
        break;
}

 

Reference address:

Flutter 49: Illustrate Flutter's native interaction with Android;

Flutter Learning Subtotal: Android Native Project introduces Flutter;

Tags: Android codec

Posted on Sat, 20 Jun 2020 23:07:21 -0400 by belaraka