Flutter与原生android进行数据交互

1,478 阅读2分钟

背景

flutter现在无疑是移动端跨平台最火的ui框架之一(个人理解他只是一款框架),有些功能免不了会调用原生功能,如摄像头、指纹认证等底层功能。本次主要讲解是flutter与原生android互相通信实现方式。

1.编写flutter公共页面

数据双向通信主要有以下实现步骤:
(1)发送通道定义:

	static const receive = const EventChannel('com.gxx.receive/plugin');
   
   //跳转到原生Activity界面
 Future<Null> _statrtToNativeActivity() async {
   String result = await sendToNative.invokeMethod('startToEditActivity');
 }
 
 // 通过插件将传递数据到原生界面
 Future<Null> _sendDataToNative() async {
   Map<String, String> map = {"flutter": "我是flutter 传递过来的"};
   String result = await sendToNative.invokeMethod('mapData', map);
   print(result);
 }

(2)接收通道定义:

 //接收来自本地的消息
 static const receiveFromNative =const EventChannel('com.gxx.send/plugin');
  //监听接收消息
 StreamSubscription _streamSubscription;

(3)在initState()方法中实例化数据接收监听

@override
void initState() {
  super.initState();
  //开启监听,通过原生界面将数据传递到flutter界面
  if (_streamSubscription == null) {
    _streamSubscription =
        receiveFromNative.receiveBroadcastStream().listen((event) {
      setState(() {
        _currentCount = event;
        print("ChannelPage: $event");
      });
    }, onError: (Object error) {
      setState(() {
        _currentCount = "计时器异常";
        print(error);
      });
    });
  }
}

(4)在dispose()方法中取消息订阅通道

@override
 void dispose() {
   // TODO: implement dispose
   super.dispose();
   //取消监听
   if (_streamSubscription != null) {
     _streamSubscription.cancel();
   }
 }

(6)整个完整代码如下:


import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          // Here we take the value from the MyHomePage object that was created by
          // the App.build method, and use it to set our appbar title.
          title: Text(widget.title),
        ),
        body: TestWidget());
  }
}

class TestWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TestState();
  }
}

class TestState extends State<TestWidget> {
  //获取插件与原生Native的交互通道
  static const sendToNative =
      const MethodChannel('com.gxx.receive/plugin');

  //具体要做的功能
  Future<Null> _statrtToNativeActivity() async {
    String result = await sendToNative.invokeMethod('startToEditActivity');
    print(result);
  }

  // 具体要做的功能
  Future<Null> _sendDataToNative() async {
    Map<String, String> map = {"flutter": "我是flutter 传递过来的"};
    String result = await sendToNative.invokeMethod('mapData', map);
    print(result);
  }

  //接收来自本地的消息
  static const receiveFromNative =
      const EventChannel('com.gxx.send/plugin');
  StreamSubscription _streamSubscription;
  var _currentCount;

  @override
  void initState() {
    super.initState();
    //开启监听
    if (_streamSubscription == null) {
      _streamSubscription =
          receiveFromNative.receiveBroadcastStream().listen((event) {
        setState(() {
          _currentCount = event;
          print("ChannelPage: $event");
        });
      }, onError: (Object error) {
        setState(() {
          _currentCount = "计时器异常";
          print(error);
        });
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return  Container(
      child: Column(
        children: <Widget>[
          RaisedButton(
            child: Text('跳转到原生界面'),
            onPressed: (){
              _statrtToNativeActivity();
            },
          ),
          RaisedButton(
            child: Text('让原生接收到数据'),
            onPressed: (){
              _sendDataToNative();
            },
          ),
          RaisedButton(child: Text("原生传递过来的数据:$_currentCount"),
          onPressed: (){

          },)
        ],
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    //取消监听
    if (_streamSubscription != null) {
      _streamSubscription.cancel();
    }
  }
}

2.原生代码编写

(1)定义数据接收插件(从flutter到原生界面)

public class FlutterPluginFtoA implements MethodChannel.MethodCallHandler {
    //这里要注意和Flutter使用的相同
    public static final String A_TO_F_CHANNEL = "com.gxx.receive/plugin";
    private Activity handlerActivity;

    public FlutterPluginFtoA(Activity activity) {
        this.handlerActivity = activity;
    }
    public static void registerWith(PluginRegistry.Registrar registrar) {
        //主要的方法MethodChannel
        MethodChannel methodChannel = new MethodChannel(registrar.messenger(), A_TO_F_CHANNEL);
        FlutterPluginFtoA instance = new FlutterPluginFtoA(registrar.activity());
        methodChannel.setMethodCallHandler(instance);
    }
    @Override
    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        switch (methodCall.method){
            case "showToast":
                //接收Flutter 传递过来的参数
                Object arguments = methodCall.arguments;
                Toast.makeText(handlerActivity, "收到Flutter传过来的" + arguments, Toast.LENGTH_SHORT).show();
                break;
            case "startToEditActivity":
                //跳转到原生界面
                Intent editActivityIntent = new Intent(handlerActivity, TestActivity.class);
                handlerActivity.startActivity(editActivityIntent);

                result.success("startOk");
                break;
            case "mapData":
                //Flutter 传递过来的数据
                //解析参数
                String text = methodCall.argument("flutter");
                Toast.makeText(handlerActivity, "接收: " + text, Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

(2)定义原生端到flutter端数据传递

public class FlutterPluginAtoF implements EventChannel.StreamHandler {
    public static final String F_TO_A_CHANNEL = "com.gxx.send/plugin";
    private static FlutterPluginAtoF instance;
    private EventChannel.EventSink events;

    public static FlutterPluginAtoF getInstance(){
        return  instance;
    }
    @Override
    public void onListen(Object o, EventChannel.EventSink eventSink) {
        this.events=eventSink;

    }
    public  static  void registerWith(PluginRegistry.Registrar registrar){
        EventChannel  eventChannel=new EventChannel(registrar.messenger(),F_TO_A_CHANNEL);
        instance=new FlutterPluginAtoF();
        eventChannel.setStreamHandler(instance);
    }
    @Override
    public void onCancel(Object o) {

    }
    public  void sendEventData(Object data){
        if(events!=null){
            events.success(data);
        }
    }
}

(3)在MainActivity分别注册接收端插件与发送端插件

class MainActivity : FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_edit_h5)
        //获取到自身的Registry
        val registry = flutterView.pluginRegistry;
        //注册插件
        FlutterPluginFtoA.registerWith(registry.registrarFor(FlutterPluginFtoA.A_TO_F_CHANNEL));
        FlutterPluginAtoF.registerWith(registry.registrarFor(FlutterPluginAtoF.F_TO_A_CHANNEL));
    }
}

(4)flutter页面直接跳转到原生界面 点击确定后将原生端数据传递给flutter页面

public class TestActivity extends Activity implements View.OnClickListener {
    private int currentCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_h5);
        Button btn=findViewById(R.id.tvIntentTxt);
        btn.setText("传递给flutter");
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
//
        FlutterPluginAtoF.getInstance().sendEventData(""+ currentCount++); //通过这个发送消息到Flutter
        Toast.makeText(this, currentCount+"", Toast.LENGTH_SHORT).show();
    }
}

3.效果

说明:以上为原生界面传递到flutter界面

说明:以上为flutter界面传递到原生界面

4.最后

本篇博客只作为学习记录知识,感谢其他博客提供思路。源码地址:github.com/guoxuxiong/…