在Flutter中调用Android的代码

参考

【Flutter 混合开发】嵌入原生View-Android

默认使用Android studioKotlin

基本配置

创建flutter项目

在终端执行

flutter create batterylevel

添加 Android 平台的实现

打开项目下的android/app/src/main/kotlin 下的 MainActivity.kt 文件。
在这里插入图片描述
我这里编辑器有提示,最好使用其推荐,这样代码会有提示
在这里插入图片描述
使用推荐后会新打开一个窗口,在原窗口里提示的错误也将不会再提示

MainActivity.kt

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class MainActivity : FlutterActivity() {
    // 在flutter引擎启动时,将自定义的插件添加到flutter 引擎的插件列表中
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine.plugins.add(MyPlugin())
    }
}

在项目文件下创建MyFlutterView.ktMyFlutterViewFactory.ktMyPlugin.kt 三个文件

  • MyFlutterView.kt编写的是原生安卓代码
  • MyFlutterViewFactory.kt一个自定义的Flutter平台视图工厂,用于创建创建Flutter平台视图并将其返回
  • MyPlugin.kt 创建一个自定义的Flutter插件,将自定义的Flutter平台视图工厂注册到Flutter引擎中,以便在Flutter应用中使用该自定义视图。
    在这里插入图片描述

MyFlutterView.kt

import android.content.Context
import android.view.View
import android.widget.TextView
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.platform.PlatformView

// context 上下文对象
// messenger 用于消息传递,BinaryMessenger二进制消息
// viewId View 生成时会分配一个唯一 ID
// args Flutter 传递的初始化参数
class MyFlutterView(
    context: Context,
    messenger: BinaryMessenger,
    viewId: Int,
    args: Map<String, Any>?
) :
    PlatformView {
    // PlatformView代表一个平台视图,它是Flutter和原生平台之间的桥梁。
    // PlatformView允许在Flutter应用中嵌入原生视图,并提供了与Flutter框架进行交互的方法。

    // 定义一个文本视图
    private val textView: TextView = TextView(context)

    init {
        // 初始化文本视图
        textView.text = "我是Android View"
    }

    // 获取文本视图
    override fun getView(): View {
        return textView
    }

    //  销毁
    override fun dispose() {

    }
}

MyFlutterViewFactory.kt

import android.content.Context
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

// 用于注册PlatformView
class MyFlutterViewFactory(private val messenger: BinaryMessenger) : PlatformViewFactory(
    StandardMessageCodec.INSTANCE
) {

    // 创建PlatformView
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        return MyFlutterView(context, messenger, viewId, args as Map<String, Any>?)
    }

}

MyPlugin.kt

"com.example.batterylevel/custom_platform_view" 是自定义平台视图的标识符,需要保证唯一。
标识符通常由小写字母、数字和斜杠(/)组成,并且不包含空格或特殊字符。
具体如何编写没查到,参考文章应该是 按着包名/视图的描述的格式,感觉挺好的

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.PluginRegistry

class MyPlugin : FlutterPlugin {

    // onAttachedToEngine 在Flutter插件与Flutter引擎绑定时被调用。
    // 在这个方法中,可以执行一些初始化操作,例如注册平台视图工厂、注册方法调用处理器等
    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        // 消息发送器
        val messenger: BinaryMessenger = binding.binaryMessenger
        //
        binding
            .platformViewRegistry
            .registerViewFactory(
                "com.example.batterylevel/custom_platform_view", MyFlutterViewFactory(messenger)
            )
    }

    // 注册视图
    companion object {
        
        fun registerWith(registrar: PluginRegistry.Registrar) {
            registrar
                .platformViewRegistry()
                .registerViewFactory(
                    "com.example.batterylevel/custom_platform_view",
                    MyFlutterViewFactory(registrar.messenger())
                )
        }
    }

    // 用于在插件从 Flutter 引擎中分离时执行清理操作。
    // 当插件不再需要与 Flutter 引擎通信时,例如应用关闭或插件被移除时,onDetachedFromEngine 方法会被调用。
    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {

    }
}

基本内容编写完成后回到flutter项目的部分,进行运行
main.dart

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '嵌入原生View-Android',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const PlatformViewDemo(),
    );
  }
}

class PlatformViewDemo extends StatelessWidget {
  const PlatformViewDemo({super.key});

  
  Widget build(BuildContext context) {
    platformView() {
      // 如果是安卓平台,则返回一个AndroidView对象
      // AndroidView 是 Flutter 提供的一个小部件,用于在 Flutter 中嵌入原生 Android 视图
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 标识符要保持一致
        return const AndroidView(
          viewType: 'com.example.batterylevel/custom_platform_view',
        );
      }
    }

    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: platformView(),
      ),
    );
  }
}

在这里插入图片描述

flutter与原生之间的通信

关于通信可以看一下这篇文章:Flutter与原生如何进行通信

简单的参数传递

flutter中的修改,main.dart

class PlatformViewDemoState extends State<PlatformViewDemo> {
  
  Widget build(BuildContext context) {
    platformView() {
      // 如果是安卓平台,则返回一个AndroidView对象
      // AndroidView 是 Flutter 提供的一个小部件,用于在 Flutter 中嵌入原生 Android 视图
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 标识符要保持一致
        return const AndroidView(
          viewType: 'com.example.batterylevel/custom_platform_view',
          creationParams: {'text': 'AndroidTextView122'},
          creationParamsCodec: StandardMessageCodec(),
        );
      }
    }

    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: platformView(),
      ),
    );
  }
}
  • creationParams :传递的参数,插件可以将此参数传递给 AndroidView 的构造函数。
  • creationParamsCodec :将 creationParams 编码后再发送给平台侧,它应该与传递给构造函数的编解码器匹配。值的范围:
    • StandardMessageCodec,这是 Flutter 默认的编解码器,用于序列化和反序列化标准数据类型,例如字符串、数字、布尔值、列表和映射
    • JSONMessageCodec,使用 JSON 格式进行序列化和反序列化。它可以用于传递复杂的数据结构,例如嵌套的映射和列表。
    • StringCodec,用于将字符串编码为字节流,并在需要时进行解码。它适用于只传递字符串类型的创建参数。
    • BinaryCodec,用于直接传递字节流类型的创建参数,不进行额外的编码或解码

修改 MyFlutterView.kt

class MyFlutterView(
    context: Context,
    messenger: BinaryMessenger,
    viewId: Int,
    args: Map<String, Any>?
) :
    PlatformView {
    // PlatformView代表一个平台视图,它是Flutter和原生平台之间的桥梁。
    // PlatformView允许在Flutter应用中嵌入原生视图,并提供了与Flutter框架进行交互的方法。

    // 定义一个文本视图
    private val textView: TextView = TextView(context)

    init {
        // 初始化文本视图
        // 没学过Kotlin,大体意思是参数存在则赋值
           args?.also { map ->
            println(map["text"])
            println("参数")
            textView.text = map["text"] as String
        }
    }

    // 获取文本视图
    override fun getView(): View {
        return textView
    }

    //  销毁
    override fun dispose() {

    }
}

在这里插入图片描述

使用MethodChannel 通信

main.dart

class PlatformViewDemoState extends State<PlatformViewDemo> {
  // 用于通信的通道
  static const platform = MethodChannel('com.flutter.guide.MyFlutterView');
  
  Widget build(BuildContext context) {
    platformView() {
      // 如果是安卓平台,则返回一个AndroidView对象
      // AndroidView 是 Flutter 提供的一个小部件,用于在 Flutter 中嵌入原生 Android 视图
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 标识符要保持一致
        return const AndroidView(
          viewType: 'com.example.batterylevel/custom_platform_view',
          creationParams: {'text': '向安卓传参数'},
          creationParamsCodec: StandardMessageCodec(),
        );
      }
    }

    return Scaffold(
        appBar: AppBar(),
        body: Column(
          children: [
            ElevatedButton(
                onPressed: () {
                  // invokeMethod 的作用是在特定的上下文中调用指定的方法。它接受两个参数:方法名称和一个包含参数的对象
                  platform.invokeMethod('setText', {'name': '张三', 'age': 18});
                },
                child: const Text("使用MethodChannel通信")),
            Expanded(child: platformView()!)
          ],
        ));
  }
}

修改 MyFlutterView.kt

class MyFlutterView(
    context: Context,
    messenger: BinaryMessenger,
    viewId: Int,
    args: Map<String, Any>?
) :
    PlatformView, MethodChannel.MethodCallHandler {
    // PlatformView代表一个平台视图,它是Flutter和原生平台之间的桥梁。
    // PlatformView允许在Flutter应用中嵌入原生视图,并提供了与Flutter框架进行交互的方法。

    // 定义一个文本视图
    private val textView: TextView = TextView(context)

    private var methodChannel: MethodChannel

    init {

        // 初始化文本视图
        // 没学过Kotlin,大体意思是参数存在则赋值
        args?.also { map ->
            textView.text = map["text"] as String
        }
        // com.flutter.guide.MyFlutterView 标识保证唯一,与flutter中的保持一致
        methodChannel = MethodChannel(messenger, "com.flutter.guide.MyFlutterView")
        methodChannel.setMethodCallHandler(this)
    }

    // 获取文本视图
    override fun getView(): View {
        return textView
    }

    //  销毁
    override fun dispose() {
        methodChannel.setMethodCallHandler(null)
    }

    // 方法调用处理器
    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        if (call.method == "setText") {
            val name = call.argument("name") as String?
            val age = call.argument("age") as Int?

            textView.text = "hello,$name,年龄:$age"
        } else {
            result.notImplemented()
        }
    }
}

注:

methodChannel = MethodChannel(messenger, "com.flutter.guide.MyFlutterView")
methodChannel.setMethodCallHandler(this)

必须放在

 args?.also { map ->
            textView.text = map["text"] as String
        }

后面,好像存在执行顺序的问题。如果放在前面, textView.text = map["text"] as String不会执行
在这里插入图片描述

flutter接收来自原生的消息
在flutter中使用invokeMethod调用原生的方法。在原生中处理对应方法时,如果要向flutter中返回消息可以使用

textView.text = "hello,$name,年龄:$age"
result.success("收到了来自flutter的调用")

在flutter中正常接收即可

ElevatedButton(
 onPressed: () async{
   // invokeMethod 的作用是在特定的上下文中调用指定的方法。它接受两个参数:方法名称和一个包含参数的对象
 var res = await  platform.invokeMethod('setText', {'name': '张三', 'age': 18});
 print(res);
 },
 child: const Text("使用MethodChannel通信"))

在这里插入图片描述

解决多个原生View通信冲突问题

这个看原文章就好了,主要是保证每一个通道都是唯一的。

原生 View 生成时,系统会为其生成唯一id:viewId,使用 viewId 构建不同名称的 MethodChannel。

class MyFlutterView(context: Context, messenger: BinaryMessenger, viewId: Int, args: Map<String, Any>?) : PlatformView, MethodChannel.MethodCallHandler {

    val textView: TextView = TextView(context)
    private var methodChannel: MethodChannel

    init {
        args?.also {
            textView.text = it["text"] as String
        }
        methodChannel = MethodChannel(messenger, "com.flutter.guide.MyFlutterView_$viewId")
        methodChannel.setMethodCallHandler(this)
    }
  ...
}

Flutter 端为每一个原生 View 创建不同的MethodChannel

var platforms = [];

AndroidView(
  viewType: 'plugins.flutter.io/custom_platform_view',
  onPlatformViewCreated: (viewId) {
    print('viewId:$viewId');
    platforms
        .add(MethodChannel('com.flutter.guide.MyFlutterView_$viewId'));
  },
  creationParams: {'text': 'Flutter传给AndroidTextView的参数'},
  creationParamsCodec: StandardMessageCodec(),
)

给第一个发送消息:

platforms[0]
    .invokeMethod('setText', {'name': 'laomeng', 'age': 18});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/368352.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MicroPython ESP32开发:快速参考

ESP32是使用非常广泛的一款微处理器&#xff0c;集成了WiFi和蓝牙模块&#xff0c;根据性能和应用场景的不同有很多不同的版本&#xff0c;本文是ESP32开发板在MicroPython环境下运行的快速参考&#xff0c;对于首次使用这个开发板在MicroPython下进行开发的应该会有一定的帮助…

会计的记账凭证

目录 一. 记账凭证的填制与审核1.1 收付款凭证1.2 转账凭证1.3 单式记账凭证 二. 记账凭证的编号 \quad 一. 记账凭证的填制与审核 \quad \quad 1.1 收付款凭证 \quad 注意︰ 凡是涉及货币资金之间收付款的业务如将库存现金存入银行或从银行提取现金等类经济业务。在实际工作中…

探索设计模式的魅力:为什么你应该了解装饰器模式-代码优化与重构的秘诀

设计模式专栏&#xff1a;http://t.csdnimg.cn/nolNS 开篇 在一个常常需要在不破坏封装的前提下扩展对象功能的编程世界&#xff0c;有一个模式悄无声息地成为了高级编程技术的隐形冠军。我们日复一日地享受着它带来的便利&#xff0c;却往往对其背后的复杂性视而不见。它是怎样…

幻兽帕鲁服务器多少钱?价格PK阿里云腾讯云华为云

2024年幻兽帕鲁服务器价格表更新&#xff0c;阿里云、腾讯云和华为云Palworld服务器报价大全&#xff0c;4核16G幻兽帕鲁专用服务器阿里云26元、腾讯云32元、华为云26元&#xff0c;阿腾云atengyun.com分享幻兽帕鲁服务器优惠价格表&#xff0c;多配置报价&#xff1a; 幻兽帕鲁…

【C++】C++入门— 类与对象初步介绍

C入门 1 认识面向对象2 类的引入3 类的定义类的定义方式 4 类的访问限定符及封装访问限定符封装 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 1 认识面向对象 C语言是面向过程的&#xff0c;关注…

位运算之妙用:识别独特数字(寻找单身狗)

目录 找单身狗1 图解&#xff1a; 代码如下&#xff1a; 找单身狗2 图解&#xff1a; 代码如下&#xff1a; 寻找单身狗1 从数组中 的1 2 3 4 5 1 2 3 4 中找出没有另一个相同的数与其匹配的数 这个问题的原理是利用异或运算的性质。异或运算&#xff08;XOR&#xff09…

java学习03 判断和循环

一 流程控制语句 1.流程控制语句分类 顺序结构 判断和选择结构(if, switch) 循环结构(for, while, do…while) 2. 顺序结构 顺序结构是程序中最简单最基本的流程控制&#xff0c;没有特定的语法结构&#xff0c;按照代码的先后顺序&#xff0c;依次执行&#xff0c;程序中…

Blender使用Rigify和Game Rig Tool基础

做动画需要的几个简要步骤&#xff1a; 1.建模 2.绑定骨骼 3.绘制权重 4.动画 有一个免费的插件可以处理好给引擎用&#xff1a;Game Rig Tool 3.6和4.0版本的 百度网盘 提取码&#xff1a;vju8 1.Rigify是干嘛用的&#xff1f; 》 绑定骨骼 2.Game Rig Tool干嘛用的&#xf…

Revit中使用依赖注入

依赖注入的技术已经很成熟&#xff0c;本文主要是说明一下Revit中的适用版本与介绍相关的开源项目。 版本问题 版本 目前的依赖注入包无法支持Revit 2020 以下的版本&#xff0c;原因是因为包中的依赖项与Revit本身的依赖项不一致导致的&#xff0c;所以说如果使用Revit DI…

2V2无人机红蓝对抗仿真

两架红方和蓝方无人机分别从不同位置起飞&#xff0c;蓝方无人机跟踪及击毁红方无人机 2020a可正常运行 2V2无人机红蓝对抗仿真资源-CSDN文库

探索Gin框架:Golang使用Gin完成文件上传

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。 前言 在之前的文章中&#xff0c;我们讲解了Gin框架的快速入门使用&#xff0c;今天我们来聊聊如何使用…

单细胞scATAC-seq测序基础知识笔记

单细胞scATAC-seq测序基础知识笔记 单细胞ATAC测序前言scATAC-seq数据怎么得出的&#xff1f; 该笔记来源于 Costa Lab - Bioinformatics Course 另一篇关于scRNA-seq的请移步 单细胞ATAC测序前言 因为我的最终目的是scATAC-seq的数据&#xff0c;所以这部分只是分享下我刚学…

c++类继承

一、继承的规则 &#xff08;1&#xff09;基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如&#xff0c;当继承方式为protected时&#xff0c;那么基类成员在派生类中的访问权限最高也为protected&#xff0c;高于protected会降级为protected&#xff0c;但低…

阿里云部署的幻兽帕鲁服务器,为什么没有一键更新游戏服务端、导入存档、可视化的游戏配置

如果有的朋友发现自己用阿里云部署的幻兽帕鲁服务器&#xff0c;找不到一键更新游戏服务端、一键导入存档、以及可视化的游戏配置。其实答案很简单&#xff0c;因为你的“阿里云计算巢”版本需要更新。你只需要更新到最新版&#xff0c;就可以拥有这些便捷的功能了。 具体的操…

【备战蓝桥杯】——循环结构终篇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-yl4Tqejg4LkjZLAM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

一文辨析清楚LORA、Prompt Tuning、P-Tuning、Adapter 、Prefix等大模型微调方法

本文探讨了大模型微调的核心概念和方法&#xff0c;详细介绍了如LoRA、Adapter Tuning、Prefix Tuning等多种微调策略。每种方法的原理、优势及适用场景都有详尽阐述&#xff0c;大家可以根据不同的应用需求和计算资源&#xff0c;选择到最合适自己的微调途径。 希望本文能对想…

Linux下grep命令详解

grep #文件内容过滤显示 #在指定的普通文件中查找并显示含有指定字符串的行&#xff0c;也可与管道符一起使用格式&#xff1a; grep-参数 查找条件 文件名 参数&#xff1a; 示例&#xff1a; [rootnode1 ~]# grep -n "root" /etc/passwd # -n&a…

LangChain结合通义千问的自建知识库

LangChain结合通义千问的自建知识库 在使用了通义千问API了之后&#xff0c;下一步就是构建知识库文档&#xff0c;使用了比较有名的LangChian&#xff0c;最后成果将自己的txt生成了知识向量库&#xff0c;最后我还把自己的论文生成了一个知识向量库&#xff0c;然后问他我的…

Java 基于 SpringBoot+Vue 的前后端分离的火车订票管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Cambalache in Ubuntu

文章目录 前言apt install flatpak这很ok后记 前言 gtkmm4相比gtkmm3有很多改革, 代码也干净了许多, 但在windows上开发 有ui设计器那自然方便很多, 但glade又不支持gtkmm4, windows上装Cambalache很是困难. 各种问题都找不到答案.于是 我用VMware虚拟机Ubuntu20.xx安装Cambal…