继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Flutter学习中遇到的问题:已有项目加入Flutter模块

慕哥9229398
关注TA
已关注
手记 1245
粉丝 199
获赞 913

本文主要尝试解决如下几个问题:

  1. 如何在在已经项目加入Flutter

  2. 混合跳转

  3. 混合栈问题

  4. 混合栈数据问题

跳转黑屏是因为debug的缘故,打release包则没有。

webp

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.  混合栈问题

  1. 如果是Android的页面跳转到Android页面,所以就是普通的Activity栈。

  2. 如果是Android的页面跳转到Flutter页面,那么都使用了我们的容器FlutterContainerActivity,所以就是普通的Activity栈,这里面遇到个坑,下面会提出并尝试解决。

  3. 如果是Flutter的页面跳转到Flutter页面,那么由Flutter自己内部的栈管理。

  4. 如果是Flutter的页面跳转到Android页面,那么自己管自己就好啦。

如果你把Flutter的页面全装到到容器FlutterContainerActivity展示,那就都是普通的Activity栈,省事!

混合跳转注意:
  1. Android某些页面的启动模式Standard,SingleTop,SingleTask,SingleInstance

  2. 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

webp

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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP

热门评论

使用Fragment方式打开flutter页面,空白的,不知道什么原因。 在另外一台机器上却没有问题

大佬,最近我也在尝试原生项目接入flutter,但是对于混合栈这一块已经纠结了好一阵子了,有没有这篇文章的源码的可以借我拜读一下啊。谢谢!

查看全部评论