本文主要讲解 Flutter 和 Android原生之间,页面相互跳转、传参,
但其中用到了两端相互通信的知识,非常建议先看完这篇 讲解通信的文章:
Flutter 与 Android原生 相互通信:BasicMessageChannel、MethodChannel、EventChannel_flutter eventchannel methodchannel basemessagechan-CSDN博客
当前案例 Flutter SDK版本:3.13.2
如果是纯Flutter开发,只会有一个Flutter引擎,如果是混合开发,原生端 需要为每个从原生端跳转的Flutter页面创建独立的引擎;
比如:
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框架了吧;
FlutterRouterManager.kt
package com.example.flutter_nav_android.util
import android.app.Activity
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterActivityLaunchConfigs
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.dart.DartExecutor
class 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.activity
import android.graphics.Color
import android.os.Bundle
import android.text.SpannableString
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.example.flutter_nav_android.databinding.ActivityPersonalBinding
import com.example.flutter_nav_android.util.FlutterRouterManager
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class 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.activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.flutter_nav_android.databinding.ActivitySchoolBinding
import com.example.flutter_nav_android.util.FlutterRouterManager
import io.flutter.embedding.android.FlutterFragment
import io.flutter.embedding.android.TransparencyMode
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.plugin.common.MethodChannel
class 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.activity
import android.content.Intent
import android.graphics.Color
import android.text.SpannableString
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.example.flutter_nav_android.databinding.ActivityMainBinding
import com.example.flutter_nav_android.util.FlutterRouterManager
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class 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
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',
);
}
}
// 原来带坑的写法
// 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方式 进行 页面跳转、传参,下面直接使用引擎进行 页面跳转、传参,但实用价值不高,因为弊端太大;
比如:
综上所述,大家将这种方式当作扩展知识就好了。
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 默认参数全部失效
@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,
),
)),
);
}
}
我用真机做测试,发现在Debug模式下,第一次从 Android 跳转 Flutter 会出现黑屏现象,但 打完包 或在 Release模式 就看不出来了;
我们默认的运行模式就是 Debug模式,可以通过 修改IDE运行命令 --release,切换为 Release模式;
GitHub - LanSeLianMa/flutter_nav_android: Flutter 和 Android原生(Activity、Fragment)相互跳转、传参