Flutter中dart和原生代码的通信之MethodChannel

前言

据我所知,真正掌握Flutter的Android开发工程师的比例并不是很高,如果你不这么认为,可能是因为你的圈子比较高端。你知道Android原生开发工程师把所有知识体系融汇贯通需要的时间是多久吗?当然这里把Flutter排除在外。资质顶尖的至少要3年,而大部分人智商属于中等偏上,大概要5年。如果是一个普通的码农,可能要8~10年甚至更久。当然我只是按之前非AI时代来进行估计的,未来AI时代可能会略有降低。10年啊,也就是一个普通的程序员需要从毕业干到快35岁危机时才能真正腾出精力来仔细研究Flutter这种跨平台的技术。当然你说我一开始的目标就是Flutter,那没问题,这不在讨论的范畴。

很多安卓开发其实压根没有练手Flutter项目的机会,因为,小公司很难招到这种十年以上的大佬。当然也不会有人从全局角度带你玩转Android Flutter混合开发,除非你运气好,正好有人带。

引入正题

如果完全没接触过Android Flutter混合开发的同学需要先看我这篇文章juejin.cn/post/725412... 。混合开发要想真正落地,不仅需要扎实的原生开发功底,还需要有刻苦钻研新技术的勇气。混合开发避不开一个话题,如何进行通信或者说相互调用的互操作性?这就引入了我们今天的主角------Method Channel。它直译过来就是方法通道,你可以理解成一个调用另一端方法的桥梁。我们看一下怎么写。

通信流程

原生调Dart
kt 复制代码
val intent = FlutterActivity
    .withNewEngine()
    .initialRoute(ROUTE_HOME)
    .build(this)
intent.setClass(this, MyFlutterActivity::class.java)
startActivity(intent)

先启动Flutter界面的原生壳Activity,清单文件该注册注册。

kt 复制代码
package com.doracrypto.crypto.ui.activity

import android.content.Intent
import com.doracrypto.crypto.AppConfig
import dora.util.SPUtils
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MyFlutterActivity : FlutterActivity() {

    companion object {
        private const val CHANNEL = "com.doracrypto.crypto/native"
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "isVipUser" -> {
                        result.success(SPUtils.readBoolean(context, AppConfig.IS_VIP))
                    }
                    "startBuyVipActivity" -> {
                        startActivity(Intent(this@MiniAppActivity, BuyVipActivity::class.java))
                        result.success(null)
                    }
                    else -> result.notImplemented()
                }
            }
    }
}

这东西虽不难,但确是必经之路。在原生侧,我们需要提供各种各样的方法给Dart侧调用。

dart 复制代码
import 'package:flutter/services.dart';

class MethodChannelPlugin {

  static const MethodChannel methodChannel = MethodChannel('com.doracrypto.crypto/native');

  // /// 调用原生浏览器组件
  // static Future<void> gotoWebView(String url) async {
  //   try {
  //     await methodChannel.invokeMethod('gotoWebView',{'url': url});
  //   } on PlatformException {
  //     print('Failed go to gotoWebView');
  //   }
  // }

  /// 检测是否是VIP用户
  static Future<bool> isVipUser() async {
    try {
      final result = await methodChannel.invokeMethod('isVipUser');
      return result == true; // 保证返回 bool
    } on PlatformException catch (e) {
      print('Failed isVipUser: $e');
      return false; // 出错时兜底返回 false
    } catch (e) {
      print('Unexpected error in isVipUser: $e');
      return false;
    }
  }

  /// 跳转购买VIP界面
  static Future<void> startBuyVipActivity() async {
    try {
      await methodChannel.invokeMethod('startBuyVipActivity');
    } on PlatformException catch (e) {
      print('Failed startBuyVipActivity: $e');
    } catch (e) {
      print('Unexpected error in startBuyVipActivity: $e');
    }
  }
}

调用时就这样去调。

dart 复制代码
bool isVip = await MethodChannelPlugin.isVipUser();
if (!isVip) {
  MethodChannelPlugin.startBuyVipActivity();
  return;
}
Dart调原生

主要都是Dart调原生,原生调用Dart的场景不是很多。不多但不代表没有,我这里简单提一嘴。

dart 复制代码
import 'package:flutter/services.dart';

class NativeBridge {

  static const MethodChannel _channel = MethodChannel("com.doracrypto.crypto/dart");

  static void init() {
    // 接收原生调用
    _channel.setMethodCallHandler((call) async {
      if (call.method == "fromNative") {
        String msg = call.arguments as String;
        print("收到原生调用:$msg");
        return "Dart收到: $msg";
      }
      return null;
    });
  }
}

在main.dart里面初始化。

dart 复制代码
void main() {
  // 等待初始化完成 
  WidgetsFlutterBinding.ensureInitialized();
  NativeBridge.init();
  runApp(MyApp());
}

原生侧调用Dart。

kt 复制代码
class MainActivity: FlutterActivity() {

    private lateinit var channel: MethodChannel

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        channel = MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            "com.doracrypto.crypto/dart"
        )
        Handler(Looper.getMainLooper()).postDelayed({
            channel.invokeMethod("fromNative", "Hello from Android")
        }, 3000)
    }
}

通道名称只要唯一就行,并不一定要这样的格式。最后编译aar,三行命令,搞定。

bash 复制代码
flutter clean
flutter pub get
flutter build aar

把编译出的aar包依赖进原生项目就大功告成了,最后正常走打原生包的流程。

写在最后

Flutter是真正的好东西,对创业者相当友好,达到高级开发后,大大节省开发和维护时间,因为只维护一份代码。当你把核心算法用Dart实现后,原生的壳实际上是可以下发给别人开发的,这又进一步节省了开发时间,前提是你的项目先要稳定盈利。欢迎体验混合开发出的app www.pgyer.com/cryptotools 。

相关推荐
蒲公英内测分发42 分钟前
智能投影仪参加海外展会,未上架的 Android 配套 App 怎么让客户限时试用?
android
ii_best1 小时前
按键精灵手机端开发安卓版实战:手写一个可最小化、可拖动的「运行日志悬浮窗」(附完整 源码 + 踩坑记录)
android·ios·智能手机·自动化·ai编程·按键精灵
终端安全笔记1 小时前
安卓做 MDM 管控,先分清三种注册入口
android·安全·智能手机
乌萨达2 小时前
手机模拟器安卓怎么用?电脑安装应用、玩手游与账号同步指南
android·智能手机·电脑·雷电模拟器
美狐美颜SDK开放平台2 小时前
Android与iOS直播APP美颜有什么区别?视频美颜SDK开发详解
android·ios·音视频·视频美颜sdk
律宏阔4 小时前
Flutter Riverpod 3:统一打印 Provider 错误与自动重试日志
前端·flutter
春猿火4 小时前
某市-2026【网安·论道】misc-afterimage_note-wp
android
m0_738185825 小时前
Flutter 鸿蒙化实战:flutter_exif_plugin 适配 OpenHarmony,图片 EXIF 读写
flutter·华为·harmonyos·鸿蒙
恋猫de小郭5 小时前
Shopify 回应为什么从 RN 回到原生,为什么不用 KMP ?
android·前端·flutter
fundroid7 小时前
Android AI 开发,真正拉开差距的是工程闭环
android·ai·大模型·agent