Aengus 的技术小筑

Aengus | Blog

Flutter 与安卓原生代码调用

1022
2020-01-02

Flutter与原生交互有三种方法,分别是MethodChannelEventChannelBasicMessageChannelMethodChannel提供了Flutter与原生代码的方法调用的通道,并且可以得到所调用函数返回的数据;EventChannel则是事件传递,可以将Flutter的一个事件(比如监听)交给原生平台,原生平台去做监听,当收到广播后借助EventChannel调用Flutter注册的监听,完成对Flutter的事件通知;BasicMessageChannel用于传递数据,Flutter与原生资源不共享,可以通过BasicMessageChannel获得原生的资源比如图片等。

Flutter和原生代码的相互调用就是通过MethodChannel,调用方与被调用方分别创建MethodChannel并分别调用invokeMethod()setMethodCallHandler()即可。

Flutter调用安卓原生方法

Flutter端首先创建MethodChannel并指定其名称,原生端创建的MethodChannel的参数名称也要与此相同,这样才可以进行使用同一个Channel进行交互,建议名称使用“域名/标识符”:

/// Flutter端代码,调用安卓代码
import 'package:flutter/services.dart';

static const platform = const MethodChannel("flutter.example.com/native");
// ...
// "getData"是调用的方法名;param是getData的参数,可以不传参
final String data = await platform.invokeMethod<String>("getData", param);

下面是安卓端Kotlin的代码,注意代码platform.setMethodCallHandler一定要调用,否则可能会不生效:

import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MyActivity: FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)
        
        val platform: MethodChannel = MethodChannel(flutterView, "flutter.example.com/native")
        platform.setMethodCallHandler {
            call, result ->
            // 下面的方法将在主线程中调用
            if (call.method == "getData") {
                try {
                    val res: String = getData(call.arguments) // call.arguments对应上面的param
                	result.success(res)	// 调用成功
                    return
                } catch (e: Exception) {
                    e.printStackTrace()
                    result.error("UNAVAILABLE", "有问题出现", null)
                    return
                }
            } else {
                result.notImplemented()	// 无此方法实现
                return
            }
        }
    }
    
    private fun getData(text: String): String {...}
}

安卓调用Flutter方法

出现此需求的一般情况是某个被动调用的方法只能使用安卓原生代码实现,然后再调用之前在Flutter中写过的方法。也就是App监听系统的某个事件,被系统触发后自动调用此原生方法,而在原生方法中又要调用Flutter方法。

安卓端Kotlin代码:

// 安卓调用Flutter方法
import io.flutter.app.FlutterActivity
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MyActivity: FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)
        
        val params: String = "1.0.5"
        var result: String = String()
        MethodChannel(flutterView, "flutter.example.com/native").invokeMethod("getData", params, object: MethodChannel.Result {
            override fun notImplemented() {
                throw Exception("方法未实现")
            }
            
            override fun error(p0: String?, p1: String?, p2: Any?) {
                throw Exception("执行时出现错误!")
        	}

        	override fun success(p0: Any?) {
            	result = p0
        	}
        })
        // 如果不需要函数返回结果,可以用下面的方式
        // MethodChannel(flutterView, "flutter.example.com/native").invokeMethod("getData", params)
    }
}

下面是Flutter端代码。同样platform.setMethodCallHandler也需要被调用,建议在runApp()之前进行初始化操作:

import 'package:flutter/services.dart';

static const platform = const MethodChannel("flutter.example.com/native");
// ...
var result;
platform.setMethodCallHandler((call) {
    if (call.method == "getData") {
        var res = getData(call.arguments);	// getData(String)必须是async方法,返回Future
        return res;
    } else {
        return null;
    }
});

getData(String text) {...}

参考

flutter与原生交互具体实现

撰写双端平台代码(插件编写实现)

[HelloFlutter——MethodChannel(Native&Flutter数据交互)