Flutter introduces a mixed use development of two -FlutterBoost

Foreword

"Flutter a mixed-use development theme," we introduced the hybrid development solutions Flutter official offer, but there are some problems does not solve, such as a page overlay native and Flutter Jump Flutter Engine problems due to repeated surge create and lead to memory , Flutter use global variables in each individual page can not be shared problems, iOS platform problem of memory leaks and so on, the official did not spend too much time on developing hybrid solutions to improve optimization.

Many domestic manufacturers have begun to study in the last year Flutter, and completed the integration in existing projects, where Ali leisure fish earlier research team and investment effort is relatively large, busy fish APP in 2018, has been integrated Flutter, and initially use in the product details page opens up, pre-free fish in order to solve the problem of mixed-use development has developed a plug-in hybrid development hybridstackmanager, open-source project addresses https://github.com/alibaba-flutter/hybridstackmanager , a feature of the program is invasive, we need to modify the source code Flutter framework, and there are certain limitations in complex page scenario, therefore, free fish next team developed a new generation hybrid technology development program FlutterBoost, and open source in early March this year.

FlutterBoost Introduction

Click to view the free fish team article for details FlutterBoost

https://mp.weixin.qq.com/s/v-wwruadJntX1n-YuMPC7g

FlutterBoost integration

Since FlutterBoost packaged in a plug-in, so the integration is very simple, requiring only a small amount of code for access to the works. Below a Demo project as an example to learn more about access.

Examples of projects

We have a native Android project FBDemo, needs-based project to introduce Flutter develop new page, we can create FBDemo same directory a Flutter module project, named flutter_boost_modulethe Flutter module project to introduce integrated into the native project, integrated by reference " Flutter a mixed-use development topics. " Then we can develop new page in the Flutter Flutter module project. Here integrated manner step by step instructions FlutterBoost

Flutter module integration projects FlutterBoost

In flutter_boost_moduleadd-dependent plug-in configuration file pubspec.yaml project

dependencies:
  flutter_boost: ^0.0.411

After the configuration execute flutter packages getcommand to download the plug-ins rely on locally.

Andrews native integration project FlutterBoost

After Flutter module project introduced FlutterBoost plug-in synchronization native Android studio project, the synchronization is complete project is structured as follows

14594750-e79e50933a730107
image

Then we can introduce FlutterBoost Android project code, add the following items depend on build.gradle under the app directory


dependencies {
     ...
     
    implementation project(':flutter_boost')
}

Flutter module project uses FlutterBoost

Suppose we use Flutter create two pages Widget: FirstPageand SecondPage.

First, we need to run rootWidget in the main method of registering these two pages.

@override
void initState() {
    super.initState();
    
    FlutterBoost.singleton.registerPageBuilders({
      'flutterbus://flutterFirstPage': (pageName, params, _) {
        print("first flutterPage params:$params");
        ...
        return FirstPage();
      },
      'flutterbus://flutterSecondPage': (pageName, params, _) {
        print("second flutterPage params:$params");
        ...
        return SecondPage();
      },
    });
    
    FlutterBoost.handleOnStartPage();
}

@override
Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Boost example',
        builder: FlutterBoost.init(),
        home: Container());
}

Andrews native projects use FlutterBoost

Flutter engine load and initialize FlutterBoostPlugin

First, according to our Application examples FlutterBoost original project needs to inherit FlutterApplication, in fact, this is not necessary, FlutterApplicationmainly in the onCreate method to initialize load flutter.so library, which we can operate, where appropriate, to add to his own.

Secondly, FlutterBoost of example in the onCreate method Application initialization FlutterBoostPlugin custom, this we can be extracted into a separate class.

Based on the above two points I implemented a tool to initialize the class used to perform FlutterBoost

public class FlutterMediator {
    public static void init(final Application app) {
        //此处必须启动初始化,主要是载入Flutter引擎文件
        FlutterMain.startInitialization(app);

        FlutterBoostPlugin.init(new IPlatform() {
            @Override
            public Application getApplication() {
                return app;
            }

            @Override
            public Activity getMainActivity() {
                return MainActivity.sRef.get();
            }

            @Override
            public boolean isDebug() {
                return true;
            }

            @Override
            public boolean startActivity(Context context, String url, int requestCode) {
                Debuger.log("startActivity url="+url);

                return PageRouter.openPageByUrl(context,url,requestCode);
            }

            @Override
            public Map getSettings() {
                return null;
            }
        });
    }
}

In this way, onCreate method in our custom Application of native projects only need to call the FlutterMediator.init(this);method to complete the initialization of the FlutterBoost. Which MainActivityshould always existed bottom of the stack of Activity, generally our home page.

Native container corresponding pages Flutter

After FlutterBoost initialization is complete, for Flutter in FirstPageand SecondPagewe need to create a page in the corresponding native Native container that FlutterBoost defined Container, can be Activity can also be a Fragment, here we use the Activity implementation,

// Flutter中FirstPage对应的Native container

public class FlutterFirstPageActivity extends BoostFlutterActivity {
    private int id = 0;
    private String name;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        if(intent != null) {
            String url = intent.getStringExtra("url");
            Map map = UrlUtil.parseParams(url);
            id = Integer.parseInt(map.get("id").toString());
            name = map.get("name").toString();
        }
    }

    @Override
    public String getContainerName() {
        return PageRouter.FLUTTER_FIRST_PAGE_URL;
    }

    @Override
    public Map getContainerParams() {
        Map map = new HashMap();
        map.put("id", id);
        map.put("name", name);
        return map;
    }

    @Override
    public void onRegisterPlugins(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }
}

FlutterBoost have achieved our good Activity type container BoostFlutterActivity, which implements the IFlutterViewContainerinterface, we custom container only needs to inherit the Activity and implement three methods to which

  • getContainerNameThat is the name of the container, and a registration layer Flutter corresponding PageBuilder;
  • getContainerParamsParameters passed to the need for the container layer corresponding to the Widget Flutter, page jump parameter passed to the received page is here Flutter process, needs to pack data into the Map;
  • onRegisterPluginsIs a plug-registered for the page;

Jump routing page

We saw above FlutterBoostPlugin line of code in the initialization PageRouter.openPageByUrl(context,url,requestCode);code of this code is used to process the page Flutter opening operation according to another page url. PageRouterRouting is a page of our native layer defined

public class PageRouter {
    public static final String NATIVE_FIRST_PAGE_URL = "flutterbus://nativeFirstPage";
    public static final String NATIVE_SECOND_PAGE_URL = "flutterbus://nativeSecondPage";
    public static final String FLUTTER_FIRST_PAGE_URL = "flutterbus://flutterFirstPage";
    public static final String FLUTTER_SECOND_PAGE_URL = "flutterbus://flutterSecondPage";

    public static boolean openPageByUrl(Context context, String url) {
        return openPageByUrl(context, url, 0);
    }

    public static boolean openPageByUrl(Context context, String url, int requestCode) {
        try {
            Intent intent;
            if (url.startsWith(NATIVE_FIRST_PAGE_URL)) {
                intent = new Intent(context, FirstNativeActivity.class);
                intent.putExtra("url", url);
                context.startActivity(intent);
                return true;
            } else if (url.startsWith(NATIVE_SECOND_PAGE_URL)) {
                intent = new Intent(context, SecondNativeActivity.class);
                intent.putExtra("url", url);
                if(context instanceof Activity) {
                    ((Activity)context).startActivityForResult(intent, requestCode);
                }
                return true;
            } else if(url.startsWith(FLUTTER_FIRST_PAGE_URL)) {
                intent = new Intent(context, FlutterFirstPageActivity.class);
                intent.putExtra("url", url);
                context.startActivity(intent);
                return true;
            } else if (url.startsWith(FLUTTER_SECOND_PAGE_URL)) {
                intent = new Intent(context, FlutterSecondPageActivity.class);
                intent.putExtra("url", url);
                if(context instanceof Activity) {
                    ((Activity)context).startActivityForResult(intent, requestCode);
                }
                return true;
            } else {
                return false;
            }
        } catch (Throwable t) {
            return false;
        }
    }

}

Flutter page and page jump Native

After more than a good preparation and page routing class definition, we can in the corresponding Flutter layer and layer calling Native method to execute the jump page url page jump operations, you can either jump Native Native page page, you can also Native Flutter page page jump, jump both Native Flutter page page, the page may jump Flutter Flutter page, the following specific examples

Native page jump Flutter page

Native Flutter page jump actually opens a page corresponding to a page Flutter Native container, we jump operation may be performed according to the route, such as the MainActivityjump to the Flutter FirstWidgetpage, the code to get a

PageRouter.openPageByUrl(this, PageRouter.FLUTTER_FIRST_PAGE_URL+"?id=123&name=bruce");

Examples of corresponding url parameters with the code above, when you do not need to pass a lot of parameters, where just an Flutter pass parameters to the page, that is, the values of id and name Flutter page spread use, specifically how we, we need to use the corresponding Flutter Native container FlutterFirstPageActivityparsing the url parameter, and then packaged into Flutter end Map passed to cover by the following methods PlatformChannel

@Override
public Map getContainerParams() {
    Map map = new HashMap();
    map.put("id", id);
    map.put("name", name);
    return map;
}

Flutter page jump Native page

We only need to use the method FlutterBoost Flutter end of the jump can be provided, for example, I need the FirstWidgetjump to the FirstNativeActivitypage that corresponds to url " flutterbus: // nativeFirstPage ", we can execute the following code

FlutterBoost.singleton.openPage("flutterbus://nativeFirstPage", {
                "query": {"description": "大家好,我来自First Flutter页面!!!!!!!!"}
              });

Wherein the query is a parameter value corresponding to the next page to be transmitted, you need not or may not pass.

Flutter Flutter page jump page

This fact, there are two ways, if FlutterBoost defined page jumps, then you need to use the following method

FlutterBoost.singleton.openPage("flutterbus://flutterSecondPage", {});

Jump recommended integrated FlutterBoost With FlutterBoost defined pages to use openPage way.

In fact, you can also use the Navigator to jump Flutter in, as follows

Navigator.of(context).push(MaterialPageRoute(builder: (context){
                return SecondPage(enterType: 1,);
              }));

If both jump method mix will be some problems when the page is returned, because FlutterBoost provides a method to close the current page FlutterBoost.singleton.closePageForContext(context);, and use the Navigator to jump if the method does not work, so we defined in the Widget page enterType to distinguish FlutterBoost default mode jump, jump if the Navigator Flutter Widget page, you need to pass enterType = 1, so that when returning the current page using a method for processing

void exitPage(BuildContext context) {
    if (enterType == 0) {
      FlutterBoost.singleton.closePageForContext(context);
    } else {
      Navigator.pop(context);
    }
}

Page jump return value

Flutter is implemented in FlutterBoost Native Page page jump function and receiving the return value, the method is particularly

FlutterBoost.singleton.openPage(
                  "flutterbus://nativeSecondPage",
                  {
                    "query": {"requestCode":1000, "type": "second"}
                  },
                  resultHandler: (String key, Map<dynamic, dynamic> result) {
                print("==============> key: $key, result: $result");
              });

resultHandler parameters openPage method is to receive the return value of the callback function, but the bug has been tested existing method, there are two main rehabilitation program

A rehabilitation program

The program uses a conventional jump Activity and returns the result of the method, i.e. Flutter Native specified page jump jump manner using the following method openPageByUrl of native PageRouter

if(context instanceof Activity) {
    ((Activity)context).startActivityForResult(new Intent(context, NativePageActivity.class), requestCode);
}

The jump method FlutterBoost whole process has been achieved returns the result of processing, but you need to modify the following two bug to normal use.

1, type conversion error

flutter_boost.dart Method onPageResultresultData parameter is Map<String, dynamic>type, and by PlatformChannel pass over the parsed data type Map<dynamic, dynamic>, it will be reported type conversion error, the console will print the phrase

... E/FlutterBoost#: onNativePageResult call error

To solve this problem simply onPageResultresultData parameter type method Map<String, dynamic>was changed Map<dynamic, dynamic>to;

2, the error correction method corresponding to the key

For 1 issue, modify the source code Flutter_Boost after the above error is not reported, but the result of receiving a callback method or come to the stage, and upon inspection found that there is another bug, through our openPageopen page methods, will eventually callback function PageResultMediatorclass setPageResultHandlerpreservation method into a Map<String,PageResultHandler>subject _handlers, the PageResultMediatorclass implements the following

typedef void PageResultHandler(String key , Map<dynamic,dynamic> result);
typedef VoidCallback = void Function();

class PageResultMediator{

  Map<String,PageResultHandler> _handlers = Map();
  void onPageResult(String key , Map<dynamic,dynamic> resultData){

    if(key == null) return;

    Logger.log("did receive page result $resultData for page key $key");

    if(_handlers.containsKey(key)){
      _handlers[key](key,resultData);
      _handlers.remove(key);
    }
  }

  VoidCallback setPageResultHandler(String key, PageResultHandler handler){
    if(key == null || handler == null) return (){};
    _handlers[key] = handler;
    return (){
      _handlers.remove(key);
    };
  }

}

Map of the key that is we jump page corresponding to url, i.e., in the code above flutterbus://nativeSecondPage, after returning the processed data into the key by the method PlatformChannel native container page is Native corresponding uniqueId, specific code as follows

14594750-1779cdb8e7932bc4
image

So, according to this last Flutter uniqueId callback method is not found before, and therefore did not come to the callback function. Then the source code of a simple Flutter_Boost been modified, the previous page url placed into a onResultprocess Resultparameter, and then out of the box, as the modified code

The code block is located ContainerRecord.java class

@Override
public void onResult(Map Result) {
    Map result = (Map) Result.get("result");
    String key = result.get("currentUrl").toString();
    NavigationService.onNativePageResult(
            genResult("onNativePageResult"),
            mUniqueId,
            key,
            Result,
            mContainer.getContainerParams()
    );
}

Repair Option II

The program uses the results of treatment FlutterBoost returns implemented without having to use native jump page acquisition result of the ordinary jump Jump Activity page, i.e.,

context.startActivity(new Intent(context, NativePageActivity.class));

The program also has a corresponding implementation FlutterBoost, but still there are two bug.

1, type conversion error

The same problem and a scheme of a problem, a modification to the reference program.

2, needResult parameters in the native client can not get the problem

When we found by studying FlutterBoost source, in the end Flutter jump page if passed in resultHandler parameters, it will be passed to add params native layer as a parameter to true needResult, open the requested page in the native layer processing will determining whether the first result data, the following code block

The class code is FlutterBoostPlugin.java

    public static void openPage(Context context, String url, final Map params, int requestCode) {
        ...

        //Handling page result.
        if (needResult(params)){
            sInstance.mMediator.setHandler(url, new PageResultHandler() {
                @Override
                public void onResult(String key, Map resultData) {
                    NavigationService.onNativePageResult(new MessageResult<Boolean>() {
                        ...
                    },"no use",key,resultData,params);
                }
            });
        }

        sInstance.mPlatform.startActivity(ctx, concatUrl(url, params), requestCode);
    }

    private Boolean needResult(Map params){

        if(params == null) return false;

        final String key = "needResult";
        if(params.containsKey(key)){
            if(params.get(key) instanceof Boolean){
                return (Boolean) params.get(key);
            }
        }
        return false;
    }

In the if statement of the method will detect whether it contains needResult params parameter and its value is true by needResult method, if true it will cache the results of a callback to mMediator object, but in fact this is not going to get to needResult parameters, because before the openPage incoming call has Flutter params made a deal, as follows

The method is in a class NavigationService_openPage.java

     private boolean onCall(MessageResult<Boolean> result,String pageName,Map params,Boolean animated){
         Map pageParams = null;
         int requestCode = 0;

         if(params != null && params.get("query") != null) {
             pageParams = (Map)params.get("query");
         }

         if(params != null && params.get("requestCode") != null) {
             requestCode = (int)params.get("requestCode");
         }

         FlutterBoostPlugin.openPage(null,pageName,pageParams,requestCode);

         result.success(true);
         return true;
      }

By the above code we will find pageParams just removed from the params passed in the query parameters, while ignoring the inside needResult parameters, so we can not find needResult parameters from params in openPage method.

After the discovery of the problem, we only need to add a parameter in openPage method boolean needResultto detect the presence or absence needResult parameters in onCall method, exists and is true, then it is passed openPage can be.

Fix the problem, then jump Native page if the results are returned to the Flutter page of it, just do the following to return to the page in the Native

Map map = new HashMap();
map.put("value", "bruce");
FlutterBoostPlugin.onPageResult(PageRouter.NATIVE_PAGE_URL, map);

After more than two solutions corresponding bug fixes, Flutter page jump Native page and get the return value of the function can be used normally, and look forward to free fish team can fix the problem in time.

For Native page jump Flutter page and return the result of functional data, currently Flutter_Boost has not been achieved, by reading the source code found in the relevant code, but not perfect, but also look forward to free the fish faster team improve this part of the function, after all page Jump return data that we often encounter scene.

Written in the last

These are integrated in the existing Flutter_Boost Andrews native project method steps, overall integration and use is still relatively simple, free fish team as much as possible to avoid the intrusion of the original code when integrating. Due to limited space, the text code stickers is not too perfect, if necessary, students can obtain a copy of the demo by micro letter public message number.

Watch "Flutter Programming Guide" micro-channel public number, the number public reply to the message interface "widget" "dart", "storage", "plug-ins" such as more accurate information, but also respond to "mixed-use development," acquisition of Ali, Tencent and other domestic manufacturers more Selected articles and more mixed development practices.

14594750-164721ef62a1eb74
image

Reproduced in: https: //www.jianshu.com/p/4eee4ddb2b6a

Guess you like

Origin blog.csdn.net/weixin_34375233/article/details/91206547