flutter踩坑记录(二)--基本使用及原生flutter交互篇

本文记录了Flutter开发的踩坑经历,介绍了在Android原生项目中创建UI、编写Dart代码以实现原生页面加载FlutterView。重点阐述了Android原生与Flutter交互的实现,通过Method Channel和Message Channel两种常用渠道,分别给出原生和Flutter部分的代码示例及方法解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

flutter踩坑记录目录

flutter踩坑记录(一)--项目准备阶段   https://blog.youkuaiyun.com/hjr365708064/article/details/95454939

flutter踩坑记录(三)-- 项目打包  https://blog.youkuaiyun.com/hjr365708064/article/details/95473183

通过上一篇的踩坑记录(一),我相信你此时已经集成flutter模块到原生项目中,也迫不及待去使用flutter和体验flutter与原生的交互(目前大多数使用场景还是要与原生集成混合开发的)

Android中创建Flutter UI

Flutter提供两种方法引入,一个是View,一个是Fragment,(目前使用我使用的view方式引用,这种方式也更灵活方法,有一个viewGroup载体就可加载flutterView)

在oncreat中添加view(下面提到的rootLayout即为布局内一个空的ConstraintLayout的viewId,使用kotlin只需要有id就可使用view)

布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible"
        android:id="@+id/rootLayout"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

activity中代码文件

val flutterView = Flutter.createView(this, lifecycle, "home_page")
val layoutParams = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT,
        ConstraintLayout.LayoutParams.MATCH_PARENT)
rootLayout.addView(flutterView, layoutParams)

createView方法说明:

第二个参数是Lifecycle对象,第三个参数是route(flutter页面跳转路径),这个参数Flutter端可以通过window.defaultRouteName获取

此时原生端加载flutterView载体已经搭建好,我们去看下flutter部分

dart代码的编写

import 'package:flutter/material.dart';

import 'list.dart';

 

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

class MyApp extends StatelessWidget {

// This widget is the root of your application.

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Flutter Demo',

theme: ThemeData(

primarySwatch: Colors.blue,

),

home: MyHomePage(title: 'Flutter Demo Home Page'),

routes: {

"home_page": (context) => MyHomePage(),

},

);

}

}

此时已经实现了原生页面中加入了flutterView的页面显示,可对于我们来说还远远不够,更重要的原生与flutter交互应该是大部分原生开发者更关心的方面

参考链接 https://blog.youkuaiyun.com/weixin_33943347/article/details/91430352

Andriod 原生与flutter交互


google为原生与flutter交互创建了channel渠道来实现,主要有3种,message,method,engine,目前常使用的是前2种

method channel 实现

原生activity内代码:

首先我们先定义channel 名称

private val CHANNEL = "demo.plugin"

method  channel 交互使用主要是使用了回调方式,这一点和原生与h5交互很类似,主要可用于flutter调用原生信息,调用方法等

//从flutter中调回原生页面
        MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
            when {
                call.method == "interaction" -> {
//                    val intent = Intent(this@FlutterTestPageActivity,
//                            PersonalSettingActivity::class.java)
//                    startActivity(intent)
                    val id = call.arguments as Int
                    ToastUtil.show(mContext!!,"收到的id为$id")
                }
                call.method == "methodId" -> result.success(12)
                else -> result.notImplemented()
            }
        }

flutter部分大部分代码实现

class _MyHomePageState extends State<MyHomePage> {

//原生与flutter部分渠道名一定要统一

final demoPlugin = const MethodChannel('demo.plugin');

num id = 0;

@override

void initState() {

super.initState();

getMethodId();

}

 

getMethodId() async {

var id = await demoPlugin.invokeMethod('methodId');

setState(() {

this.id = id;

});

}

widget显示部分

Text('需要的id为${this.id}'),

Container(

padding: EdgeInsets.only(top: 10.0),

child: RaisedButton(

child: Text('现在是Flutter'),

onPressed: () {

demoPlugin.invokeMethod('interaction', 123);

},

),

),

方法解释说明:

call.method == "interaction"  用来从flutter给原生发送信息或者打开原生页面的实现

call.method == "methodId"   用来flutter页面初始化从原生处取所需消息

message channel 渠道实现

message channel 交互使用主要是方便实现flutter与原生的消息传递,例如初始化页面时传递token给flutter页面,或者flutter按钮点击操作传递信息回原生页面,主要用于字符串等传递,主要使用 BasicMessageChannel传递

activity部分代码

private val CHANNEL = "demo.plugin"
private var messageChannel: BasicMessageChannel<String>? =null(string是自定义的传递消息的泛型)
val flutterView = Flutter.createView(this,lifecycle,"flutter_view")
val layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
        LinearLayout.LayoutParams.MATCH_PARENT)
linearLayout.addView(flutterView,layoutParams)
/**
 * 初始化通信通道
 * 参数一:FlutterView实例对象
 * 参数二:消息通道名字(key)
 * 参数三:消息解码器(用于处理通信消息类型)
 */
messageChannel = BasicMessageChannel(flutterView,CHANNEL, StringCodec.INSTANCE)
//处理来自Flutter中发送的消息
messageChannel!!.setMessageHandler { p0, p1 ->
    //具体处理接收到的从Flutter中发送的消息 p0
    Log.e("setMessageHandler",p0)
    p1?.reply("")
}
//延时发送,确保页面初始化完成后发送数据
Handler().postDelayed({run {
    messageChannel?.send(accessToken!!)
}},2000)

此时activity对于message channel的设置已完成

dart部分代码

//注册消息通道

static const BasicMessageChannel<String> platform =

BasicMessageChannel<String>("demo.plugin", StringCodec());

String message = "测试";

widget部分代码

Column(

children: <Widget>[

Text(message),

RaisedButton(

onPressed: () {

platform.send('给原生页面发消息');

},

child: Text('给原生页面发消息'),

),

InkWell(

child: Text('获取ID'),

onTap: () {

_getPicUploadId();

},

)

],

)

具体处理messageHandler逻辑

Future<String> _handleMessage(String message) async {

setState(() {

this.message = message;

// SharePreferencesUtil().setString('token', message);

});

return "";

}

 

@override

void initState() {

super.initState();

platform.setMessageHandler(_handleMessage);

}

至此已展示两种常用消息通道的基本使用,如需更详细使用可参考Flutter Platform channel详解

链接为 https://www.jianshu.com/p/cb96d62f5042

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值