Author: Ma Kunle
Flutter has matured over the years since its debut in 2015, and is widely used by Internet companies including Alibaba, Meituan and Pindoduo. 90% +% of new business on The ICBU Ali seller uses Flutter development, and the ICBU client development group has a large number of Flutter developers.
The early experimental version of Flutter for Web (FFW) was released in 2019. At the time, it had been investigated by many interested students, but was not suitable for use in a production environment due to problems with its initial release. In March of this year (2021), FFW entered stable with the release of Flutter 2.0.
The foreign trade information section of Alibaba Seller is mainly developed with Flutter. In the goal of this fiscal year, the promotion of foreign trade information outside the App is an important part of open source drainage. App foreign news promotion needs a content bearing Web page, the requirements of the Web page are as follows:
- Duplicate UI and functions of relevant pages on App side (mainly including a custom HTML parsing rendering engine written by DART)
- Rapid on-line
- App function synchronization
Due to the lack of support from the front-end students, the only way to complete this page is by the students themselves on the App end. After some consideration, we choose FFW for the following reasons:
- The cost of switching to front-end technology stack Rax is slightly higher, and the target page function reproduction needs more time
- Use the EXISTING DART code on the reusable side of the FFW target page for most of the code
- The application of Flutter technology stack covers a wide range of students
After the above thinking, officially open FFW pit filling tour.
Demo
At present, the ffW-related pages of Ali sellers have been online, and the problem of large js files of products has always existed since the release of FFW. Theoretically, this will affect the page loading experience. In the actual test, it is observed that the loading experience on PC and mobile devices is ok and runs smoothly.
- Outside shots demo:alisupplier.alibaba.com/content_pag content display page…
- Ali seller App download page: alisupplier.alibaba.com/content_pag…
Problems in the overview
The FFW project is easy to create. Switch to the stable version of Flutter, then run the command Flutter create xxxProject to enter the project and click run a Demo project to start the project. To apply FFW to practical projects, we need to consider the problems of engineering and how to integrate into Ali’s system, such as how to release, how to control the development process and how to request interfaces, etc., which are summarized as follows:
The above are the problems encountered in the minimum closed-loop practice of FFW open source drainage of Ali sellers. In addition, there are other problems to be built in FFW:
Engineering basis
The following is a description of the causes and solutions of engineering basic problems in the minimum closed-loop practice.
Environment and reuse
Referring to app-side Flutter development, FFW should first consider what version of Flutter to choose, and then consider how to reuse existing Flutter code.
Flutter Version selection
Version selection problems are caused by inconsistent Flutter versions of FFW and Flutter for App (FFA). The REQUIRED Flutter version of FFW is 2.0+, while the current Flutter version in our App is 1.x +. It will take an indefinite time to upgrade to the 2.0+ version. After some consideration, the current versions of FFW and FFA are as follows:
FFA: hummer/release/v1.22.6.3 -- hummer offshoot of UC FFW: Origin /flutter-2.8-candidateCopy the code
The stable version of FFW was not chosen because FFW pages froze due to webGL issues on the recently released iOS 15. The fix for this issue is now integrated into the candidate version. (Current latest stable version is 2.10.0, problem resolved)
Code reuse
There are two issues to consider when reusing FFA code into FFW:
- Dart code reuse
- Reuse of platform-related plug-in capabilities
Dart code reuse
FFW requires that the dart version of Flutter 2.0+ be 2.12, which introduces Sound null safety features. The Flutter version used on FFA is 1.+ and the corresponding DART version does not introduce air safety. At the same time, the dart library code of the new and old versions cannot be mixed compiled, so the existing App side code base cannot be seamlessly reused at present. The existing code can only be reused by modifying it. The main points of code modification are as follows:
- Can be null variable, type added after?
User? nullableUser;
Copy the code
- Is used when operating on variables that can be null? Or!!!
nullableUser? .toString(); // NPE nullableUser is null. .toString(); // Force the value to be non-null, otherwise an error will be reportedCopy the code
- The optional @required annotation is replaced with the required reserved word
// Old version User({@required this.name, @required this.age,}); // New version User({required this.name, required this.age,});Copy the code
The low-version code can be compiled in the new version basically after the three steps of modification. In addition, some API will be changed due to version upgrade, and corresponding modifications will be required, such as:
// typedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, Widget child); /// typepedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, Widget? child);Copy the code
This type of problem is the majority of API changes and is relatively easy to modify. TextSelectionControls also changed the number of handleCut parameters:
Void handleCut(TextSelectionDelegate delegate) {... } // new version void handleCut(TextSelectionDelegate delegate, ClipboardStatusNotifier? clipboardStatus) {... }Copy the code
This type of modification needs to be modified according to the actual situation, and the difficulty is medium. The newly added parameters are most likely not needed.
Platform-specific plug-ins
Platform-related plug-ins will invoke Native capabilities. To use the plug-ins in FFA on FFW, it is necessary to implement corresponding capabilities for the plug-ins on the Web platform, which will be explained in the JS invocation section below. If you are using the pub.dev library, and the library meets the following conditions, you can directly use the corresponding version:
- There is a Web version of the code base
- Support for Null Safety is available in the release (Web support will also support this)
Web version supported | Air safety support |
Release system
After the local Demo project is created and running successfully, there are several issues to consider:
- How is the development to release process managed
- How to publish the page online and make it accessible to public networks
- How to package builds
- How to release
For the control of the process from development to release, refer to DEF platform (Ali internal front-end development and release platform) and create WebApp for management, which is not detailed here. The content involved in page publishing is as follows:
Engineering construction
There are two ways to construct FFW. Not all the products constructed need to be simplified in the application. There is also some additional processing required to publish the product on the DEF platform. In the construction of the main consideration of how to build, FFW build optional commands are as follows:
Render a flutter build web --web-renderer canvaskit // Render a flutter build web --web-renderer HTMLCopy the code
The difference between the two commands is how the target page is rendered. The official explanation of Flutter is as follows:
The summary is as follows:
- Html: the page uses Html basic elements rendering, the advantage is that the page resource file is small;
- CanvasKit: The WebAssembly technology is used, providing better performance. However, webAssembly-related WASM files need to be loaded to load 2.+ MB resource files, which is more suitable for scenarios that have high requirements on page performance.
In the empty project, the comparison between the two methods of resource loading is as follows. Considering the page size and page performance, we choose to use HTML.
Html mode | CanvasKit way |
Product streamlining and processing
For newly created projects, the compiled artifacts are located in the./build/web directory and are structured as follows:
Build ├─ [384] Web ├─ [2] AssetManifest. Json │ ├─ [82] FontManifest. Json │ ├─ [702 ├── [96] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [1.07] ├─ [128] the ICONS │ ├ ─ ─ [5.2 K] Icon - 192. The PNG │ └ ─ ─ [8.1 K] Icon - 512. The PNG ├ ─ ─ [3.6 K] index. The HTML release retain 】 【 ├ ─ ─ 1.2 [M]. The main dart. Js ├── [57] Manifest.txt ├─ [57] Manifest.txt ├─ [55] Manifest.txtCopy the code
The functions and descriptions of directories and files are as follows:
- Assets: assets, such as images and fonts, correspond to assets configured in yamL files. If images in FFW are configured on TPS and IconFont is not used, this directory is not required.
- Favicon. PNG: icon of the page, not required when using TPS resources;
- Flutter_service_worker. js: local debug controls page loading, reload, close, etc.
- ICONS: icon resources that do not need to be published to TPS;
- Index.html: the page entry file, the main job is to import main.dart.js and some other resources, similar to App shell project, need;
- Main.dart.js: the product of compiling the DART in the project, required;
- Manifest.json: configuration of the page as a Webapp, not required;
- Version. json: build information, not required.
In a real release, the only build artifacts required are index.html and main.dart.js, and for each iteration, only main.dart.js is required when no “shell engineering” changes are involved.
Once you have selected the desired artifacts, you need to do some work with these two files before the DEF platform can be released:
- The reference to main.dart.js in HTML is replaced with the CDN address of the corresponding iteration (concatenated according to the iteration number and release environment);
- In the HTML tag changes, reference docs. Flutter. Dev/development…
- Remove comments from js and HTML files (def publish door god check);
- Replace?? With?? Operator (pin H5 container this operator error);
- Move index.html and main.dart.js to the artifacts folder on the DEF platform.
Page release
On the DEF platform, js and HTML files will be published to the corresponding CDN after the production file is processed, and HTML will be deployed to a specific address:
Pretest:
- Dev.g.alicdn.com/algernon/al…
- Dev.g.alicdn.com/algernon/al…
- Market.wapa.taobao.com/app/algerno… (Deployment address)
Online:
- G.alicdn.com/algernon/al…
- G.alicdn.com/algernon/al…
- Market.m.taobao.com/app/algerno… (Deployment address)
For the online environment index.html content is as follows:
<! DOCTYPE html> <html> <head> <! - published to the domain of the secondary directory using - > < base href = "/ content_page/" / > < / head > < body > <! <script type="text/javascript" -- replace with the corresponding CDN address of main.dart. SRC = "https://g.alicdn.com/algernon/alisupplier_content_web/1.0.10/main.dart.js" > < / script > < / body > < / HTML >Copy the code
At this point, we can access our target page using the page deployment address. If the page is opened once and there is no need for multiple page hops internally, at this point we are done publishing. If multiple page jumps are involved, you also need to publish relevant content to your own domain name. A simple way is to configure redirection, in addition to directly referencing products can also be:
- Target domain address redirection: their domain address deployment is redirected to the page, such as the alisupplier.alibaba.com/page_conten… Market.m.taobao.com/app/algerno… Tag mode (default UrlStrategy);
- Destination domain address redirection: Create index. HTML under the destination domain name and reference the main.dart.js file, or embed the published page in the destination page. Reference: docs. Flutter. Dev/deployment /…
Code debugging
After the basic link runs, the requirements can be developed. The more important environment in the development process is the debugging of the code. FFW can be debugged in Chrome in a similar way to App and has a better experience. After setting breakpoints in the IDE in the Debug environment, you can Debug them in the IDE and view them in Chrome, where you can even see the Dart code. This section uses VSCode as an example to describe the debugging process and experience.
Start Flutter debugging
Breakpoints visible in VSCode and Chrome
Ability to support
After entering the actual development, you need to support such capabilities as routing and interface requests, starting with page routing and address.
Page routing and address
When multiple pages appear in FFW applications or parameters need to be transmitted through Http links, the corresponding route configuration is required. Similar to FFA, the corresponding Route can be configured in the root MaterialApp, and then the page can be opened directly by navigator. push or page address. The following code can realize the named jump and page address jump:
MyApp extends StatelessWidget {@override Widget Build (BuildContext Context) {return MaterialApp( debugShowCheckedModeBanner: false, onGenerateRoute: RouteConfiguration.onGenerateRoute, onGenerateInitialRoutes: (settings) { return [RouteConfiguration.onGenerateRoute(RouteSettings(name: settings))]; }); }}Copy the code
RouteConfiguration {static Map<String, RouteWidgetBuilder? > builders = {PageA '/page_a': (context, params) {return PageA(title: params? ['title']); }, /// page_b': (context, params) {return PageB(param1: params? ['param1'], param2: params? ['param2']); }}; static Route<dynamic> onGenerateRoute(RouteSettings settings) { return NoAnimationMaterialPageRoute( settings: settings, builder: (context) { var uri = Uri.parse(settings.name ?? ''); var route = builders[uri.path]; if (route ! = null) { return route(context, uri.queryParameters); } else { return CommonPageNotFound(routeSettings: settings); }}); }}Copy the code
After the configuration is complete, you can jump to the page, or directly jump to the page by using the ADDRESS of the European Champions browser:
- In-app jump: After the configuration is complete, you can jump to the target page from the Navigator inside the application
Of (context). RestorablePushNamed ('/page_b? Param1 = 123 ¶ m2 = ABC ');Copy the code
- Redirect: Enter the address in the address box of the browser to go to the page
/// page B access address https://xxx.xx/#/page_b? Param1 = 123 ¶ m2 = ABCCopy the code
Note: The address redirect method above requires that the UrlStrategy of FFW be hash tag (the default UrlStrategy).
Native JS calls for Web platforms
Using repositories such as pub.dev makes it easy to use various capabilities in FFW. Consider extending capabilities that are not in the repository. FFA allows you to use native capabilities through plug-ins, as well as FFW allows you to use JS capabilities through extensions. Through the ability to call JS the front end of the massive accumulation of technology can be applied to FFW.
Dart in FFW will eventually compile to JS, and JS should be available naturally in FFW. To support JAVASCRIPT calls in DART, dart has released a js library that makes it easy to call JS from Dart using annotations in the library.
For example, if you need to call the alert method, define it as follows:
// add js_interface to your dependencies. Add js_interface to your dependencies. import 'package:js/js.dart'; @js ('alert') external void jsAlert(String MSG);Copy the code
Dart and call the jsAlert method where alert is needed:
import 'package:mtest/js_interface.dart'; . JsAlert (' test message '); .Copy the code
Pub.dev /packages/js… After the ability of JS, the following many problems are solved.
Mtop interface
In view of the construction of the existing Mtop (a gateway used by Ali App) on the App end, it will reduce a lot of work if the existing Mtop can be called in FFW. To do this, you need to add the Mtop call capability to FFW, and there are two parts to doing this:
- The FFW side supports Mtop calls
- The server supports H5 Mtop invocation
FFW support Mtop
The power of MTOP is introduced into FFW by the ability to call mtop.js. The overall process is as follows:
1. Add top.js to index.html
< script SRC = "/ / g.alicdn.com/mtb/lib-mtop/2.6.1/mtop.js" > < / script >Copy the code
2. Define the interface file js_mtop_interface.dart
@JS() library lib.mtop; import 'package:js/js.dart'; import 'package:js/js_util.dart'; import 'dart:convert'; import 'dart:js'; @anonymous @js () class MtopParams {external String get API; external String get v; external dynamic get data; external String get ecode; external String get dataType; external String get type; external factory MtopParams({ required String api, required String v, required dynamic data, required String ecode, required String dataType, required String type, }); } @js (' lib.top.request ') external dynamic _jsMtopRequest(MtopParams params); MapToJSObj (map <String, dynamic> a) {var object = newObject(); a.forEach((k, v) { var key = k; var value = v; setProperty(object, key, value); }); return object; } // Future mtopRequest(String API, Map<String, dynamic> params, String version, String method) { var jsPromise = _jsMtopRequest( MtopParams( api: api, v: version, data: mapToJSObj(params), ecode: '0', type: method, dataType: 'json', ), ); return promiseToFuture(jsPromise); } // return result parsing using @js (' json.stringify ') external String stringify(Object obj);Copy the code
3. Call mTOP interface
import 'package:mtest/mtop/js_mtop_interface.dart'; . try { var res = await mtopRequest(apiName, params, version, method); print('res $res'); } catch (err) { data = stringify(err); }Copy the code
4. Parse result: The result returned by the interface request is a jsObject that can be converted to JSON using the JS method json.stringify and used at the Dart level
String jsonStr = stringify(res);
Copy the code
Server H5 Mtop configuration
After mtop.js is connected to FFW, it can be called only after processing the target MTOP interface:
- Mtop releases the H5 version
- Apply for configuring the CORS domain name whitelist
dot
With the request of MTOP, FFW can introduce the JS library of golden Command arrow for the dot, and the process is as follows:
Index.html introduces js files
<script type="text/javascript" src="https://g.alicdn.com/alilog/mlog/aplus_v2.js"></script>
Copy the code
2. Define the interface file js_goldlog_interface.dart
@JS() library lib.goldlog; import 'package:js/js.dart'; @js ('goldlog.record') external dynamic _jsGoldlogRecord(String t, String e, String n, String O, String A); void goldlogRecord(String logkey, String eventType, String queryParams) { _jsGoldlogRecord(logkey, eventType, queryParams, 'GET', ''); }Copy the code
3. Make calls
import 'package:mtest/track/js_goldlog_interface.dart'; . goldlogRecord(logkey, eventType, queryParams); .Copy the code
Then the corresponding point configuration can be carried out on the log platform.
monitoring
Monitoring capability access is relatively simple. Here, select ARMS (Apply real-time monitoring service) and directly introduce ARMS into index.html. The process is as follows:
1. Introduce related libraries in index.html
<script type="text/javascript"> var trace = window.TraceSdk({ pid: 'as-content-web', plugins: [ [window.TraceApiPlugin, { sampling: 1 }], [window.TracePerfPlugin], [window.TraceResourceErrorPlugin] ], }); // Start trace and listen for global JS exceptions, temporarily comment trace.install() when the problem is debug; trace.logPv(); </script>Copy the code
2. Perform related configurations on the ARMS platform
Note: Trace.install () will cause the page not to be displayed in the Debug environment. You can disable it in the Debug environment.
Optimization and compatibility
After completing the above basic capacity construction, FFW can basically meet the development of simple needs. In addition to requirements development, experience, compatibility and other issues need to be considered.
Load optimization
One issue FFW has had since its release is package size. For an empty HelloWorld project, the size of a single JS package is 1.2MB (before compression), which can take several seconds to load on a mobile device when the network is bad. To improve the page loading experience, consider the following things you can do:
Wait process optimization
FFW pages are always blank until js loading is complete, giving a feeling that the page is stuck. Therefore, loading animation can be added before JS loading is complete to prevent the page from being blank all the time. The skeleton screen can be inserted between data loading by referring to the practice that works on the App, as follows:
< iframe SRC = "https://g.alicdn.com/algernon/alisupplier_content_web/0.9.1/skeleton/index.html" id = "iframe" frameborder="0" scrolling="no"></iframe> <script> function setIframeSize() { <! } function removeIFrame() {var iframe = document.getelementById (" iframe "); iframe.parentNode.removeChild(iframe); } setIframeSize(); </script> <! <script type="text/javascript" SRC = "https://g.alicdn.com/algernon/alisupplier_content_web/1.0.10/main.dart.js" onload = "removeIFrame ()" > < / script >Copy the code
TODO JS unpacking & Optimization
Awaiting process optimization can ascend to a certain extent experience, single take temporary solution not effect a permanent cure, if you want to load faster still have to make the resources of the load is small, for multi-page applications, can be the main, the dart, js split into multiple small package, in the process of using stepwise loading, now learn Meituan have corresponding technology, but unknown, implementation details need to be researched. Refer to github.com/flutter/flu…
compatibility
Similar to App, there will be experience problems on different devices, and FFW will have compatibility problems in different H5 containers. In our practice, the stomping records of different H5 containers are as follows:
Problem of white screen in H5 container:
- Don’t support?? Syntax, solve after replacement
- FFW product JS contains a large number of try{}finally{} no-catch operations, which will report an error in the pin H5 container, which will be solved by unified substitution of scripts when packaging
Wechat H5 container white screen problem:
- Remove the MaterialIcons and replace them with images
Page freezes on iOS 15:
- IOS 15 webGL2.0 problems, currently has a solution to be released github.com/flutter/flu…
IOS compatibility issues:
- Clickable RichText, after setting the underline attribute, the link following the image will be blocked, the solution has not been found, can only not use the underscore of RichText
- Clickable RichText will scroll automatically when clicked. Verify that it is caused by the InteractiveSelectionu property. If set to false, it behaves the same as Android
Other problems
In addition to the compatibility problems of H5 containers, some problems of FFW itself are encountered in practice, which are recorded as follows:
Provider library problems:
- The provider in the library/lib/SRC/provider. The dart ProviderNotFoundException class toString () method contains a huge long error description String, the String compiled js grammar will go wrong, after deleting
JsonConverter problem:
- JsonConverter().convert will report errors when running. Use caution. Dart array to JS array can be manually converted
The content of the TODO
In current practice, only one small closed-loop construction for business availability has been completed. There are still many TODO contents in FFW, as follows:
Engineering construction:
- DEF cloud build: When trying to install the Flutter environment on DEF cloud build platform, there will be 403 requests for contents outside Ali. However, there are many contents in the Flutter that need to be pulled online, such as the contents in the packages under the Flutter root directory. Currently, local build is used and needs to be solved.
- Local debug when mTOP access: For MTOP requests, the CORS whitelist must be configured and the port number must be 80. For local debugging, the IP address is used and the port number is a random number. The operation cannot be performed by forcibly setting times.
Basic functions:
- Video and audio playback ability to be studied
Compatibility and optimization
- Js package split loading needs to be studied
- Customization font file optimization needs to be studied
Think about:
- Dynamic of Flutter in App: Replace the Flutter page in App with FFW to make a dynamic solution similar to WEEX
- Webappization of Apps: Flutter apps can be converted into WebApps at low cost via FFW, solving problems such as the lack of a Mac version of the App
Pay attention to [Alibaba mobile technology] wechat public number, every week 3 mobile technology practice & dry goods to give you thinking!