Flutter 混合開發實戰問題記錄(二)自定義簡單的混合棧路由

小豬睡枕頭single發表於2019-03-02

混合開發中不可避免的存在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,有興趣可以參考。

相關文章