Flutter和Native之间进行通信

Flutter和Native之间通讯,是日常开发中经常需要用到的功能。
本文介绍了Flutter和Native如何进行通讯,以及在引入FlutterBoost的情况下,如何进行Flutter和Native的通讯。
如果想下载Demo源码,可以直接拉到最后面。

Flutter和Native通信基础

Flutter和Native之间通信的常见场景
  • 初始化Flutter时Native向Dart传递数据
  • Native发送数据给Dart
  • Dart发送数据给Native
  • Dart发送数据给Native,然后Native回传数据给Dart
Flutter和Native通信的机制

Flutter和Native通信使用Channel(平台通道)在客户端(UI)和主机(平台)之间传递

Channel支持的数据类型

在这里插入图片描述

Channel

Flutter定义了三种不同类型的Channel

  • BasicMessageChannel:用于使用指定的编解码器对消息进行编码和解码,属于双向通信,可以 Native 端主动调用,也可以Flutter主动调用。
  • MethodChannel:Flutter 与 Native 端相互调用,调用后可以返回结果,可以 Native 端主动调用,也可以Flutter主动调用,属于双向通信。此方式为最常用的方式, Native 端调用需要在主线程中执行。
  • EventChannel:用于数据流(event streams)的通信, Native 端主动发送数据给 Flutter,通常用于状态的监听,比如网络变化、传感器数据等。

Flutter和Native通信示例

首先,我们要新建一个Android原生项目,和一个Flutter module,并使其在同一个文件夹下
在这里插入图片描述
并将其配置,使其能够进行混合开发,具体详见 Flutter与Android Native进行混合开发

在Flutter Module中,新建BatteryChannel.dart
class BatteryChannel(flutterEngine: BinaryMessenger, context: Context) :
    MethodChannel.MethodCallHandler {
    private val batteryChannelName = "com.liubike/battery"
    private var channel: MethodChannel
    private var mContext: Context

    companion object {
        private const val TAG = "BatteryChannel"
    }

    init {
        Log.d(TAG, "init")
        channel = MethodChannel(flutterEngine, batteryChannelName)
        channel.setMethodCallHandler(this)
        mContext = context;
        Log.d(TAG, "init2")
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        Log.d(TAG, "onMethodCall: " + call.method)
        if (call.method == "getBatteryLevel") {
            val batteryLevel = getBatteryLevel()
            if (batteryLevel != -1) {
                result.success(batteryLevel)
            } else {
                result.error("UNAVAILABLE", "Battery level not available.", null)
            }
        } else {
            result.notImplemented()
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val batteryManager =
                mContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
            val intent = ContextWrapper(mContext).registerReceiver(
                null,
                IntentFilter(Intent.ACTION_BATTERY_CHANGED)
            )
            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) *
                    100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }

        return batteryLevel
    }
}
在Flutter Module中,进行调用
import 'package:flutter/material.dart';
import 'BatteryChannel.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  String _batteryLevel = 'Unknown battery level.';

  // 异步获取到电量,然后重新渲染页面
  void getBatteryLevel() async{
    _batteryLevel = await BatteryChannel.getBatteryLevel();
    setState(() {
    });
  }

  @override
  void initState() {
    super.initState();
    BatteryChannel.initChannels();  // 初始化通道
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),Text(
              '$_batteryLevel',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: getBatteryLevel,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), 
    );
  }
}

在原生项目中,新建BatteryChannel.kt
package com.liubike.fluttercommunicatenative

import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build
import android.util.Log
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

class BatteryChannel(flutterEngine: BinaryMessenger, context: Context) :
    MethodChannel.MethodCallHandler {
    private val batteryChannelName = "com.liubike/battery"
    private var channel: MethodChannel
    private var mContext: Context

    companion object {
        private const val TAG = "BatteryChannel"
    }

    init {
        channel = MethodChannel(flutterEngine, batteryChannelName)
        channel.setMethodCallHandler(this)
        mContext = context;
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        Log.d(TAG, "onMethodCall: " + call.method)
        if (call.method == "getBatteryLevel") {
            val batteryLevel = getBatteryLevel()
            if (batteryLevel != -1) {
                result.success(batteryLevel)
            } else {
                result.error("UNAVAILABLE", "Battery level not available.", null)
            }
        } else {
            result.notImplemented()
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val batteryManager =
                mContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
            val intent = ContextWrapper(mContext).registerReceiver(
                null,
                IntentFilter(Intent.ACTION_BATTERY_CHANGED)
            )
            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) *
                    100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }

        return batteryLevel
    }
}
在原生项目中,创建AgentActivity.kt

需要在configureFlutterEngine方法中,实例化BatteryChannel

package com.liubike.fluttercommunicatenative

import android.os.Bundle
import android.widget.Toast
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class AgentActivity : FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Toast.makeText(this, "agrent", Toast.LENGTH_SHORT).show()
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        BatteryChannel(flutterEngine.dartExecutor.binaryMessenger,this)
    }
}

不要忘了在AndroidManifest.xml中注册

<activity
    android:name=".AgentActivity"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize">
</activity>
最后,在MainActivity.kt中跳转到Flutter页面

跳转到Flutter页面后,再去获取电量

package com.liubike.fluttercommunicatenative

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var btn01 = findViewById<Button>(R.id.btn_01)
        btn01.setOnClickListener {
            /*
            //跳转到Flutter默认页面
			startActivity(
            	FlutterActivity.createDefaultIntent(this)
            )*/

            /*
            //跳转到Flutter指定页面
			startActivity(
                    FlutterActivity
                            .withNewEngine()
                            .initialRoute("/home")
                            .build(this)
            )*/

            startActivity(Intent(this,AgentActivity::class.java))
        }
    }
}
效果如下

在这里插入图片描述

引入FlutterBoost,进行Flutter和Native的通讯

其他地方,和Flutter官方是一样的,主要就是Channel实例化改到了FlutterBoost初始化的地方。

关于FlutterBoost的接入,可以看我的另一篇博客Flutter接入FlutterBoost进行跳转

在Flutter Module中,新建BatteryChannel.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class BatteryChannel {
  static const _batteryChannelName = "com.liubike/battery";  // 1.方法通道名称
  static MethodChannel _batteryChannel;

  static void initChannels(){
    _batteryChannel = MethodChannel(_batteryChannelName);  // 2. 实例化一个方法通道
  }

  // 3. 异步任务,通过平台通道与特定平台进行通信,获取电量,这里的宿主平台是 Android
  static getBatteryLevel() async {
    initChannels();
    String batteryLevel;
    try {
      final int result = await _batteryChannel.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    return batteryLevel;
  }
}
在Flutter Module中,进行调用
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/BatteryChannel.dart';

class SecondPage extends StatelessWidget {
  const SecondPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _batteryLevel = 'Unknown battery level.';
  // 异步获取到电量,然后重新渲染页面
  getBatteryLevel() async{
    _batteryLevel = await BatteryChannel.getBatteryLevel();
    setState(() {
    });
  }

  @override
  void initState() {
    super.initState();
    BatteryChannel.initChannels();  // 初始化通道
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            MaterialButton(
                color: Colors.green,
                onPressed: () {
                  getBatteryLevel();  // 2.调用通道方法
                },
                child: const Text("获取电量")),
            new Text(_batteryLevel),
          ],
        ),
      ),
    );
  }
}
在Android端新建BatteryChannel.kt
package com.liubike.boosttestandroid

import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build
import android.util.Log
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

class BatteryChannel(flutterEngine: BinaryMessenger, context: Context) :
    MethodChannel.MethodCallHandler {
    private val batteryChannelName = "com.liubike/battery"
    private var channel: MethodChannel
    private var mContext: Context

    companion object {
        private const val TAG = "BatteryChannel"
    }

    init {
        channel = MethodChannel(flutterEngine, batteryChannelName)
        channel.setMethodCallHandler(this)
        mContext = context;
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        Log.d(TAG, "onMethodCall: " + call.method)
        if (call.method == "getBatteryLevel") {
            val batteryLevel = getBatteryLevel()
            if (batteryLevel != -1) {
                result.success(batteryLevel)
            } else {
                result.error("UNAVAILABLE", "Battery level not available.", null)
            }
        } else {
            result.notImplemented()
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val batteryManager =
                mContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
            val intent = ContextWrapper(mContext).registerReceiver(
                null,
                IntentFilter(Intent.ACTION_BATTERY_CHANGED)
            )
            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) *
                    100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }

        return batteryLevel
    }
}

在Application中初始化FlutterBoost,并实例化Channel

FlutterBoost.instance().setup(this, new FlutterBoostDelegate() {
    @Override
    public void pushNativeRoute(FlutterBoostRouteOptions options) {
        String pageName = options.pageName();
        Log.i("NativeApp", "pageName:" + pageName);
        //这里根据options.pageName来判断你想跳转哪个页面
        Intent intent = null;
        if ("native_main".equals(pageName)){
            intent = new Intent(FlutterBoost.instance().currentActivity(), MainActivity.class);
        }else if("native_second".equals(pageName)){
            intent = new Intent(FlutterBoost.instance().currentActivity(), SecondActivity.class);
        }
        FlutterBoost.instance().currentActivity().startActivityForResult(intent, options.requestCode());
    }

    @Override
    public void pushFlutterRoute(FlutterBoostRouteOptions options) {
        Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class)
                .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
                .destroyEngineWithActivity(false)
                .uniqueId(options.uniqueId())
                .url(options.pageName())
                .urlParams(options.arguments())
                .build(FlutterBoost.instance().currentActivity());
        FlutterBoost.instance().currentActivity().startActivity(intent);
    }
}, engine -> {
    //Channel在这里进行实例化
    new BatteryChannel(engine.getDartExecutor(), this);
});
最后,在MainActivity.kt中跳转到Flutter页面

跳转到Flutter页面后,再去获取电量

Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class)
        .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.opaque)
        .destroyEngineWithActivity(false)
        .url("flutterPage") //在main.dart的routerMap中有注册 flutterPage
        .urlParams(params)
        .build(this);
startActivity(intent);
效果如下

在这里插入图片描述

相关源码下载

Flutter与Android Native进行混合开发,相互跳转,进行通信_示例Demo

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Flutter 和 React Native 都是强大的框架,各有优缺点。Flutter 提供了快速开发和卓越的性能,但是它仅支持 Android 和 iOS,而且在某些情况下没有明显的好处。React Native 则支持多种平台,并且可以使用 JavaScript 和 React 来开发应用,但是它在性能上可能不如 Flutter 那么出色。 ### 回答2: Flutter 是一种由 Google 开发的跨平台应用开发框架,而 React Native 是由 Facebook 创建的另一种跨平台应用开发框架。它们都可以用于开发高性能的移动应用,但却有各自的优缺点。 首先,让我们来谈谈 Flutter 的优点。Flutter 使用 Dart 编程语言,它的一大优点是具有热重载功能,这意味着开发者可以快速地看到他们所做的更改的实时预览。这加快了开发速度并提高了生产力。另外,Flutter 的UI组件是自定义的,不依赖于平台原生组件,这意味着应用程序的外观和性能在不同平台上都是一致的。Flutter 还具有很好的性能,应用程序可以实现原生级别的用户体验。最后,Flutter 的文档和社区资源相对丰富,为开发者提供了很好的支持。 然而,Flutter 也有一些缺点。首先,Flutter 相对较新,相比于 React Native,它的生态系统和第三方库更少。其次,由于自定义UI组件,一些原生平台功能可能需要使用平台通道(Paltform Channel)来实现,这可能需要额外的开发工作。最后,Flutter 使用 Dart 语言,这意味着开发者需要学习一门新的语言,这可能对一些开发者来说是一个学习曲线。 接下来,我们来看看 React Native 的优点。首先,React Native 是基于 JavaScript 的,这使得很多前端开发者可以很容易地上手。它还有一个强大的社区和生态系统,有很多第三方库和插件可供选择。第二,React Native 允许开发者使用原生代码,以提高性能和访问平台特有功能。这使得 React Native 适用于开发对原生平台特性有较高要求的应用程序。最后,React Native 有很好的跨平台性能,开发者可以同时为 Android 和 iOS 开发应用程序,这可以节省时间和资源。 然而,React Native 也有一些缺点。首先,应用程序的性能可能不如原生应用程序。虽然 React Native 为开发者提供了许多原生组件和API,但使用这些功能可能需要对底层原生代码的进一步了解。第二,由于使用 JavaScript,React Native 在一些复杂的应用程序中可能会遇到性能问题。最后,React Native 的文档和社区相对较好,但相较于 Flutter,信息不够丰富。 综上所述,Flutter 和 React Native 都有各自的优点和缺点。选择哪种框架取决于开发者的需求和资源。如果开发速度和性能是首要考虑因素,那么可以选择 Flutter。如果对原生特性的依赖度较高,并且有一支熟悉 JavaScript 的团队,那么 React Native 也是一个不错的选择。 ### 回答3: 一、Flutter的优点: 1. 高性能:Flutter使用自己的高性能渲染引擎Skia进行绘图操作,可以直接绘制UI界面,减少了与平台的交互,提高了性能表现。 2. 跨平台:Flutter可以同时在Android和iOS平台上运行,只需一份代码即可。开发者可以通过Flutter框架编写跨平台的应用,大大节省了开发时间和成本。 3. 热重载:Flutter支持热重载,修改代码后可以实时看到效果,提高了开发效率。 4. UI丰富:Flutter提供了丰富的UI组件,可以快速构建各种复杂的界面和动画效果。 5. 社区活跃:Flutter拥有庞大的开发者社区,文档和资源丰富,问题可以及时得到解决。 6. 学习曲线较低:Flutter使用Dart语言进行开发,语法简洁易学,对于有一定编程基础的开发者来说,上手相对容易。 二、Flutter的缺点: 1. 相对新生:相比于React NativeFlutter相对来说发展时间较短,生态环境相对较弱,一些功能和第三方库还在积极补充中。 2. 运行体积较大:由于Flutter自带了渲染引擎和一些基础组件,导致应用的安装包体积较大,对于初始下载和安装时间较长的应用来说,会对用户体验造成一定影响。 三、React Native的优点: 1. 生态丰富:React Native有较为完善的生态环境,因为React Native诞生更早,社区已经积累了多个成熟的第三方库和组件,可以快速引入使用,提高开发效率。 2. 稳定性较高:React Native经过多年发展已经相对较为稳定,出现的bug相对较少,更适合对稳定性要求较高的项目。 3. 社区活跃:React Native拥有庞大的开发者社区,问题可以及时得到解决。此外,社区提供的资源丰富,有很多优秀的教程、文章和开源项目供学习和借鉴。 四、React Native的缺点: 1. 性能问题:由于React Native是通过Bridge与原生代码进行通信,会造成一定的性能损耗。对于对性能要求较高的应用,可能需要进行一些优化。 2. 学习曲线相对陡峭:React Native使用JavaScript语言进行开发,相对于Flutter的Dart语言来说,学习曲线较陡峭,对于没有JavaScript基础的开发者可能更为困难。 3. 动画效果受限:相对于Flutter的自绘UI,React Native对于一些复杂的动画效果支持相对较弱,需要借助于原生代码进行实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值