flutter使用Chanel与原生通信

在Flutter中,Platform Channel允许Flutter与原生平台(如Android和iOS)之间进行双向通信,以便在Flutter应用程序和原生代码之间传递消息和调用功能。

以下是使用Platform Channel与原生通信的一般步骤:

1. 在Flutter端创建一个MethodChannel对象,用于发送消息给原生平台。通常在Flutter Widget的初始化方法中创建MethodChannel。

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

// 创建MethodChannel对象
MethodChannel _channel = MethodChannel('com.example.channelName');

2. 在Flutter端发送消息给原生平台,可以使用MethodChannel的invokeMethod方法。

复制代码
// 发送消息给原生平台
dynamic result = await _channel.invokeMethod('methodName', arguments);

3. 在原生平台(如Android和iOS)实现对应的方法,用于接收Flutter端发送的消息。

对于Android平台,可以在MainActivityApplication类中注册MethodChannel,并实现对应的方法。

java 复制代码
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {
    private static final String CHANNEL = "com.example.channelName";

    @Override
    public void configureFlutterEngine(FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
                .setMethodCallHandler((call, result) -> {
                    if (call.method.equals("methodName")) {
                        // 处理Flutter端发送的消息
                        String arg = call.arguments.toString();
                        // 执行相应的操作
                        // ...
                        // 将结果返回给Flutter端
                        result.success("Result from native");
                    } else {
                        result.notImplemented();
                    }
                });
    }
}

对于iOS平台,在AppDelegate.m文件中注册MethodChannel,并实现对应的方法。

复制代码
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  
  FlutterViewController *controller = (FlutterViewController *)self.window.rootViewController;
  FlutterMethodChannel *channel = [FlutterMethodChannel
      methodChannelWithName:@"com.example.channelName"
            binaryMessenger:controller.binaryMessenger];
  
  [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
    if ([@"methodName" isEqualToString:call.method]) {
      // 处理Flutter端发送的消息
      NSString *arg = call.arguments;
      // 执行相应的操作
      // ...
      // 将结果返回给Flutter端
      result(@"Result from native");
    } else {
      result(FlutterMethodNotImplemented);
    }
  }];
  
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

通过以上步骤,你可以在Flutter端和原生代码之间进行双向通信。

以下是我项目初期的调研代码块:

flutter的代码:

复制代码
class GetxStatePage extends StatefulWidget {
  const GetxStatePage({super.key});

  @override
  State<StatefulWidget> createState() {
    return GetxStatePageState();
  }
}

class GetxStatePageState extends State<GetxStatePage> {
  late MethodChannel _channel;

  @override
  void initState() {
    super.initState();
    //初始化MethodChannel,通道名称"multiple-flutters",Android端ios也要统一
    _channel = const MethodChannel('multiple-flutters');

  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: SGColors.white,
          title: const Text(
            'Getx',
            style: TextStyle(color: SGColors.textColor),
          ),
        ),
        body: Center(
          child: InkWell(
            onTap: () {
              String value = "Hello from Flutter";
              //这里定义方法和参数
              _channel.invokeMethod<void>("nextData", {'data': value});
              // 在此处添加您希望执行的点击事件
              print('跳转到Android');
            },
            child: SizedBox(
              width: 100,
              height: 100,
              child: Text("Getx"),
            ),
          ),
        ),
      ),
    );
  }
}

我们再看看Android端的实现代码:首先打通通道需要engine,channel,与flutter端的统一就行;

复制代码
class EngineBindings(
    activity: Activity, delegate: EngineBindingsDelegate, entrypoint: String,
    initialRoute: String) :
    DataModelObserver {
    val channel: MethodChannel
    val engine: FlutterEngine
    val delegate: EngineBindingsDelegate

    init {
        // This has to be lazy to avoid creation before the FlutterEngineGroup.
        val dartEntrypoint =
            DartExecutor.DartEntrypoint(
                FlutterInjector.instance().flutterLoader().findAppBundlePath(), entrypoint
            )
        // engine = BaseApplication.getApplication().engines.createAndRunEngine(activity, dartEntrypoint)
        engine = BaseApplication.getApplication().engines.createAndRunEngine(activity, dartEntrypoint, initialRoute)
        this.delegate = delegate
        channel = MethodChannel(engine.dartExecutor.binaryMessenger, "multiple-flutters")
    }

    /**
     * This setups the messaging connections on the platform channel and the DataModel.
     */
    fun attach() {
        DataModel.instance.addObserver(this)
        channel.invokeMethod("setCount", DataModel.instance.counter)
        channel.setMethodCallHandler { call, result ->
            when (call.method) {
                "incrementCount" -> {
                    DataModel.instance.counter = DataModel.instance.counter + 1
                    result.success(null)
                }
                "next" -> {
                    this.delegate.onNext()
                    result.success(null)
                }
                "nextData" -> {
                    val data: String? = call.argument("data")
                    this.delegate.onNext(data)
                    result.success(null)
                }
                else -> {
                    result.notImplemented()
                }
            }
        }
    }

    /**
     * This tears down the messaging connections on the platform channel and the DataModel.
     */
    fun detach() {
        engine.destroy();
        DataModel.instance.removeObserver(this)
        channel.setMethodCallHandler(null)
    }

    override fun onCountUpdate(newCount: Int) {
        channel.invokeMethod("setCount", newCount)
    }

}

具体的activity必须继承FlutterActivity,且这个类必须在主配置清单AndroidMainfest.xml中配置:

复制代码
<activity
  android:name=".ui.demo.SingleFlutterActivity"
  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  android:exported="true"
  android:hardwareAccelerated="true"
  android:windowSoftInputMode="adjustResize" />

class FlutterToAndroidActivity : FlutterActivity(), EngineBindingsDelegate {
  var mFlutterApi: SGAndroid2Flutter? = null

  private val engineBindings: EngineBindings by lazy {
    EngineBindings(activity = this, delegate = this, entrypoint = FlutterRouter.MESSAGE_CENTER_ENTRY_POINTER, initialRoute = "${FlutterRouter.MESSAGE_CENTER_ROUTER}?psId=1234")
  }

  override fun onDestroy() {
    super.onDestroy()
    engineBindings.detach()
  }

  override fun provideFlutterEngine(context: Context): FlutterEngine? {
    return engineBindings.engine
  }

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    engineBindings.attach()
    setContentView(layout.activity_flutter_to_android)
    val extraString = intent.getStringExtra("extraString")
    tv_center.text = extraString

    val binaryMessenger: BinaryMessenger = provideFlutterEngine(this)!!.getDartExecutor().getBinaryMessenger()
    mFlutterApi = SGAndroid2Flutter(binaryMessenger)

    tv_center.setOnClickListener {
      callFlutterMethod()
    }
  }

  private fun callFlutterMethod() {
    val handler = Handler(Looper.getMainLooper())
    (0..2)
      .map { it.toLong() * 100 }
      .forEach {
        handler.postDelayed(it) {
          mFlutterApi?.sendData(it.toString()) {  // 必须在主线程中调用
            println("从 Flutter 获取到的值是:$it ") // true,回调在主线程
          }
        }
      }
  }

  override fun onNext() {
  }

  override fun onNext(str: String?) {
    
  }
}

就可以在onNext的方法中调用我们的操作;

复制代码
/**
 * flutter 调用原生的方法,原生写法
 * */
 
override fun onNext(str: String?) {

  val flutterIntent = Intent(this, FlutterToAndroidActivity::class.java)
  flutterIntent.putExtra("extraString", str)
  startActivity(flutterIntent)
}

最后执行,flutter跳转FlutterToAndroidActivity成功,flutter成功调用原生Android的方法。

体会:

之前一直使用纯flutter开发,当需要原生加flutter开发的时候,其实成本更大了。

他既需要Android写好桥接代码,又需要ios写一套,flutter端的是一套。

为什么会这样?因为船大难掉头,一些大的现有项目没办法短时间改技术栈,一些公司会拿出一部分试试水。部分代码迁移。为以后的项目打基础。

遇到些特殊的需求,会更麻烦,比如我们这种做法:需要在原生端获取网络数据,去请求接口,然后把数据传递给flutter,而一开始请求哪个接口,传哪些参数又需要flutter传给原生,Android和ios两端去实现。

所以在项目中我们用到了pigeon的插件,这样就不用写太多的代码,通信的过程pigeon会帮你自动生成,可以看我下一篇文章实践!

https://juejin.cn/post/7270861556031700992

相关推荐
xiaolizi5674898 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100018 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜8 小时前
Python入门篇【文件处理】
android·java·python
我不是8神8 小时前
gin与gorm框架知识点总结
ios·iphone·gin
遥不可及zzz11 小时前
Android 接入UMP
android
奋斗的小青年!!12 小时前
Flutter浮动按钮在OpenHarmony平台的实践经验
flutter·harmonyos·鸿蒙
Coder_Boy_13 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab13 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言
冬奇Lab13 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
冬奇Lab15 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化