这里以 Flutter 调用原生系统日志库,来理解下 Flutter 与 Android 交互
这里创建的时候用到了 Kotlin 、AndroidX
Android端
进入 android 目录下的 build.gradle ,点击 Open for Editing in Android Studio ,打开新的 android项目。
App 目录下 build.gradle 引入第三方日志封装库
dependencies {
implementation 'com.orhanobut:logger:2.2.0'
}
第三方库当然需要初始化等一些操作,这里多数很熟悉,直接上代码
定义 App(Application),继承 FlutterApplication ,注意在 AndroidManifest.xml 中配置
App 中
class App : FlutterApplication() {
override fun onCreate() {
super.onCreate()
mApp = this
//...
Logger.addLogAdapter(AndroidLogAdapter(formatStrategy))
}
companion object {
lateinit var mApp: Context
}
}
orhanobut.logger.Logger 参考它的 GitHub 用法
MainActivity (继承 FlutterActivity) 中复写 configureFlutterEngine 方法,但首先需要确定一个唯一的字符串标识符,来构造一个命名通道,这里以 "com.milanxiaotiejiang.plugins/log" 命名
class MainActivity : FlutterActivity() {
private val CHANNEL_LOG = "com.milanxiaotiejiang.plugins/log"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
// super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_LOG)
.setMethodCallHandler { call, result ->
val arguments = call.arguments.toString()
when (call.method) {
"logI" -> Logger.i(arguments)
"logD" -> Logger.d(arguments)
"logV" -> Logger.v(arguments)
"logW" -> Logger.w(arguments)
"logE" -> Logger.e(arguments)
}
result.success(true)
}
}
}
这里 super.configureFlutterEngine(flutterEngine) 与 GeneratedPluginRegistrant.registerWith(flutterEngine) 两方法都可以。
setMethodCallHandler :设置方法处理回调,可以取出方法名,进行判断,最后调用相应的原生方法。
而 result 为返回结果,它有三个方法
public interface Result {
@UiThread
void success(@Nullable Object result);
@UiThread
void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);
@UiThread
void notImplemented();
}
Android 端准备完毕
Flutter端
定义 log_services.dart 文件,这里 MethodChannel 中 name 就是原生中定义的唯一的字符串标识符,调用 invokeMethod 方法 + 调用原生方法名可实现。
import 'package:flutter/services.dart';
//声明MethodChannel
const _platform = const MethodChannel('com.milanxiaotiejiang.plugins/log');
class Logger {
Logger._();
//invokeMethod方法接收的参数,第一个必选参数,设置的是方法的名称;后面的参数为可选的需要传递的参数
static void i(String msg) async {
_platform.invokeMethod('logI', {'msg': msg});
}
static void d(String msg) async {
_platform.invokeMethod('logD', {'msg': msg});
}
static void v(String msg) async {
_platform.invokeMethod('logV', {'msg': msg});
}
static void w(String msg) async {
_platform.invokeMethod('logW', {'msg': msg});
}
static void e(String msg) async {
_platform.invokeMethod('logE', {'msg': msg});
}
}
这样 Flutter 调用 Logger 就可以在 logcat 中显示日志了。
ios 本人不是很了解,也没有设备,就不提及 ios 了哈!以一张图看 Dart 与 原生 之间的通信
需要注意的是,在使用方法通道进行方法调用时,由于涉及到跨系统数据交互,Flutter 会使用 StandardMessageCodec 对通道中传输的信息进行类似 JSON 的二进制序列化,以标准化数据传输行为。这样在我们发送或者接收数据时,这些数据就会根据各自系统预定的规则自动进行序列化和反序列化。
另外方法通道是非线程安全的。这意味着原生代码与 Flutter 之间所有接口调用必须发生在主线程。Flutter 是单线程模型,因此自然可以确保方法调用请求是发生在主线程(Isolate)的;而原生代码在处理方法调用请求时,如果涉及到异步或非主线程切换,需要确保回调过程是在原生系统的 UI 线程中执行的,否则应用可能会出现奇怪的 Bug,甚至是 Crash。
那么,我们可以将 Android 中网络请求放在原生,调用 Flutter 中创建异步任务调用原生 API 请求后台。这样可以使用更强大的 OkHttp,甚至 Mars。