前面我们学习了Dart端页面的跳转是通过Navigator控制的,而在android原生开发中,采用的是Intent。那混合开发中,两者间的页面跳转又是如何实现的呢?
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:theme="@style/Theme.AppCompat"
android:windowSoftInputMode="adjustResize" />
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MyBasicMessageChannel extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: BasicMessageChannelHome(),
);
}
}
class BasicMessageChannelHome extends StatefulWidget {
State<BasicMessageChannelHome> createState() =>
BasicMessageChannelHomeState();
}
class BasicMessageChannelHomeState extends State<BasicMessageChannelHome> {
var _basicMessage = BasicMessageChannel("BasicChannel", StringCodec());
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: GestureDetector(
child: Text('发送BasicMessageChannel'),
onTap: () {
_basicMessage.send('JumpNativeActivity').then((value) {
print(value);
});
},
),
),
),
);
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FlutterMethodChannel extends StatelessWidget {
MethodChannel methodChannel = MethodChannel('nativeCall');
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: GestureDetector(
onTap: () {
_callNativeMethod();
},
child: Center(
child: Text('调用Native方法'),
),
),
),
);
}
void _callNativeMethod() async {
try {
methodChannel.invokeMethod('JumpNativeActivity');
} catch (e) {
print(e);
}
}
}
package com.example.flutter_hello
import android.content.Context
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.StringCodec
const val TAG:String="MainActivity"
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
var channel = BasicMessageChannel(
flutterEngine.dartExecutor.binaryMessenger,
"BasicChannel",
StringCodec.INSTANCE
)
channel.setMessageHandler { message, reply ->
startActivity(
Intent(
this,
SecondActivity::class.java
)
)
reply.reply("成功跳转")
}
}
}
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.StringCodec
const val TAG:String="MainActivity"
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e(TAG,"onCreate")
MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
"nativeCall"
).setMethodCallHandler { call, result ->
run {
if (call.method.equals("JumpNativeActivity")) {
result.success("success")
startActivity(
Intent(
this,
SecondActivity::class.java
)
)
}
}
}
}
该方式是基于Navigator和routes的,所以,对于Dart端一定要配置好routes。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class DartPages extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{
'home': (BuildContext context) => DartHomePage(),
'second': (BuildContext context) => DartSecondPage(),
},
initialRoute: 'home',
);
}
}
class DartHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart主页'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
MethodChannel methodChannel=const MethodChannel("nativeCall");
methodChannel.invokeMethod("toSecondActivity");
},
child: const Text('跳转'),
),
);
}
}
class DartSecondPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart第二页'),
),
);
}
}
MainActivity
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.StringCodec
const val TAG:String="MainActivity"
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e(TAG,"onCreate")
MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
"nativeCall"
).setMethodCallHandler { call, result ->
run {
if (call.method.equals("nativeMethod")) {
result.success("success")
Log.e(TAG, "Get Dart call method")
}else if(call.method.equals("toSecondActivity")){
startActivity(
Intent(
this,
SecondActivity::class.java
)
)
}
}
}
}
}
该方法使用的是withNewEngine,页面跳转会出现卡顿感
SecondActivity
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.flutter_hello.databinding.ActivitySecondBinding
import io.flutter.embedding.android.FlutterActivity
class SecondActivity : AppCompatActivity() {
lateinit var mContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this
val binding: ActivitySecondBinding =
DataBindingUtil.setContentView(this, R.layout.activity_second)
binding.jumpToDartSecond.setOnClickListener {
//方式1:跳转到已经在flutter的routers声明的命名路由页面(会卡顿)
startActivity(FlutterActivity.withNewEngine().initialRoute("second").build(mContext))
}
}
}
2、在Application里面先设置好FlutterEngine,使用的时候直接取缓存过得FlutterEngine
自定义MyApplication
package com.example.flutter_hello
import android.app.Application
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.dart.DartExecutor
class MyApplication : Application() {
lateinit var flutterEngineInit: FlutterEngine
override fun onCreate() {
super.onCreate()
flutterEngineInit = FlutterEngine(this)
// 开始执行Dart代码以预热FlutterEngine
flutterEngineInit.navigationChannel.setInitialRoute("second")
flutterEngineInit.getDartExecutor()
.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())
// 缓存FlutterActivity要使用的FlutterEngine
FlutterEngineCache.getInstance().put("second", flutterEngineInit)
}
override fun onTerminate() {
flutterEngineInit.destroy()
super.onTerminate()
}
}
在Manifest文件里面注册该自定义的Application
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.flutter_hello.databinding.ActivitySecondBinding
import io.flutter.embedding.android.FlutterActivity
class SecondActivity : AppCompatActivity() {
lateinit var mContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this
val binding: ActivitySecondBinding =
DataBindingUtil.setContentView(this, R.layout.activity_second)
binding.jumpToDartSecond.setOnClickListener {
//方式2:跳转到initialRoute指定的页面(不卡顿)
startActivity(
FlutterActivity
.withCachedEngine("second")
.build(mContext)
)
}
}
}
PS:如果要使用window属性,必须导入 'dart:ui’的包
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class DartPages extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{
'home': (BuildContext context) => DartHomePage(),
'second': (BuildContext context) => DartSecondPage(),
},
home: _widgetForRoute(window.defaultRouteName),
);
}
}
class DartHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart主页'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
MethodChannel methodChannel=const MethodChannel("nativeCall");
methodChannel.invokeMethod("toSecondActivity");
},
child: const Text('跳转'),
),
);
}
}
class DartSecondPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart第二页'),
),
);
}
}
Widget? _widgetForRoute(String route){
switch(route){
case "home":
return DartHomePage();
case "second":
return DartSecondPage();
default:
return DartHomePage();
}
}
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
var INIT_PARAMS = "initParams"
const val TAG:String="MainActivity"
class MainActivity : FlutterActivity() {
private var initParams: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e(TAG,"onCreate")
initParams = getIntent().getStringExtra(INIT_PARAMS)
}
override fun getInitialRoute(): String? {
return if (initParams == null) super.getInitialRoute() else initParams
}
companion object {
fun start(context: Context, initParams: String) {
val intent = Intent(context, MainActivity::class.java)
intent.putExtra(INIT_PARAMS, initParams)
context.startActivity(intent)
}
}
}
1、在继承FlutterActivity的类重写getInitialRoute方法
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.flutter_hello.databinding.ActivitySecondBinding
import io.flutter.embedding.android.FlutterActivity
class SecondActivity : AppCompatActivity() {
lateinit var mContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this
val binding: ActivitySecondBinding =
DataBindingUtil.setContentView(this, R.layout.activity_second)
binding.jumpToDartSecond.setOnClickListener {
MainActivity.start(mContext,"second")
}
}
}
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class DartPages extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{
'home': (BuildContext context) => DartHomePage(),
'second': (BuildContext context) => DartSecondPage(),
},
home: _widgetForRoute(window.defaultRouteName),
);
}
}
class DartHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart主页'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
MethodChannel methodChannel=const MethodChannel("nativeCall");
methodChannel.invokeMethod("toSecondActivity");
},
child: const Text('跳转'),
),
);
}
}
class DartSecondPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
centerTitle: true,
),
body: const Center(
child: Text('欢迎来到Dart第二页'),
),
);
}
}
Widget? _widgetForRoute(String route){
switch(route){
case "home":
return DartHomePage();
case "second":
return DartSecondPage();
default:
return DartHomePage();
}
}
package com.example.flutter_hello
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.flutter_hello.databinding.ActivitySecondBinding
import io.flutter.embedding.android.FlutterActivity
class SecondActivity : AppCompatActivity() {
lateinit var mContext: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mContext = this
val binding: ActivitySecondBinding =
DataBindingUtil.setContentView(this, R.layout.activity_second)
binding.jumpToDartSecond.setOnClickListener {
startActivity(Intent(mContext,ThreeActivity::class.java))
}
}
}
package com.example.flutter_hello
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.FragmentTransaction
import io.flutter.embedding.android.FlutterFragment
//原生页面采用FlutterFragment引入Flutter的widgets
class ThreeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_three)
var ft:FragmentTransaction=supportFragmentManager.beginTransaction()
val dartView:FlutterFragment=FlutterFragment.withNewEngine().initialRoute("second").build()
ft.replace(R.id.dartPageContain,dartView).commit()
}
}
总结:虽然混合开发中页面跳转能够实现,但是总体的页面切换的效果还是很差,估计用户体验不是很高,混合开发中跨平台页面渲染还有很大提升空间。