小工具知识网

当前位置: 首页 > 行业知识 > Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

行业知识

Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

2026-11-01 03:07:31 来源:互联网转载

前言

本文主要讲解 Flutter 和 Android原生之间,页面相互跳转、传参,

但其中用到了两端相互通信的知识,非常建议先看完这篇 讲解通信的文章:

Flutter 与 Android原生 相互通信:BasicMessageChannel、MethodChannel、EventChannel_flutter eventchannel methodchannel basemessagechan-CSDN博客

当前案例 Flutter SDK版本:3.13.2

Flutter使用多个轻量型引擎,进行混合开发,是从 2.0 开始的,大大的减轻了内存压力;

轻量型引擎开发-官方介绍视频:https://www.youtube.com/watch?v=p6cK_0jp2ag

Flutter和原生端的关系

混合路由栈

如果是纯Flutter开发,只会有一个Flutter引擎,如果是混合开发,原生端 需要为每个从原生端跳转的Flutter页面创建独立的引擎 (也可以单例,但单例写法需要处理一些问题,这个到 FlutterEngineGroup 章节会具体讲解);

比如:

1.0 从 Android_A页面  ==== 跳转到 ==== Flutter_A页面,Android端需要为Flutter_A页面,创建Flutter引擎;

1.1 紧接着,从 Flutter_A页面 ==== 跳转到 ==== Flutter_B页面,就不需要,它俩共用一个引擎;

1.2 每个Flutter引擎都有自己的路由栈,且这个路由栈只能管理Flutter页面;

1.3 使用Flutter提供的 Navigator.pop(context); 方法,可以从 Flutter_B页面 回退到 Flutter_A页面,但无法从 Flutter_A页面 回退到 Android_A,会黑屏,因为Flutter栈里面没有Android页面,可以使用 Navigator.canPop(context); 来检查Flutter路由栈中,是否还有其他路由;

1.4 如果不使用 Navigator.pop(context); 回退方法,使用手机自带的 Back按键 / 左滑屏幕 进行回退,是没有问题的,因为这种回退方式调用的是原生API,Android原生不光提供FlutterView渲染Flutter页面结果,还会创建FlutterActivity和FlutterView进行绑定;

1.5 看到这,大家应该理解,为什么说Flutter只是UI框架了吧;

Android 和 Flutter 跳转

Android 跳转 Flutter

Flutter 跳转 Android

效果图

Android代码

FlutterRouterManager.kt

package com.example.flutter_nav_android.utilimport android.app.Activityimport io.flutter.embedding.android.FlutterActivityimport io.flutter.embedding.android.FlutterActivityLaunchConfigsimport io.flutter.embedding.engine.FlutterEngineimport io.flutter.embedding.engine.FlutterEngineCacheimport io.flutter.embedding.engine.dart.DartExecutorclass FlutterRouterManager(    val targetRoute: String,    val mEngineId: String,    val mContext: Activity) {    var mEngine: FlutterEngine? = null    init {        createCachedEngine()    }    companion object {        /**         * 获取缓存中的 Flutter引擎         */        @JvmStatic        fun getEngineCacheInstance(engineId: String): FlutterEngine? {            return FlutterEngineCache.getInstance().get(engineId)        }    }    /**     * 1、创建Flutter引擎     * 2、将初始命名路由,修改为目标页面路由     * 3、缓存Flutter引擎     */    fun createCachedEngine(): FlutterEngine {        val flutterEngine = FlutterEngine(mContext) // 创建Flutter引擎        // 将初始命名路由,修改为目标页面路由        flutterEngine.navigationChannel.setInitialRoute(targetRoute)        // 这一步,是在执行相关Dart文件入口的 main函数,将Flutter页面渲染出结果        // 原生端获取结果,进行最终渲染上屏        flutterEngine.dartExecutor.executeDartEntrypoint(            DartExecutor.DartEntrypoint.createDefault()        )        // 将加载好的引擎,存储起来        FlutterEngineCache.getInstance().put(mEngineId, flutterEngine)        mEngine = flutterEngine        return flutterEngine    }    /**     * 根据引擎ID,前往指定的Flutter页面     */    fun push() {        // 创建新的引擎(了解即可)        // mContext.startActivity(        //    FlutterActivity        //        .withNewEngine() // 创建引擎        //        .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent) // 背景改为透明,不然切换页面时,会闪烁黑色        //        .build(mContext))        // 使用缓存好的引擎(推荐)        mContext.startActivity(            FlutterActivity                .withCachedEngine(mEngineId) // 获取缓存好的引擎                .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent) // 背景改为透明,不然切换页面时,会闪烁黑色                .build(mContext)        )    }    /**     * 销毁当前Flutter引擎     */    fun destroy() {        mEngine?.destroy()    }}

PersonalActivity.kt

package com.example.flutter_nav_android.ui.activityimport android.graphics.Colorimport android.os.Bundleimport android.text.SpannableStringimport android.text.Spannedimport android.text.style.ForegroundColorSpanimport android.view.Viewimport androidx.appcompat.app.AppCompatActivityimport com.example.flutter_nav_android.databinding.ActivityPersonalBindingimport com.example.flutter_nav_android.util.FlutterRouterManagerimport io.flutter.embedding.engine.FlutterEngineimport io.flutter.plugin.common.MethodCallimport io.flutter.plugin.common.MethodChannelclass PersonalActivity : AppCompatActivity(), MethodChannel.MethodCallHandler, View.OnClickListener {    private lateinit var bind: ActivityPersonalBinding    private lateinit var homeFlutterEngine: FlutterEngine    private lateinit var loginRouterManager: FlutterRouterManager    private lateinit var loginMethodChannel: MethodChannel    private lateinit var homeMethodChannel: MethodChannel    private val METHOD_CHANNEL_LOGIN = "com.example.flutter_nav_android/login/method"    private val METHOD_CHANNEL_HOME = "com.example.flutter_nav_android/home/method"    private val NAV_FLUTTER_LOGIN_NOTICE = "navFlutterLoginNotice"    private val POP_NOTICE = "popNotice"    private val PERSONAL_POP_NOTICE = "personalPopNotice"    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        bind = ActivityPersonalBinding.inflate(layoutInflater)        setContentView(bind.root)        initView()        loginRouterManager = FlutterRouterManager("/login", "login_engine", this)        // 两端建立通信        loginMethodChannel = MethodChannel(loginRouterManager.mEngine!!.dartExecutor, METHOD_CHANNEL_LOGIN)        loginMethodChannel.setMethodCallHandler(this)        // 获取 Flutter Home页面的引擎,并且建立通信        homeFlutterEngine = FlutterRouterManager.getEngineCacheInstance("home_engine")!!        homeMethodChannel = MethodChannel(homeFlutterEngine.dartExecutor,METHOD_CHANNEL_HOME)    }    /**     * 监听来自 Flutter端 的消息通道     *     * call: Android端 接收到 Flutter端 发来的 数据对象     * result:Android端 给 Flutter端 执行回调的接口对象     */    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {        val methodName: String = call.method        when (methodName) { // 销毁 Flutter Login 页面            POP_NOTICE -> {                val age = call.argument("age")                getResult(age.toString())                loginRouterManager.mEngine!!.navigationChannel.popRoute()            }            else -> {                result.notImplemented()            }        }    }    override fun onClick(v: View?) {        when (v) {            bind.toFlutter -> { // 前往 Flutter Login 页面                val map: MutableMap = mutableMapOf()                map["name"] = "老王"                loginMethodChannel.invokeMethod(NAV_FLUTTER_LOGIN_NOTICE,map)                loginRouterManager.push()            }            bind.pop -> { // 销毁 Android Personal 页面                val map: MutableMap = mutableMapOf()                map["age"] = 18                homeMethodChannel.invokeMethod(PERSONAL_POP_NOTICE,map)                finish()            }        }    }    /**     * 初始化页面     */    private fun initView() {        bind.toFlutter.setOnClickListener(this)        bind.pop.setOnClickListener(this)        var name = intent.getStringExtra("name")        val title = "接收初始化参数:"        val msg = title + name        val ss = SpannableString(msg)        ss.setSpan(            ForegroundColorSpan(Color.RED),            title.length,            msg.length,            Spanned.SPAN_INCLUSIVE_EXCLUSIVE        )        bind.initV.text = ss    }    /**     * 获取上一页的返回参数     */    private fun getResult(age: String) {        val title = "接收上一页返回参数:"        val msg = title + age        val ss = SpannableString(msg)        ss.setSpan(            ForegroundColorSpan(Color.RED),            title.length,            msg.length,            Spanned.SPAN_INCLUSIVE_EXCLUSIVE        )        bind.resultV.text = ss    }    override fun onDestroy() {        super.onDestroy()        loginRouterManager.destroy()    }}

SchoolActivity.kt

package com.example.flutter_nav_android.ui.activityimport android.content.Intentimport android.os.Bundleimport androidx.appcompat.app.AppCompatActivityimport com.example.flutter_nav_android.databinding.ActivitySchoolBindingimport com.example.flutter_nav_android.util.FlutterRouterManagerimport io.flutter.embedding.android.FlutterFragmentimport io.flutter.embedding.android.TransparencyModeimport io.flutter.embedding.engine.FlutterEngineCacheimport io.flutter.plugin.common.MethodChannelclass SchoolActivity : AppCompatActivity() {    private lateinit var bind: ActivitySchoolBinding    private lateinit var bookFragment: FlutterFragment    private lateinit var studentFragment: FlutterFragment    private val METHOD_CHANNEL_BOOK = "com.example.flutter_nav_android/book/method"    private val METHOD_CHANNEL_STUDENT = "com.example.flutter_nav_android/student/method"    private val NAV_FLUTTER_BOOK_NOTICE = "navFlutterBookNotice"    private val NAV_FLUTTER_STUDENT_NOTICE = "navFlutterStudentNotice"    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        bind = ActivitySchoolBinding.inflate(layoutInflater)        setContentView(bind.root)        initView()        initChannel()    }    /**     * 建立通信     */    private fun initChannel() {        val bookEngine = FlutterRouterManager.getEngineCacheInstance("book_engine")        val bookChannel = MethodChannel(bookEngine!!.dartExecutor,METHOD_CHANNEL_BOOK)        val map: MutableMap = mutableMapOf()        map["title"] = "Book"        bookChannel.invokeMethod(NAV_FLUTTER_BOOK_NOTICE,map)        val studentEngine = FlutterRouterManager.getEngineCacheInstance("student_engine")        val studentChannel = MethodChannel(studentEngine!!.dartExecutor,METHOD_CHANNEL_STUDENT)        val map2: MutableMap = mutableMapOf()        map2["title"] = "Student"        studentChannel.invokeMethod(NAV_FLUTTER_STUDENT_NOTICE,map2)    }    /**     * 初始化页面     */    private fun initView() {        bookFragment = FlutterFragment.withCachedEngine("book_engine")            .transparencyMode(TransparencyMode.transparent) // 背景透明,避免切换页面,出现闪烁            .shouldAttachEngineToActivity(false) // 是否让Flutter控制Activity,true:可以 false:不可以,默认值 true            .build()        supportFragmentManager            .beginTransaction()            .add(bind.bookFragment.id, bookFragment)            .commit()        studentFragment = FlutterFragment.withCachedEngine("student_engine")            .transparencyMode(TransparencyMode.transparent) // 背景透明,避免切换页面,出现闪烁            .shouldAttachEngineToActivity(false) // 是否让Flutter控制Activity,true:可以 false:不可以,默认值 true            .build()        supportFragmentManager            .beginTransaction()            .add(bind.studentFragment.id, studentFragment)            .commit()    }    // ================================ 这些是固定写法,Flutter需要这些回调 ================================    override fun onPostResume() {        super.onPostResume()        bookFragment.onPostResume()        studentFragment.onPostResume()    }    override fun onNewIntent(intent: Intent) {        super.onNewIntent(intent)        bookFragment.onNewIntent(intent)        studentFragment.onNewIntent(intent)    }    override fun onBackPressed() {        bookFragment.onBackPressed()        studentFragment.onBackPressed()    }    override fun onRequestPermissionsResult(        requestCode: Int,        permissions: Array,        grantResults: IntArray    ) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults)        bookFragment.onRequestPermissionsResult(            requestCode,            permissions,            grantResults        )        studentFragment.onRequestPermissionsResult(            requestCode,            permissions,            grantResults        )    }    override fun onUserLeaveHint() {        bookFragment.onUserLeaveHint()        studentFragment.onUserLeaveHint()    }    override fun onTrimMemory(level: Int) {        super.onTrimMemory(level)        bookFragment.onTrimMemory(level)        studentFragment.onTrimMemory(level)    }}

MainActivity.kt

package com.example.flutter_nav_android.ui.activityimport android.content.Intentimport android.graphics.Colorimport android.text.SpannableStringimport android.text.Spannedimport android.text.style.ForegroundColorSpanimport android.view.Viewimport androidx.appcompat.app.AppCompatActivityimport com.example.flutter_nav_android.databinding.ActivityMainBindingimport com.example.flutter_nav_android.util.FlutterRouterManagerimport io.flutter.plugin.common.MethodCallimport io.flutter.plugin.common.MethodChannelclass MainActivity : AppCompatActivity(), MethodChannel.MethodCallHandler, View.OnClickListener {    private lateinit var bind: ActivityMainBinding    private lateinit var homeMethodChannel: MethodChannel    private val METHOD_CHANNEL_HOME = "com.example.flutter_nav_android/home/method"    private val NAV_ANDROID_PERSONAL_NOTICE = "navAndroidPersonalNotice"    private val NAV_FLUTTER_HOME_NOTICE = "navFlutterHomeNotice"    private val POP_NOTICE = "popNotice"    private lateinit var homeRouterManager: FlutterRouterManager    private lateinit var bookRouterManager: FlutterRouterManager    private lateinit var studentRouterManager: FlutterRouterManager    override fun onCreate(savedInstanceState: android.os.Bundle?) {        super.onCreate(savedInstanceState)        bind = ActivityMainBinding.inflate(layoutInflater)        setContentView(bind.root)        bind.toFlutter.setOnClickListener(this)        bind.toFlutterFragment.setOnClickListener(this)        homeRouterManager = FlutterRouterManager("/home", "home_engine", this)        // 两端建立通信        homeMethodChannel = MethodChannel(homeRouterManager.mEngine!!.dartExecutor,METHOD_CHANNEL_HOME)        homeMethodChannel.setMethodCallHandler(this)        // 这里Fragment案例的        bookRouterManager = FlutterRouterManager("/book", "book_engine", this)        studentRouterManager = FlutterRouterManager("/student", "student_engine", this)    }    /**     * 监听来自 Flutter端 的消息通道     *     * call: Android端 接收到 Flutter端 发来的 数据对象     * result:Android端 给 Flutter端 执行回调的接口对象     */    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {        val methodName: String = call.method        when (methodName) {            NAV_ANDROID_PERSONAL_NOTICE -> { // Flutter Home 页面 前往 Android Personal 页面                val intent = Intent(this, PersonalActivity::class.java)                intent.putExtra("name",call.argument("name"))                startActivity(intent)            }            POP_NOTICE -> { // 销毁 Flutter Home 页面                val age = call.argument("age")                getResult(age.toString())                homeRouterManager.mEngine!!.navigationChannel.popRoute()            }            else -> {                result.notImplemented()            }        }    }    override fun onClick(v: View?) {        when (v) {            bind.toFlutter -> { // 前往 Flutter Home 页面                val map: MutableMap = mutableMapOf()                map["name"] = "张三"                homeMethodChannel.invokeMethod(NAV_FLUTTER_HOME_NOTICE,map)                homeRouterManager.push()            }            bind.toFlutterFragment -> {                val intent = Intent(this, SchoolActivity::class.java)                startActivity(intent)            }        }    }    /**     * 获取上一页的返回参数     */    private fun getResult(age: String) {        val title = "接收上一页返回参数:"        val msg = title + age        val ss = SpannableString(msg)        ss.setSpan(            ForegroundColorSpan(Color.RED),            title.length,            msg.length,            Spanned.SPAN_INCLUSIVE_EXCLUSIVE        )        bind.resultV.text = ss    }    override fun onDestroy() {        super.onDestroy()        homeRouterManager.destroy()        bookRouterManager.destroy()        studentRouterManager.destroy()    }}

activity_personal.xml

                                                        

activity_school.xml

                                        

activity_main.xml

                                                

AndroidManifest.xml

                                                                                                                                                                                                    

Flutter代码

book.dart

import 'package:flutter/material.dart';import 'package:flutter/services.dart';class Book extends StatefulWidget {  const Book({super.key});  @override  State createState() => _BookState();}class _BookState extends State {  String title = '';  static const String METHOD_CHANNEL_BOOK = 'com.example.flutter_nav_android/book/method';  static const String NAV_FLUTTER_BOOK_NOTICE = 'navFlutterBookNotice';  @override  void initState() {    super.initState();    MethodChannel bookMethodChannel = const MethodChannel(METHOD_CHANNEL_BOOK);    bookMethodChannel.setMethodCallHandler(methodHandler);  }  /// 监听来自 Android端 的消息通道  /// Android端调用了函数,这个handler函数就会被触发  Future methodHandler(MethodCall call) async {    final String methodName = call.method;    switch (methodName) {      case NAV_FLUTTER_BOOK_NOTICE: // 进入当前页面        {          title = call.arguments['title'];          setState(() {});          return 0;        }      default:        {          return PlatformException(              code: '-1',              message: '未找到Flutter端具体实现函数',              details: '具体描述'); // 返回给Android端        }    }  }  @override  Widget build(BuildContext context) {    return Scaffold(      backgroundColor: Colors.amberAccent,      body: Container(        width: MediaQuery.of(context).size.width,        height: MediaQuery.of(context).size.height,        alignment: Alignment.center,        child: Text(          'Flutter $title',          style: const TextStyle(            fontWeight: FontWeight.bold,            color: Colors.red,            fontSize: 20,          ),        ),      ),    );  }}

home.dart

import 'package:flutter/material.dart';import 'package:flutter/services.dart';class Home extends StatefulWidget {  const Home({super.key});  @override  State createState() => _HomeState();}class _HomeState extends State {  late MethodChannel homeMethodChannel;  String name = '';  String age = '';  static const String METHOD_CHANNEL_HOME = 'com.example.flutter_nav_android/home/method';  static const String NAV_ANDROID_PERSONAL_NOTICE = 'navAndroidPersonalNotice';  static const String NAV_FLUTTER_HOME_NOTICE = 'navFlutterHomeNotice';  static const String POP_NOTICE = 'popNotice';  static const String PERSONAL_POP_NOTICE = 'personalPopNotice';  @override  void initState() {    super.initState();    homeMethodChannel = const MethodChannel(METHOD_CHANNEL_HOME);    homeMethodChannel.setMethodCallHandler(methodHandler);  }  /// 监听来自 Android端 的消息通道  /// Android端调用了函数,这个handler函数就会被触发  Future methodHandler(MethodCall call) async {    final String methodName = call.method;    switch (methodName) {      case NAV_FLUTTER_HOME_NOTICE: // 进入当前页面        {          name = call.arguments['name'];          setState(() {});          return 0;        }      case PERSONAL_POP_NOTICE: // Android Personal 页面 销毁了        {          age = '${call.arguments['age']}';          setState(() {});          return 0;        }      default:        {          return PlatformException(              code: '-1',              message: '未找到Flutter端具体实现函数',              details: '具体描述'); // 返回给Android端        }    }  }  /// 销毁当前页面  popPage() {    if (Navigator.canPop(context)) { // 检查Flutter路由栈中,是否还有其他路由      Navigator.pop(context);    } else {      Map map = {'age': 12};      homeMethodChannel.invokeMethod(POP_NOTICE, map);    }  }  /// 前往 Android Personal 页面  navAndroidPersonal() {    Map map = {'name': '李四'};    homeMethodChannel.invokeMethod(NAV_ANDROID_PERSONAL_NOTICE, map);  }  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(          backgroundColor: Colors.blue,          title: const Text(            'Flutter Home',            style: TextStyle(                fontWeight: FontWeight.w500,                fontSize: 26,                color: Colors.yellow),          )),      body: SizedBox(        width: MediaQuery.of(context).size.width,        height: MediaQuery.of(context).size.height,        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          crossAxisAlignment: CrossAxisAlignment.center,          children: [            Padding(              padding: const EdgeInsets.only(bottom: 16),              child: RichText(                  text: TextSpan(                      text: '接收初始化参数:',                      style: const TextStyle(color: Colors.black, fontSize: 20),                      children: [                    TextSpan(                      text: name,                      style: const TextStyle(color: Colors.red,fontWeight: FontWeight.bold),                    )                  ])),            ),            Padding(              padding: const EdgeInsets.only(bottom: 16),              child: RichText(                  text: TextSpan(                      text: '接收上一页返回参数:',                      style: const TextStyle(color: Colors.black, fontSize: 20),                      children: [                    TextSpan(                      text: age,                      style: const TextStyle(color: Colors.red,fontWeight: FontWeight.bold),                    )                  ])),            ),            Padding(              padding: const EdgeInsets.only(bottom: 8),              child: ElevatedButton(                onPressed: navAndroidPersonal,                child: const Text(                  '前往 Android Personal',                  style: TextStyle(fontSize: 20),                ),              ),            ),            ElevatedButton(              onPressed: popPage,              child: const Text(                '返回 上一页',                style: TextStyle(fontSize: 20),              ),            ),          ],        ),      ),    );  }}

login.dart

import 'package:flutter/material.dart';import 'package:flutter/services.dart';class Login extends StatefulWidget {  const Login({super.key});  @override  State createState() => _LoginState();}class _LoginState extends State {  late MethodChannel loginMethodChannel;  String name = '';  final String METHOD_CHANNEL_LOGIN = 'com.example.flutter_nav_android/login/method';  static const String NAV_FLUTTER_LOGIN_NOTICE = 'navFlutterLoginNotice';  final String POP_NOTICE = 'popNotice';  @override  void initState() {    super.initState();    loginMethodChannel = MethodChannel(METHOD_CHANNEL_LOGIN);    loginMethodChannel.setMethodCallHandler(methodHandler);  }  /// 监听来自 Android端 的消息通道  /// Android端调用了函数,这个handler函数就会被触发  Future methodHandler(MethodCall call) async {    final String methodName = call.method;    switch (methodName) {      case NAV_FLUTTER_LOGIN_NOTICE: // 进入当前页面        {          name = call.arguments['name'];          setState(() {});          return 0;        }      default:        {          return PlatformException(code: '-1', message: '未找到Flutter端具体实现函数', details: '具体描述'); // 返回给Android端        }    }  }  /// 销毁当前页面  popPage() {    if (Navigator.canPop(context)) { // 检查Flutter路由栈中,是否还有其他路由      Navigator.pop(context);    } else {      Map map = {'age': 28};      loginMethodChannel.invokeMethod(POP_NOTICE, map);    }  }  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(          backgroundColor: Colors.blue,          title: const Text(            'Flutter Login',            style: TextStyle(                fontWeight: FontWeight.w500,                fontSize: 26,                color: Colors.yellow),          )),      body: SizedBox(        width: MediaQuery.of(context).size.width,        height: MediaQuery.of(context).size.height,        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          crossAxisAlignment: CrossAxisAlignment.center,          children: [            Padding(              padding: const EdgeInsets.only(bottom: 16),              child: RichText(                  text: TextSpan(                      text: '接收初始化参数:',                      style: const TextStyle(color: Colors.black, fontSize: 20),                      children: [                    TextSpan(                      text: name,                      style: const TextStyle(color: Colors.red,fontWeight: FontWeight.bold),                    )                  ])),            ),            ElevatedButton(              onPressed: popPage,              child: const Text(                '返回 上一页',                style: TextStyle(fontSize: 20),              ),            ),          ],        ),      ),    );  }}

student.dart

import 'package:flutter/material.dart';import 'package:flutter/services.dart';class Student extends StatefulWidget {  const Student({super.key});  @override  State createState() => _StudentState();}class _StudentState extends State {  String title = '';  static const String METHOD_CHANNEL_STUDENT = 'com.example.flutter_nav_android/student/method';  static const String NAV_FLUTTER_STUDENT_NOTICE = 'navFlutterStudentNotice';  @override  void initState() {    super.initState();    MethodChannel bookMethodChannel = const MethodChannel(METHOD_CHANNEL_STUDENT);    bookMethodChannel.setMethodCallHandler(methodHandler);  }  /// 监听来自 Android端 的消息通道  /// Android端调用了函数,这个handler函数就会被触发  Future methodHandler(MethodCall call) async {    final String methodName = call.method;    switch (methodName) {      case NAV_FLUTTER_STUDENT_NOTICE: // 进入当前页面        {          title = call.arguments['title'];          setState(() {});          return 0;        }      default:        {          return PlatformException(              code: '-1',              message: '未找到Flutter端具体实现函数',              details: '具体描述'); // 返回给Android端        }    }  }  @override  Widget build(BuildContext context) {    return Scaffold(      backgroundColor: Colors.cyan,      body: Container(        width: MediaQuery.of(context).size.width,        height: MediaQuery.of(context).size.height,        alignment: Alignment.center,        child: Text(          'Flutter $title',          style: const TextStyle(            fontWeight: FontWeight.bold,            color: Colors.white,            fontSize: 20,          ),        ),      ),    );  }}

main.dart

import 'package:flutter/material.dart';import 'package:flutter_nav_android/book.dart';import 'package:flutter_nav_android/student.dart';import 'home.dart';import 'login.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,      ),      routes: {        '/home': (context) => const Home(),        '/login': (context) => const Login(),        '/book': (context) => const Book(),        '/student': (context) => const Student(),      },      initialRoute: '/home',    );  }}

踩坑

  • 一个路由坑,Flutter 加载 根命名路由标识,默认是 " / ",如果你在Flutter端使用了 " / " 作为根路由页面,有时候,从Android 跳转 Flutter页面时,它会将 根路由页面 先push进栈,再push你的目标页面进栈,会多出一个页面;
  • 所有我直接不用 " / " 标识,而使用页面对应的路由标识字符串,来指定根路由。
    // 原来带坑的写法// routes: {//    '/': (context) => const Home(),//    '/login': (context) => const Login(),//    '/personal': (context) => const Personal()// },// initialRoute: '/',// 解决方式的写法routes: {    '/home': (context) => const Home(),    '/login': (context) => const Login(),    '/personal': (context) => const Personal() },initialRoute: '/home',

    奇技淫巧

    在案例中,我使用的是 命名路由 和 Channel方式 进行 页面跳转、传参,下面直接使用引擎进行 页面跳转、传参,但实用价值不高,因为弊端太大;

    比如:

    • 只提供了List类型,进行传参;
    • 目标Flutter页面内的widget,默认参数会全部失效;
    • Flutter的Widget默认参数,是由主文件内的 MaterialApp 组件提供的,一个Flutter应用,一般只会使用一个 MaterialApp,它代表返回一个App,如果将目标Flutter页面套上 MaterialApp ,可以解决这个默认参数问题,但会引发 路由问题;
    • 不过也有适用场景:让每个Flutter页面完全独立,之间没有任何交互,比如跳转、数据共享等等,这样路由就不需要了,让每个Flutter页面都使用 MaterialApp,当作App和原生交互;

      综上所述,大家将这种方式当作扩展知识就好了。

      Android代码

      class MainActivity : AppCompatActivity(), View.OnClickListener {    ... ...     override fun onCreate(savedInstanceState: android.os.Bundle?) {        super.onCreate(savedInstanceState)        ... ...         val flutterEngine = FlutterEngine(this)        // 定义参数        val dartEntrypointArgs = mutableListOf()        dartEntrypointArgs.add("张三")        // 这种方式传参数,会导致这个Flutter页面中的Widget默认参数,全部失效,        // 这种只有 Dart主入口文件,比如main.dart的 main函数才能接收到参数        // void main(List) {}        // flutterEngine.dartExecutor.executeDartEntrypoint(        //    DartExecutor.DartEntrypoint.createDefault(),        //    dartEntrypointArgs        // )        // 这种可以指定页面接收,但需要在主入口文件里先声明               // void showPersonal(List args) {}        flutterEngine.dartExecutor.executeDartEntrypoint(            DartExecutor.DartEntrypoint(                FlutterInjector.instance().flutterLoader().findAppBundlePath(),                "showPersonal"), // 找到目标Flutter页面提供的 暴露函数            dartEntrypointArgs)        FlutterEngineCache.getInstance().put("personal_engine", flutterEngine)    }    override fun onClick(v: View?) {        ... ...         val map: MutableMap = mutableMapOf()        map["name"] = "张三"        startActivity(            FlutterActivity                .withCachedEngine("personal_engine") // 获取缓存好的引擎                .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent) // 背景改为透明,不然切换页面时,会闪烁黑色                .build(this))    }}

      Flutter代码

      main.dart(主文件)

      import 'package:flutter/material.dart';import 'package:flutter_nav_android/personal.dart';void main(List args) {  debugPrint('args:$args');  runApp(const MyApp());}/// 注解说明文档:https://mrale.ph/dartvm/compiler/aot/entry_point_pragma.html/// 注解:表明它可以在 AOT 模式下直接从本机或 VM 代码解析、分配或调用@pragma("vm:entry-point")void showPersonal(List args) { // 在主文件入口暴露出来  debugPrint('args:$args');  runApp(Personal(title: args.first));}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,      ),    );  }}

      personal.dart(目标页面)

      import 'package:flutter/material.dart';class Personal extends StatefulWidget {  final String? title;  const Personal({super.key,this.title});  @override  State createState() => _PersonalState();}class _PersonalState extends State {    /// 在这个页面中,使用的Widget 默认参数全部失效,外层套上 Material组件 也无效  @override  Widget build(BuildContext context) {    return Container(      color: Colors.white,      width: MediaQuery.of(context).size.width,      height: MediaQuery.of(context).size.height,      alignment: Alignment.center,      child: Directionality(          textDirection: TextDirection.ltr,          child: Text(            widget.title ?? '',            style: const TextStyle(              color: Colors.lightBlue,              fontSize: 30,            ),          )),    );  }}

      FlutterEngineGroup

      • 如果你接受以上缺点,可以使用 FlutterEngineGroup,这个东西就是换成了单例写法,我们自己写单例,需要处理一个问题,比如这个需求:同时获取两个Flutter引擎,这里就要通过判空新建一个Flutter引擎;
      • 而 FlutterEngineGroup 已经处理了这个问题,自首个Flutter引擎起,后面多出的Flutter引擎,都是其子类,如果只剩下最后一个,那么这个Flutter引擎将和首个Flutter引擎性能特征相同;
      • FlutterEngineGroup官方文档:多个 Flutter 页面或视图 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      • 从我个人体验上来说,不使用单例,性能也足够了,如果有很多混合的Flutter页面,那当我没说。
      • 我没找到创建子类Flutter引擎的相关代码,是从注解中发现的

        Debug 和 Release

        我用真机做测试,发现在Debug模式下,第一次从 Android 跳转 Flutter 会出现黑屏现象,但 打完包 或在 Release模式 就看不出来了;

        我们默认的运行模式就是 Debug模式,可以通过 修改IDE运行命令 --release,切换为 Release模式;

        源码地址

        GitHub - LanSeLianMa/flutter_nav_android: Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

上一篇:揭秘拼多多砍价真相,谁在暗中助力你砍价?

下一篇:瓦里奥轻松下载攻略,一键获取,快速上手!