Flutter 页面嵌入 Android原生 View

这篇具有很好参考价值的文章主要介绍了Flutter 页面嵌入 Android原生 View。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

文章主要讲解Flutter页面如何使用Android原生View,但用到了Flutter 和 Android原生 相互通信知识,建议先看完这篇讲解通信的文章

Flutter 与 Android原生 相互通信:BasicMessageChannel、MethodChannel、EventChannel-CSDN博客

数据观察监听,Flutter使用ValueNotifier,Android原生使用LiveData,在实体数据发生改变时,自动刷新。

效果图

Flutter 页面嵌入 Android原生 View,Flutter + Android 混合开发,flutter,android

图解

Flutter 页面嵌入 Android原生 View,Flutter + Android 混合开发,flutter,android

1、Android原生端

1.0 PlatformView

Android:ComputeLayoutPlatform.kt

package com.example.flutter_mix_android.ui.flutterplugin.platform;

import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.lifecycle.ViewModelProvider
import com.example.flutter_mix_android.R
import com.example.flutter_mix_android.bean.CountBean
import com.example.flutter_mix_android.databinding.LayoutComputeBinding
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView

/**
 * 封装成PlatformView
 */
class ComputeLayoutPlatform(
    context: Context,
    rootContext: Context,
    messenger: BinaryMessenger,
    viewId: Int,
    args: Any?,
) : FrameLayout(context), PlatformView, MethodChannel.MethodCallHandler {

    private lateinit var mChannel: MethodChannel
    private lateinit var bind: LayoutComputeBinding
    private lateinit var viewModel: CountBean

    companion object {
        // Android原生View 在Flutter引擎上注册的唯一标识,在Flutter端使用时必须一样
        private const val ANDROID_SEND_FLUTTER_DATA_NOTICE: String = "androidSendFlutterDataNotice" // Android端 向 Flutter端 发送数据
        private const val ANDROID_GET_FLUTTER_DATA_NOTICE: String = "androidGetFlutterDataNotice" // Android端 获取 Flutter端 数据
        private const val FLUTTER_SEND_ANDROID_DATA_NOTICE: String = "flutterSendAndroidDataNotice" // Flutter端 向 Android端 发送数据
        private const val FLUTTER_GET_ANDROID_DATA_NOTICE: String = "flutterGetAndroidDataNotice" // Flutter端 获取 Android端 数据
    }

    init {
        initChannel(messenger, viewId)
        initView()
        initData(rootContext, args)
    }

    /**
     * 初始化消息通道
     */
    private fun initChannel(messenger: BinaryMessenger, viewId: Int) {
        // 创建 Android端和Flutter端的,相互通信的通道
        // 通道名称,两端必须一致
        mChannel = MethodChannel(messenger, "flutter.mix.android/compute/$viewId")

        // 监听来自 Flutter端 的消息通道
        // Flutter端调用了函数,这个handler函数就会被触发
        mChannel.setMethodCallHandler(this)
    }

    /**
     * 初始化视图
     */
    private fun initView() {
        LayoutInflater.from(context).inflate(R.layout.layout_compute, this, true)
        bind = LayoutComputeBinding.bind(getChildAt(0))
        bind.add.setOnClickListener {
            val count: Int = viewModel.curNum.value ?: 0
            viewModel.curNum.value = count + 1
        }

        bind.androidSendFlutterData.setOnClickListener {
            androidSendFlutterData()
        }

        bind.androidGetFlutterData.setOnClickListener {
            androidGetFlutterData()
        }
    }

    /**
     * Android端 向 Flutter端 发送数据,PUT 操作
     */
    private fun androidSendFlutterData() {
        val map: MutableMap<String, Int> = mutableMapOf<String, Int>()
        map["androidNum"] = viewModel.curNum.value ?: 0

        mChannel.invokeMethod(
            ANDROID_SEND_FLUTTER_DATA_NOTICE,
            map,
            object : MethodChannel.Result {
                override fun success(result: Any?) {
                    Log.d("TAG", "success:$result")
                    updateFlutterNum((result as? Int) ?: 0)
                }

                override fun error(
                    errorCode: String,
                    errorMessage: String?,
                    errorDetails: Any?
                ) {
                    Log.d(
                        "TAG",
                        "errorCode:$errorCode --- errorMessage:$errorMessage --- errorDetails:$errorDetails"
                    )
                }

                /**
                 * Flutter端 未实现 Android端 定义的接口方法
                 */
                override fun notImplemented() {
                    Log.d("TAG", "notImplemented")
                }
            })
    }

    /**
     * Android端 获取 Flutter端 数据,GET 操作
     */
    private fun androidGetFlutterData() {
        // 说一个坑,不传参数可以写null,
        // 但不能这样写,目前它没有这个重载方法,invokeMethod第二个参数是Object类型,所以编译器不会提示错误
        // mChannel.invokeMethod(ANDROID_GET_FLUTTER_DATA_NOTICE, object : MethodChannel.Result {

        // public void invokeMethod(@NonNull String method, @Nullable Object arguments)

        mChannel.invokeMethod(
            ANDROID_GET_FLUTTER_DATA_NOTICE,
            null,
            object : MethodChannel.Result {
                override fun success(result: Any?) {
                    Log.d("TAG", "success:$result")
                    updateGetFlutterNum((result as? Int) ?: 0)
                }

                override fun error(
                    errorCode: String,
                    errorMessage: String?,
                    errorDetails: Any?
                ) {
                    Log.d(
                        "TAG",
                        "errorCode:$errorCode --- errorMessage:$errorMessage --- errorDetails:$errorDetails"
                    )
                }

                /**
                 * Flutter端 未实现 Android端 定义的接口方法
                 */
                override fun notImplemented() {
                    Log.d("TAG", "notImplemented")
                }
            })
    }

    /**
     * 初始化数据
     */
    private fun initData(rootContext: Context, args: Any?) {
        val owner = rootContext as FlutterFragmentActivity
        viewModel = ViewModelProvider(owner)[CountBean::class.java]
        bind.countBean = viewModel
        bind.lifecycleOwner = owner

        // 获取初始化时 Flutter端 向 Android 传递的参数
        val map: Map<String, Int> = args as Map<String, Int>
        viewModel.getFlutterNum.value = map["flutterNum"]
    }

    /**
     * 监听来自 Flutter端 的消息通道
     *
     * call: Android端 接收到 Flutter端 发来的 数据对象
     * result:Android端 给 Flutter端 执行回调的接口对象
     */
    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        // 获取调用函数的名称
        val methodName: String = call.method
        when (methodName) {
            FLUTTER_SEND_ANDROID_DATA_NOTICE -> {
                // 回调结果对象
                // 获取Flutter端传过来的数据
                val flutterCount: Int? = call.argument<Int>("flutterNum")
                updateFlutterNum(flutterCount ?: 0)
                result.success("success")

                // 回调状态接口对象,里面有三个回调方法
                // result.success(result: Any?)
                // result.error(errorCode: String, errorMessage: String?, errorDetails: Any?)
                // result.notImplemented()
            }

            FLUTTER_GET_ANDROID_DATA_NOTICE -> {
                result.success(viewModel.curNum.value)
            }

            else -> {
                result.notImplemented()
            }
        }
    }

    fun updateFlutterNum(flutterCount: Int) {
        viewModel.flutterNum.value = flutterCount
    }

    fun updateGetFlutterNum(flutterCount: Int) {
        viewModel.getFlutterNum.value = flutterCount
    }

    override fun getView(): View? {
        return this
    }

    override fun dispose() {}

}

1.1 PlatformViewFactory

Android:ComputeLayoutPlatformFactory.kt

package com.example.flutter_mix_android.ui.flutterplugin.factory

import android.content.Context
import com.example.flutter_mix_android.ui.flutterplugin.platform.ComputeLayoutPlatform
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工厂,创建PlatformView
 */
class ComputeLayoutPlatformFactory(
    private val rootContext: Context,
    private val messenger: BinaryMessenger, // 二进制信使
) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { // 消息编解码器

    private lateinit var computeLayoutPlatform: ComputeLayoutPlatform

    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        computeLayoutPlatform = ComputeLayoutPlatform(context, rootContext, messenger, viewId, args)
        return computeLayoutPlatform
    }

}

1.2 FlutterPlugin

Android:FlutterPlugin.kt

package com.example.flutter_mix_android.ui.flutterplugin.plugin;

import android.content.Context
import com.example.flutter_mix_android.ui.flutterplugin.factory.ComputeLayoutPlatformFactory
import io.flutter.embedding.engine.plugins.FlutterPlugin

/**
 * 将AndroidView 注册为 Flutter插件
 *
 * rootContext:这个context,我是用来作ViewModel观察的,setLifecycleOwner
 */
class ComputeLayoutPlugin(private val rootContext: Context) : FlutterPlugin {

    companion object {
        // Android原生View 在Flutter引擎上注册的唯一标识,在Flutter端使用时必须一样
        private const val viewType: String = "com.example.flutter_mix_android.ui.flutterplugin.platform/ComputeLayoutPlatform"
    }

    /**
     * 连接到flutter引擎时调用
     */
    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        // 将Android原生View 在Flutter引擎上注册
        binding.platformViewRegistry.registerViewFactory(
            viewType,
            ComputeLayoutPlatformFactory(rootContext, binding.binaryMessenger)
        )
    }

    /**
     * 与flutter引擎分离时调用
     */
    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {}

}

1.3 注册插件

Android:MainActivity.kt

Ps:建议大家直接使用FlutterFragmentActivity平替掉FlutterActivity,因为

FlutterActivity继承于Activity

FlutterFragmentActivity继承于FragmentActivity,它实现了 LifecycleOwnerViewModelStoreOwner

package com.example.flutter_mix_android.ui.activity

import com.example.flutter_mix_android.ui.flutterplugin.plugin.ComputeLayoutPlugin
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine

class MainActivity: FlutterFragmentActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        // 注册为Flutter插件
        flutterEngine.plugins.add(ComputeLayoutPlugin(this))
    }

}

1.4 实体 + LiveData

package com.example.flutter_mix_android.bean

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class CountBean : ViewModel() {

    var curNum: MutableLiveData<Int> = MutableLiveData<Int>() // Android端点击次数

    var flutterNum: MutableLiveData<Int> = MutableLiveData<Int>() // Flutter端点击次数(接收到的)

    var getFlutterNum: MutableLiveData<Int> = MutableLiveData<Int>() // Flutter端点击次数(主动获取的)

}

2、Flutter端

1.0 页面完整代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mix_android/bean/count_bean.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {

  final CountBean countBean = CountBean();

  late MethodChannel channel;

  // Android原生View 在Flutter引擎上注册的唯一标识,在Flutter端使用时必须一样
  final String viewType = 'com.example.flutter_mix_android.ui.flutterplugin.platform/ComputeLayoutPlatform';
  static const String FLUTTER_SEND_ANDROID_DATA_NOTICE = 'flutterSendAndroidDataNotice'; // Flutter端 向 Android端 发送数据
  static const String FLUTTER_GET_ANDROID_DATA_NOTICE = 'flutterGetAndroidDataNotice'; // Flutter端 获取 Android端 数据
  static const String ANDROID_SEND_FLUTTER_DATA_NOTICE = 'androidSendFlutterDataNotice'; // Android端 向 Flutter端 发送数据
  static const String ANDROID_GET_FLUTTER_DATA_NOTICE = 'androidGetFlutterDataNotice'; // Android端 获取 Flutter端 数据

  /// 初始化消息通道
  initChannel(int viewId) {
    channel = MethodChannel('flutter.mix.android/compute/$viewId'); // 创建 Flutter端和Android端的,相互通信的通道

    // 监听来自 Android端 的消息通道
    // Android端调用了函数,这个handler函数就会被触发
    channel.setMethodCallHandler(handler);
  }

  /// 监听来自 Android端 的消息通道
  /// Android端调用了函数,这个handler函数就会被触发
  Future<dynamic> handler(MethodCall call) async {
    // 获取调用函数的名称
    final String methodName = call.method;
    switch (methodName) {
      case ANDROID_SEND_FLUTTER_DATA_NOTICE:
        {
          int androidCount = call.arguments['androidNum'];
          countBean.androidNum.value = androidCount;
          return '$ANDROID_SEND_FLUTTER_DATA_NOTICE ---> success';
        }
      case ANDROID_GET_FLUTTER_DATA_NOTICE:
        {
          return countBean.curNum.value ?? 0;
        }
      default:
        {
          return PlatformException(
              code: '-1', message: '未找到Flutter端具体实现函数', details: '具体描述');
        }
    }
  }

  /// Flutter端 向 Android端 发送数据,PUT 操作
  flutterSendAndroidData() {
    Map<String, int> map = {'flutterNum': countBean.curNum.value};
    channel.invokeMethod(FLUTTER_SEND_ANDROID_DATA_NOTICE, map).then((value) {
      debugPrint('$FLUTTER_SEND_ANDROID_DATA_NOTICE --- Result:$value');
    }).catchError((e) {
      if (e is MissingPluginException) {
        debugPrint('$FLUTTER_SEND_ANDROID_DATA_NOTICE --- Error:notImplemented --- 未找到Android端具体实现函数');
      } else {
        debugPrint('$FLUTTER_SEND_ANDROID_DATA_NOTICE --- Error:$e');
      }
    });
  }

  ///  Flutter端 获取 Android端 数据,GET 操作
  flutterGetAndroidData() {
    channel.invokeMethod(FLUTTER_GET_ANDROID_DATA_NOTICE).then((value) {
      debugPrint('$FLUTTER_GET_ANDROID_DATA_NOTICE --- Result:$value');
      countBean.getAndroidNum.value = value ?? 0;
    }).catchError((e) {
      if (e is MissingPluginException) {
        debugPrint('$FLUTTER_GET_ANDROID_DATA_NOTICE --- Error:notImplemented --- 未找到Android端具体实现函数');
      } else {
        debugPrint('$FLUTTER_GET_ANDROID_DATA_NOTICE --- Error:$e');
      }
    });
  }

  /// 累计点击次数
  computeCount() {
    countBean.curNum.value += 1;
  }

  Widget computeWidget() {
    final ButtonStyle btnStyle = ElevatedButton.styleFrom(
        elevation: 0,
        padding: const EdgeInsets.symmetric(horizontal: 12),
        backgroundColor: Colors.white,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(35)));
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            'Flutter页面',
            style: TextStyle(
                color: Color(0xff0066ff),
                fontSize: 20,
                fontWeight: FontWeight.bold),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 16, bottom: 8),
            child: Row(
              children: [
                ValueListenableBuilder<int>(
                    valueListenable: countBean.curNum,
                    builder: (context, count, _) {
                      return Text('点击次数:$count',
                          style: const TextStyle(fontSize: 16));
                    }),
                Padding(
                  padding: const EdgeInsets.only(left: 16, right: 8),
                  child: ElevatedButton(
                    style: btnStyle,
                    onPressed: computeCount,
                    child: const Text('+1'),
                  ),
                ),
                ElevatedButton(
                  style: btnStyle,
                  onPressed: flutterSendAndroidData,
                  child: const Text('发送给Android端'),
                )
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(bottom: 8),
            child: Row(
              children: [
                ValueListenableBuilder(
                    valueListenable: countBean.getAndroidNum,
                    builder: (context, count, _) {
                      return Text('获取Android页面点击次数:$count',
                          style: const TextStyle(fontSize: 16));
                    }),
                Padding(
                  padding: const EdgeInsets.only(left: 16, right: 3),
                  child: ElevatedButton(
                    style: btnStyle,
                    onPressed: flutterGetAndroidData,
                    child: const Text('获取Android端数据'),
                  ),
                ),
              ],
            ),
          ),
          ValueListenableBuilder(
              valueListenable: countBean.androidNum,
              builder: (context, count, _) {
                return Text('接收Android端发送的点击次数:$count',
                    style: const TextStyle(fontSize: 16));
              }),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xffA4D3EE),
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: SafeArea(
          top: true,
          child: Column(
            children: [
              Expanded(
                  flex: 1,
                  child: AndroidView(
                    viewType: viewType, // Android原生View 在Flutter引擎上注册的唯一标识,在Flutter端使用时必须一样
                    creationParams: {'flutterNum': countBean.curNum.value}, // Flutter端 初始化时 向Android端 传递的参数
                    creationParamsCodec: const StandardMessageCodec(), // 消息编解码器
                    onPlatformViewCreated: (viewId) {
                      initChannel(viewId);
                      // 使用 viewId 构建不同名称的 MethodChannel,
                      // 主要应用于 多个相同AndroidView一起使用时,避免消息冲突
                      // List<MethodChannel> mChannels = [];
                      // mChannels.add(MethodChannel('flutter.mix.android/compute/$viewId'));
                      // mChannels[0].invokeMethod(method)
                      // mChannels[0].setMethodCallHandler((call) => null)
                    },
                  )),
              Expanded(flex: 1, child: computeWidget()),
            ],
          ),
        ),
      ),
    );
  }

}

1.1 实体 + ValueNotifier

import 'package:flutter/cupertino.dart';

class CountBean {

  ValueNotifier<int> curNum = ValueNotifier<int>(10); // Flutter端点击次数

  ValueNotifier<int> androidNum = ValueNotifier<int>(0); // Android端点击次数(接收到的)

  ValueNotifier<int> getAndroidNum = ValueNotifier<int>(0); // Android端点击次数(主动获取的)

}

6、源码地址

https://github.com/LanSeLianMa/flutter_mix_android文章来源地址https://www.toymoban.com/news/detail-810635.html

到了这里,关于Flutter 页面嵌入 Android原生 View的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 原生Android与uniapp开发的H5混合开发

    vue版本选择2.0  记住一点,打包H5前修改配置,否则在Android中打开会白屏,修改方式如下 打包成H5,打包后可以在浏览器打开确保有内容 assets文件夹没有就自己建 xml布局文件处加入一个webview标签 Activity的 onCreate周期加入如下代码 运行项目就可以看到uniAPP的页面了

    2024年02月21日
    浏览(32)
  • 微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转其他小程序如何操作?

     微信小程序appId查看方法: 1)有后台登录权限的情况下:登录微信公众平台后, 微信公众平台 微信公众平台,给个人、企业和组织提供业务服务与用户管理能力的全新服务平台。 https://mp.weixin.qq.com/ 点击右上角logo,在“帐号信息”中找到AppID(小程序ID) 2)没有后台登录权

    2024年02月11日
    浏览(46)
  • uniapp微信小程序在web-view嵌入的uniapp H5页面中预览word文件

    在小程序中预览文件可以使用uni.uploadFile下载后再uni.openDocument打开预览,但uni.openDocument API是不支持H5的,这时候可能会想到使用微软在线预览,但是实际出来的效果会存在各种兼容性问题。因此我们需要在h5页面中跳回小程序然后走小程序的预览文件逻辑。

    2024年02月11日
    浏览(46)
  • flutter和android互相调用、android原生项目与flutter module之间的交互、如何在flutter module中使用原生的方法

    bridge.dart MainActivity.kt MainActivity中 Flutter中 android项目依赖flutter module的方式网上有很多,这里就不做讲解。主要说一下这种情况下android如何与flutter module之间进行方法的调用 踩坑:期初我是想让flutter module调用它内部中的.android文件夹下的原生代码。.android文件夹下有Flutter、

    2023年04月08日
    浏览(37)
  • 微信小程序web-view嵌入uni-app H5页面,通过H5页面跳转企业微信客户聊天窗口如何操作?

    1)找到企业ID,登录 企业微信 企业微信 https://work.weixin.qq.com/wework_admin/loginpage_wx  2)找到接入链接  功能-客服-微信客服 微信公众平台,给个人、企业和组织提供业务服务与用户管理能力的全新服务平台。 https://mp.weixin.qq.com/

    2024年02月11日
    浏览(45)
  • 【flutter和android原生的异步】

    java android 中,是多线程的 1.flutter中不要以为异步就是多线程  2.flutter的线程隔离理论? UI 线程 : 在 Flutter 中,UI 线程负责处理用户界面的构建和渲染。所有与用户界面相关的操作,例如布局计算、绘制和处理用户输入等,都在 UI 线程中执行。 UI 线程是单线程的,也称为主

    2024年04月15日
    浏览(33)
  • Flutter 与原生交互(Android,iOS)

    本质上 Flutter 和 原生通信是通过 Channel 来完成的:Flutter中消息的传递是完全异步的; 消息使用 Channel(平台通道) 在客户端(UI) 和主机(p平台) Flutter 与 native端交互三种方式 1.BasicMessageChannel (用于传递字符串和半结构化信息,持续通信使用,例如dart端将服务器的数据陆续传入到

    2024年02月17日
    浏览(38)
  • flutter开发实战-MethodChannel实现flutter与原生Android双向通信

    flutter开发实战-MethodChannel实现flutter与原生Android双向通信 最近开发中需要原生Android与flutter实现通信,这里使用的MethodChannel MethodChannel:用于传递方法调用(method invocation)。 通道的客户端和宿主端通过传递给通道构造函数的通道名称进行连接 一个应用中所使用的所有通道名称

    2024年02月13日
    浏览(28)
  • 在Android原生项目中 创建 Flutter模块

    应用场景: 在已有的 Android原生项目中,引入Flutter模块,摸索了两天,终于给整出来了; 如果是新项目 ,最好直接创建Flutter项目,然后在Fluter的 android / ios目录中,写原生代码; 本文除了讲解 Android原生如何创建Flutter模块外,还会演示在使用 Gradle 高版本 和 低版本  时可

    2024年01月19日
    浏览(32)
  • Flutter 调用原生(Android)方法以及数据传输

    flutter是一个UI框架,有许多方法和功能只能靠原生自己来调用,但是我们怎么通过flutter去间接调用呢?官方给出了两种方法 在平台通道之间进行消息传递: 注:消息和响应以异步的形式进行传递,以确保用户界面能够保持响应。 flutter端: 然后找到android工程,打开MainActi

    2024年02月10日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包