本文主要尝试解决如下几个问题:
如何在在已经项目加入Flutter
混合跳转
混合栈问题
混合栈数据问题
跳转黑屏是因为debug的缘故,打release包则没有。
af.gif
1. 如何在在已经项目加入Flutter
直接参考这篇文章Add Flutter to existing apps
2. 混合跳转
首先:Android跳转到Flutter
创建一个FlutterActivity
直接继承FlutterActivity或者自定义一个CustomFlutterActivity,我用的自定义,是做了一些封装和flutter插件注册
public abstract class CustomFlutterActivity extends AppCompatActivity implements FlutterView.Provider, PluginRegistry, FlutterActivityDelegate.ViewFactory { private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this); private final FlutterActivityEvents eventDelegate; private final FlutterView.Provider viewProvider; private final PluginRegistry pluginRegistry; public CustomFlutterActivity() { this.eventDelegate = this.delegate; this.viewProvider = this.delegate; this.pluginRegistry = this.delegate; } @Override protected void onCreate(Bundle savedInstanceState) { if (injectRouter()) ARouter.getInstance().inject(this); super.onCreate(savedInstanceState); this.eventDelegate.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); registerCustomPlugin(this); } protected boolean injectRouter() { return false; } //省略部分代码 ......... ......... private static void registerCustomPlugin(PluginRegistry registrar) { FlutterPluginJumpToAct.registerWith(registrar.registrarFor(FlutterPluginJumpToAct.CHANNEL)); } }
做一个Flutter用的容器,通过容器统一管理需要跳转的Flutter界面
@Route(path = RouterPath.MainPath.MAIN_FLUTTER_CONTAINER, name = "FlutterContainerActivity")public class FlutterContainerActivity extends CustomFlutterActivity { private static String CHANNEL = "com.jzhu.msg/plugin"; private static int TIME_ONE_SECOND = 1000; @Autowired(name = "path") String path; @Override protected boolean injectRouter() { return true; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initBasicMessageChannel(); } @Override public FlutterView createFlutterView(Context context) { WindowManager.LayoutParams matchParent = new WindowManager.LayoutParams(-1, -1); FlutterNativeView nativeView = this.createFlutterNativeView(); FlutterView flutterView = new FlutterView(FlutterContainerActivity.this, (AttributeSet) null, nativeView); flutterView.setInitialRoute(path); flutterView.setLayoutParams(matchParent); this.setContentView(flutterView); return flutterView; } private void initBasicMessageChannel() { switch (path) { case RouterPath.ModuleFlutterPath.FLUTTER_HOME: initHomeBasicMessage(); break; case RouterPath.ModuleFlutterPath.FLUTTER_TEST: initTestBasicMessage(); break; } } private void initTestBasicMessage() { BasicMessageChannel channel = new BasicMessageChannel<String>( getFlutterView(), CHANNEL, StringCodec.INSTANCE); channel.setMessageHandler((o, reply) -> { ToastUtils.show((String)o,3000); reply.reply("FlutterContainerActivity:回条消息给你"); }); new Handler().postDelayed(() -> channel.send("FlutterContainerActivity:发条消息给你"), TIME_ONE_SECOND); } private void initHomeBasicMessage() { //todo } }
Flutter提供的页面
void main() { runApp(new MaterialApp( routes: <String, WidgetBuilder>{ '/homepage': (BuildContext context) => new MyHomePage(), '/testpage': (BuildContext context) => new TestPage(), }, home: new MyHomePage())); }
路由
public interface RouterPath { interface MainPath{ String MAIN_FLUTTER_CONTAINER = "/main/FlutterContainerActivity"; String MAIN_TEST= "/main/TestActivity"; } interface ModuleFlutterPath{ String FLUTTER_HOME= "/homepage"; String FLUTTER_TEST= "/testpage"; } }
点击跳转
ARouter.getInstance() .build(RouterPath.MainPath.MAIN_FLUTTER_CONTAINER) .withString("path", RouterPath.ModuleFlutterPath.FLUTTER_HOME) .navigation();
最后:Flutter跳转到Android
通过插件实现,用法参考我之前写一篇Flutter知识点: Flutter与原生(Android)的交互
3. 混合栈问题
如果是Android的页面跳转到Android页面,所以就是普通的Activity栈。
如果是Android的页面跳转到Flutter页面,那么都使用了我们的容器FlutterContainerActivity,所以就是普通的Activity栈,这里面遇到个坑,下面会提出并尝试解决。
如果是Flutter的页面跳转到Flutter页面,那么由Flutter自己内部的栈管理。
如果是Flutter的页面跳转到Android页面,那么自己管自己就好啦。
如果你把Flutter的页面全装到到容器FlutterContainerActivity展示,那就都是普通的Activity栈,省事!
混合跳转注意:
Android某些页面的启动模式Standard,SingleTop,SingleTask,SingleInstance
Flutter页面也存在一些特殊的跳转,popAndPushNamed,pushNamedAndRemoveUntil,popUntil,pushReplacementNamed
以上需要根据实际情况处理,存在特殊跳转,销毁等逻辑
开发中需要特别需要注意的一个问题:
跳转顺序:Android页面 -> Flutter页面(使用了FlutterContainerActivity)-> Flutter页面(原始)
期望结果:Flutter页面(原始)-> Flutter页面(使用了FlutterContainerActivity)-> Android页面
真实结果:Flutter页面(原始)-> Flutter页面(使用了FlutterContainerActivity)-> Flutter页面(homepage) -> Android页面
得到疑问:我们并没有启动homepage,为什么多了一个homepage?
代码猜想:Flutter栈里初始化了一个homepage, 其他Flutter的页面都在这个栈之上。
void main() { runApp(new MaterialApp( routes: <String, WidgetBuilder>{ ............ }, home: new MyHomePage())); }
如何解决:使用SystemNavigator.pop(),
Tells the operating system to close the application, or the closest equivalent.
WillPopScope参考这篇Flutter学习中的问题记录: 如何监听实体/虚拟返回键和AppBar返回键
class _MyHomePageState extends State<MyHomePage> { static const jumpPlugin = const MethodChannel('com.jzhu.jump/plugin'); Future<Null> _jumpToNative() async { Map<String, String> map = {"path": "/main/TestActivity"}; String result = await jumpPlugin.invokeMethod('jump2act', map); print(result); } Future<bool> _requestPop() { SystemNavigator.pop(); return new Future.value(false); } @override Widget build(BuildContext context) { return new WillPopScope( child: new Scaffold( appBar: new AppBar( title: new Text("Home Page"), ), body: new Center( child: new RaisedButton( child: new Text("跳到TestActivity"), onPressed: _jumpToNative), ), // This trailing comma makes auto-formatting nicer for build methods. ), onWillPop: _requestPop); } }
4. 混合栈数据问题,以插件的方式解决 。
MethodChannel,EventChanneld的数据传输,用法参考我之前写一篇Flutter知识点: Flutter与原生(Android)的交互
主要举例BasicMessageChannel和BinaryMessages
1_Sd6s3EDGkU8TBS9xLc4Zvw.png
FlutterContainerActivity中初始化,监听,发送
为什么要延迟发送?
因为FlutterView可能还没初始化,这时候无法接收消息
private static String CHANNEL = "com.jzhu.msg/plugin"; private static String CHANNEL_BINARY = "com.jzhu.msg.binary/plugin"; private static int TIME_ONE_SECOND = 1000; private void initTestBasicMessage() { BasicMessageChannel channel = new BasicMessageChannel<String>( getFlutterView(), CHANNEL, StringCodec.INSTANCE); channel.setMessageHandler((o, reply) -> { ToastUtils.show((String)o,3000); reply.reply("FlutterContainerActivity:回条消息给你"); }); new Handler().postDelayed(() -> channel.send("FlutterContainerActivity:发条消息给你"), TIME_ONE_SECOND); ByteBuffer message = ByteBuffer.allocateDirect(256); message.putDouble(3.14); message.putInt(123456789); new Handler().postDelayed(() -> getFlutterView().send(CHANNEL_BINARY,message), TIME_ONE_SECOND); getFlutterView().setMessageHandler(CHANNEL_BINARY, (byteBuffer, binaryReply) -> { byteBuffer.order(ByteOrder.nativeOrder()); double x = byteBuffer.getDouble(); int n = byteBuffer.getInt(); Log.i("zj", "Received: "+x+ " and "+ n); binaryReply.reply(message); }); }
Flutter中监听,发送
static const channel = const BasicMessageChannel<String>('com.jzhu.msg/plugin', StringCodec());static const String channelBinary = 'com.jzhu.msg.binary/plugin';void _sendMsg2Android() async { _replyMsg = await channel.send('TestPage:发条消息给你'); setState(() {}); final WriteBuffer buffer = WriteBuffer() ..putFloat64(3.14) ..putInt32(123456789); final ByteData message = buffer.done(); _replyBinaryMsg = await BinaryMessages.send(channelBinary, message); _decodeData(message); } void _initMessageHandler() { channel.setMessageHandler((String message) async { _receivedMsg = message; setState(() {}); }); BinaryMessages.setMessageHandler(channelBinary, (ByteData message) async { _decodeData(message); }); } void _decodeData(ByteData message){ final ReadBuffer readBuffer = ReadBuffer(message); final double x = readBuffer.getFloat64(); final int n = readBuffer.getInt32(); print('Received $x and $n'); }
作者:老实巴交的读书人
链接:https://www.jianshu.com/p/5aa4f2a7ed0e
热门评论
使用Fragment方式打开flutter页面,空白的,不知道什么原因。 在另外一台机器上却没有问题
大佬,最近我也在尝试原生项目接入flutter,但是对于混合栈这一块已经纠结了好一阵子了,有没有这篇文章的源码的可以借我拜读一下啊。谢谢!