热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:利用Flutter如何优雅的调用Android原生方法?

篇首语:本文由编程笔记#小编为大家整理,主要介绍了利用Flutter如何优雅的调用Android原生方法?相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了利用 Flutter 如何优雅的调用 Android 原生方法?相关的知识,希望对你有一定的参考价值。






Flutter 的优势与缺点

Flutter 作为一个跨平台的移动 UI 框架,可以快速在 iosandroid 上构建高质量的原生用户界面。可以说是一套代码做到了多端运行,我们常说的 Flutter 跨平台,其实是 UI 跨平台,编写好了一套 UI 代码,就可以在 IOS、Android、Web 上呈现出同样的效果,节省了大量的人力成本,这也是 Flutter 越来越流行的原因之一。

å©ç¨ Flutter å¦ä½ä¼éçè°ç¨ Android åçæ¹æ³ï¼

然而 Flutter 也有它的缺点,很明显的是它并不能直接调用平台的系统功能,比如使用蓝牙、相机、GPS、音量、电池等,因此要在 Flutter 中调用这些能力就必须和原生平台进行通信。


Flutter 架构概览

了解一个框架的全貌,有助于我们从更高的视角去看待一门新技术,而避免深陷代码细节,无法自拔。首先来看一张官方给出的 Flutter 整体架构图,如下。

官方将 Flutter 框架大致分为了三层,Framework、Engine、Embedder。下面我将详细讲解一下这三层到底是什么,在实际开发中承担着怎样的角色。


Dart Framework 层

作为一个 Flutter 开发者,辛勤的码农,你每天都在这片土地挥洒着汗水。 你每天使用的各种 UI 组件(Flutter UI 控件已经快接近 400 个了),各种 Flutter Package,Flutter Plugin,层出不穷的第三方库让你感到头皮发凉。所以我不过多介绍大家都应该懂了吧,Dart 是最好的语言~


Engine 层

Flutter 引擎,官方是这样介绍它的。



Flutter 的核心,主要使用 C++ 编写,提供了 Flutter 应用所需的原语。当需要绘制新一帧的内容时,引擎将负责对需要合成的场景进行栅格化。它提供了 Flutter 核心 API 的底层实现,包括图形(通过 
Skia)、文本布局、文件及网络 IO、辅助功能支持、插件架构和 Dart 运行环境及编译环境的工具链。

我觉得官方描述得已经很详细了,总结一下就是:它负责 Flutter UI 的渲染以及宿主的交互,接入了 Engine 的就叫做宿主,如 Android 品台接入了 Flutter Engine,那么宿主就是 Android 平台。

Flutter Engine 是开源的,在 github 上可以找到,传送门 github.com/flutter/eng… 直观感受下这个 Engine 项目都是用哪些语言编写的,如下图。其实主要语言还是 C++,其中 Dart 很多是测试代码。


Embedder 平台嵌入层

官方是这样介绍它的。



平台嵌入层是用于呈现所有 Flutter 内容的原生系统应用,它充当着宿主操作系统和 Flutter 之间的粘合剂的角色。当你启动一个 Flutter 应用时,嵌入层会提供一个入口,初始化 Flutter 引擎,获取 UI 和栅格化线程,创建 Flutter 可以写入的纹理。嵌入层同时负责管理应用的生命周期,包括输入的操作(例如鼠标、键盘和触控)、窗口大小的变化、线程管理和平台消息的传递。 Flutter 拥有 Android、iOS、Windows、macOS 和 Linux 的平台嵌入层,当然,开发者可以创建自定义的嵌入层

我觉得官方这段解释得同样很好,我几乎无法有更好的解释~但我还是要谈谈自己的见解,因为从程序员的角度看代码比谈概念更具体。Embedder 层的代码同样包含于 Engine 项目中,如下图。


Embedder 层代码整体可以分为两大块


  • 各平台的 Embedder 层代码,用于接入 Flutter Engine。如 Android 平台 Embedder 是用 Java 写的,当然还有与其对应的 C++ 代码,方便 Java 调用 JNI 来和 Flutter Engine 之间通信。自然 IOS 就是 Object-C 了。
  • 共用的 Embedder 层代码,C++ 编写, 用于平台消息传递等功能。

了解了 Flutter 架构,下面开始进入实战环节。


Flutter 如何与特定平台进行通信

本小节再次强调“特定平台”这个概念,因为 Flutter 它只是一个 UI 跨平台的框架,读者需要牢记于心,凡是涉及到平台相关的功能,还是必须要由原生平台来实现。本文以 Flutter 在 Android 平台上的应用,来讲解 Flutter 该怎样和 Android 原生进行通信

Flutter 与特定平台进行通信的流程大致是这样的。


  • Flutter 通过类似 JNI 方法调用的方式与 Flutter Engine 通信
  • Flutter Engine 层调用特定平台的 Embedder 层代码
  • 特定平台接收到来自 Embedder 层的消息,进行业务处理

反之,特定平台想和 Flutter 进行通信,过程刚好和上面相反。


使用 MethodChannel 通道进行方法调用

Flutter 与特定平台进行通信需要通过“平台通道”,细心的读者可能已经发现,平台通道(Platform Channels)被官方划分在 Engine 层。平台通道分为三种类型,分别是 BasicMessageChannel、MethodChannel、EventChannel。其中 MethodChannel 它使用异步方法调用的方式进行平台通信,这也是最常用的一种方式。


编写 Flutter 端代码

这里以官方的一个手机电量查询例子来演示整个方法调用过程,Flutter 端代码如下。优雅的做法是,遵循职责单一的原则,将每一个方法通道封装成一个类。比如我这个通道是用来管理电量的,那么就叫 BatteryChannel ,所有和电量有关的方法都封装在这个类中。

class BatteryChannel {
static const _batteryChannelName = "cn.blogss/battery"; // 1.方法通道名称
static MethodChannel _batteryChannel;
static void initChannels(){
_batteryChannel = MethodChannel(_batteryChannelName); // 2\\. 实例化一个方法通道
}
// 3\\. 异步任务,通过平台通道与特定平台进行通信,获取电量,这里的宿主平台是 Android
static getBatteryLevel() async {
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 页面中这样做就行了。

class BatteryRoute extends StatefulWidget {
@override
State createState() {
return BatteryRouteState();
}
}
class BatteryRouteState extends State {
String _batteryLevel = 'Unknown battery level.';
// 3.异步获取到电量,然后重新渲染页面
getBatteryLevel() async{
_batteryLevel = await BatteryChannel.getBatteryLevel();
setState(() {});
}
@override
void initState() {
super.initState();
BatteryChannel.initChannels(); // 1\\. 初始化通道
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("BatteryRoute"),
centerTitle: true,
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new ElevatedButton(
child: new Text('Get Battery Level'),
onPressed: (){
getBatteryLevel(); // 2\\. 调用通道方法
},
),
new Text(_batteryLevel),
],
),
),
);
}
}

编写 Android 端代码

Android 端代码与 Flutter 端类似,如下所示。同样这个类叫 BatteryChannel,下面是 Kotlin 写的,没了解过的读者理解上来可能有点难度。不过它也很简单,这个通道就负责电量的查询了。只需实现 MethodChannel.MethodCallHandler 接口,重写 onMethodCall 方法,这样 Flutter 端的方法调用就会进入到这里。

class BatteryChannel(flutterEngine: BinaryMessenger, context: Context): MethodChannel.MethodCallHandler {
private val batteryChannelName = "cn.blogss/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;
}
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
}
}

然后我们还要在 MainActivity 中实例化一下这个通道,如下。常用的做法是在 configureFlutterEngine 这个方法中实例化我们的通道就行了,有多少个通道,就在这里实例化多少个通道。

class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
BatteryChannel(flutterEngine.dartExecutor.binaryMessenger,context) // 实例化通道
}
}

最后看下效果。


写在最后

本文详细介绍了 Flutter 框架概览,分析了 Dart Framework、Engine、Embedded 三层实际开发中所处的位置,然后通过代码实战,Flutter 通过平台通道与 Android 平台进行通信,查询到了手机电量。读者应该对这两部分知识有了深刻的理解与运用,下一篇,我将继续带领大家更深层次的探索平台通道通信机制!




推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
author-avatar
jin冫g_-_-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有