Flutter 混合开发实战问题记录(二)自定义简单的混合栈路由

3,065 阅读3分钟

混合开发中不可避免的存在native向flutter页面跳转,flutter向原生跳转,甚至Activity或Fragment中某个view使用flutter开发。 咸鱼技术团队作为国内flutter技术领跑者开源了其混合栈的工具。 简书文章,或可以直接查阅GitHub仓库.

鉴于hyBirdStacManager中含有一些我们不很需要的功能和若干bug,目前我们可以借鉴下思路写个简单的工具类。

一、flutter -> native

flutter开启原生页面并传参较为简单,可以通过官方methodChannel直接调用native方法,不在赘述

dart代码

class MyFlutterPlugin {
    static const MethodChannel _channel =
      const MethodChannel('com.your.packagename/flutter_plugin');
    
     /**
   * 打开原生页面
   */
    static Future<String> openNativePage(String target , {Map paramsMap}) async {
     if(paramsMap == null){
        paramsMap = Map();
     }
     return await _channel.invokeMethod("openNative" , {"target" :target , "params" : paramsMap});
  }
}

参数的形式可以自定义为json,object等等

android端代码

注册插件的时机跟你的情况而定,现在先放在自动生成的插件后边

public abstract class BaseFlutterActivity extends FlutterFragmentActivity implements         LifecycleOwner{

      ......    

      @Override
    protected void onCreate(Bundle savedInstanceState) {
        AppManager.getAppManager().addActivity(this);
        ......
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
        //自定义plugin
        MyPlugin.registerWith(getFlutterView());
    }
}

public class MyPlugin {

    public static void registerWith(final BinaryMessenger messenger){
        new MethodChannel(messenger, "com.your.packagename/flutter_plugin").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
            
                ....
                
                // 解析参数,做页面跳转
                if ("openNative".equals(methodCall.method)){
                    NativeRouteUtil.schemePage(methodCall,result);
                }
            }
        });
    }
}

跳转代码可参考伪代码

 public static void schemePage(MethodCall methodCall, MethodChannel.Result result) {
       
        String target = methodCall.argument("target");
        switch (target) {
            case FlutterConstant.ROUTE_NATIVE_SETTING:
                SettingActivity.openSettingActivity(context);
                break;
            default:
                break;
        }
    }

二、native -> flutter

这是很容易想到的思路,为了保证界面跳转动画统一,页面栈方便维护(即使是flutter栈),在每次渲染一个新flutter页面的时候给他一个原生的载体,即一个Activity的壳,在Activity中的flutterView加载flutter页面

dart代码

flutter中有个main()方法入口,并且官方为我们提供了入口route的获取方式

void main(){
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_){
    runApp(new MyApp());
  });
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home:  _widgetForRoute(window.defaultRouteName),
    );
  }
}

Widget _widgetForRoute(String route) {
  String uri = StringUtil.getSchemeRouteName(route);
  String paramsJson = StringUtil.getSchemeRouteParams(route);
  switch (uri) {
    case ROUTE_ABOUT_US:
      return  AboutWidget(params: paramsJson);

    default:
      Toast.toast("您访问的页面不存在");
      SystemNavigator.pop();
  }
}

_widgetForRoute(String route)方法的参数可以自行配置标准,可以为/path + ?+ params的形式,标记进入哪个页面和传递相应参数。

android端代码

套壳是常见的封装形式,举个简单的例子,

public class FlutterContainerActivity extends BaseFlutterActivity {

    public static void openFlutterContainerAct(Context context, String url) {
        try {
            Intent intent = new Intent(context, FlutterContainerActivity.class);
            intent.putExtra(ROUTE_TARGET,url);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.setAction(ROUTE_ACTION);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三、native -> native

略.

不过可以封装一下,进入你的框架内,作为routeUtil的一部分

四、flutter -> flutter

虽然flutter内部有官方的跳转方法,但假如你的根flutter页面作为tab嵌入的方式渲染的话,如果用 Navigator.of(context)跳转,会发生新页面无法全屏的现象,所以还是为了动画统一和页面的良好管理机制,仍然推荐在dart内部先调用plugin方法,然后再用方式二进行跳转。

附dart内部的route跳转

class RouterUtil {

  static const ROUTE = 1;
  static const FADE = 2;

  static route(BuildContext context, Widget targetWidget) {
    Navigator.of(context)
        .push(MaterialPageRoute(builder: (mContext) => targetWidget));
  }

  static routeAnimation(BuildContext context, Widget targetWidget) {
    Navigator.of(context)
        .push(_MyCustomRoute(builder: (context) => targetWidget));
  }

  static route4Animation(BuildContext context, Widget targetWidget , num type) {
    Navigator.of(context)
        .push(_MyCustomRoute(builder: (context) => targetWidget , type : type));
  }
}

class _MyCustomRoute<T> extends MaterialPageRoute<T> {

  num mType = 2;

  _MyCustomRoute({WidgetBuilder builder, RouteSettings settings , var type})
      : super(builder: builder, settings: settings);

  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, Widget child) {
    if (settings.isInitialRoute) return child;
    if(mType == 1){
      return RotationTransition(turns: animation, child: child);
    }else if(mType == 2){
      return FadeTransition(opacity: animation, child: child);
    }
    return FadeTransition(opacity: animation, child: child);
  }
}

前两天闲鱼放弃了之前的混合栈项目,新开源了flutter_boost , 这是github,有兴趣可以参考。