The practice of Flutter Web from 0 to deployment and online

1 Introduction

First of all, let me explain that this article is for client development students ( Flutterit is best to have a foundation). FlutterAlthough it was born from Googlethe Chrometeam, everyone knows that Flutterthe first supported platform is Androidand iOS, and the core maintenance platform is still Androidand iOS. dartThe learning cost of the language is not high, Flutterand the responsive UI has great similarities with Composeand SwiftUI, and the overall architecture idea is more biased towards the client-side model. In addition, in order to realize many hardware or Nativerelated basic functions, professional client-side development knowledge is required, so Flutterit is more recognized and used by client-side development students (in our team, Flutterit is already a necessary basic skill for client-side development students). Although Flutterthe biggest highlight is cross-end, in fact, cross-end between client and webend is not common due to the large difference. Therefore, under this background, we Flutterdid not initially webmake efforts on the end. But Flutterit is the gene that it carries web, so the stable version Flutter2was finally released when it was released . So since the cross-end between the client and the end is not common, front-end developers probably won’t use it for development (it’s really unnecessary, the package size increases and there is a certain performance loss, and you need to learn new languages ​​and development ideas, native development is not good), what’s the use ? With this in mind, I haven't investigated end-to-end support for a long time after use. However, with the development and changes of business and internal needs,web
webFlutterwebFlutter Web
FlutterwebFlutter WebThe advantages are also gradually revealed. Let me talk about the use Flutter Webof the main three scenarios.

2. Flutter Web usage scenarios

  • 1. The internal web requirements of the client team : In the context of reducing costs and increasing efficiency in the post-epidemic era, we will use more self-developed tools. The use of self-developed tools and the visualization of results are usually displayed in the form of web pages. Although there are front-end development students in the team, considering that self-developed tools are more attempts within the group and have nothing to do with business, naturally front-end students should not be allowed to undertake this part of the work. The learning cost of web development is low for client- side students , and they Flutter Webcan develop web pages quickly .VuewebcssFlutterFlutterFlutter
  • 2. Web business requirements that do not require long-term maintenance : webthe terminal carries many activity requirements, which are characterized by strong timeliness, simple functions, and no long-term maintenance. However, these needs are often generated in large quantities during a certain period of time (such as some activities or lists during the holidays), or suddenly (such as instant demand for speculation). The insertion of these tasks sometimes leads to webthe delay of some long-term iterative end requirements, which affects the overall schedule of the team. Since the development of these requirements is not difficult, the performance requirements are not high, and long-term maintenance is not required (meaning that even if no one in the team uses it Flutteror Flutter Webit will hang up one day), it is especially suitable for apportionment to client development. After the client development students joined in, they shared part of the work equally to improve the efficiency of the entire team.
  • 3. Cross-end between the client and the web : I personally think that this part of the demand is relatively small. But if there is such a demand, then we can save a lot of human resources to redevelop a set of webterminals.

Okay, now that there is a demand, let's walk through Flutter Webthe process of how to develop, deploy and go online.

3. Creation and business realization of Flutter Web project

3.1. Create and run

We use Android Studioas an IDE to Flutter 3.10.5create a Flutter Webproject based on the version.
Create one New Flutter Project, Platformsjust check it when selecting Web, and go straight to it Create.

webThen we found an extra folder in the project directory :

If you want to runget up, just select chromethe browser and click run:

Then we can see the running results in the browser. Of course, we can also open the developer mode for easy viewing and debugging:

After this part runs through, congratulations that you can happily use Flutterthe development webpage. Next, we will implement a business requirement: create a webpage search function.

I won’t go into details about the development and implementation of business functions. You can tell Flutterthe students who have done development that there is no difference. The basic configuration/network module/data sharing/routing can be packaged as you want. I just took the code of the corresponding module of the previous client project and modified it slightly Flutter. UIThe development on the website is also how to layout and layout, and the business development experience is no different from that of the client Flutter.

3.2. Debugging

How to debug after running through?
If you are familiar with the browser developer mode, you can directly use the browser to debug. It is no problem to type logor to see the source code, and you can capture packets:debug

Of course , the Android Studioclient -side students may not be familiar with the browser developer mode .Flutterweb

3.3.window

When developing on webthe end, we usually use windowobjects to perform some operations. windowObject represents a browser window or a frame. Objects are required for common eventoperations such as monitoring and opening web pages window.
FlutterThe built-in dart:htmlpackage window, we can use it to realize the acquired windowproperties or windowoperate on them, such as:

//打开网页
window.open("http://www.baidu.com","");

//监听event
window.addEventListener("mousedown", (event) => {
    
    
     //do something
});

In addition window, it can also help us distinguish the operating environment.

3.4. Browser operating environment distinction

The client usually needs to distinguish between Androidthese iOStwo different operating environments, while webthe client needs to UAdistinguish between different browser environments, and the UI/logic in different environments will be different. In China, we most often need to distinguish between PCend/mobile Androidend/end/ iOSend/WeChat webpage/WeChat applet. Then we can define a class and use it window.navigator.userAgentto distinguish these environments:

import 'dart:html';

class DeviceUtil {
    
    
  static final DeviceUtil _instance = DeviceUtil._private();

  static DeviceUtil get() => _instance;

  factory DeviceUtil() => _instance;

  late String ua;

  DeviceUtil._private() {
    
    
    ua = window.navigator.userAgent;
  }

  //移动端
  isMobile() {
    
    
    return RegExp(
        r'phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')
        .hasMatch(ua);
  }

  //iOS端
  isIos() {
    
    
    return RegExp(r'\(i[^;]+;( U;)? CPU.+Mac OS X').hasMatch(ua);
  }

  //Android端
  isAndroid() {
    
    
    var isAndroid = ua.contains("Android") || ua.contains("Adr");
    return isAndroid;
  }

  //微信环境
  isWechat() {
    
    
    return ua.contains("MicroMessenger");
  }

  //微信小程序环境
  isMiniprogram() {
    
    
    if (ua.contains("micromessenger")) {
    
    
      //微信环境下
      if (ua.contains("miniprogram")) {
    
    
        //小程序;
        return true;
      }
    }
    return false;
  }
}


3.5. Development/test/production environment distinction

Like the client, webthe client also needs to distinguish development/test/production environments. In the same way as the client, we can still distinguish the environment by configuring different entry files. like:

  • main_dev.dart
void main() {
    
    
  AppConfig.init(ConfigType.dev);
  root_main.main();
}

  • main_test.dart
void main() {
    
    
  AppConfig.init(ConfigType.test);
  root_main.main();
}

  • main_online.dart
void main() {
    
    
  AppConfig.init(ConfigType.online);
  root_main.main();
}

Now AppConfig.init()you can make different configurations according to different environments.

3.6. Other commonly used libraries or plug-ins

I won’t introduce libraries such as data sharing/network/UI/animation, because these libraries are not related to the platform, just use what you are familiar with. The following is an introduction to the plug-ins that need to be used to implement some browser-related functions.

  • When shared_preferences
    is developed on the client side, we know that if we need to implement lightweight local serialization for some data shared_preferences, we can use it to achieve the Androidcorresponding SharedPreferencessum . When developing, we know that if we need to serialize some data locally, we can use it . In fact , plug-ins are also supported , and their implementation is also encapsulated . I won't go into details about the use of , I'm already very familiar with it.iOSNSUserDefaultswebLocalStorageFluttershared_preferenceswebLocalStorageshared_preferences
  • image_picker_for_web
    comes from our familiar image_pickerplugin. Depending on the browser, it supports or partially supports taking photos/shooting videos/reading pictures/reading videos, etc.
  • The js
    plugin is used to use annotations to help you Dartcall JavaScript APIor JavaScriptcall Dart API.

Well, so far, I think it is no longer a problem to use Flutterand develop a regular business. webNext, let's discuss how to package and deploy online?

4. Package and deploy online

4.1. Packaging

Flutter WebThe packaging is very simple, run:

flutter build web

That's it. But this is obviously not enough, because we need to distinguish the environment to get through the package.
In the previous chapter, we configured different entry files. Let’s take the devenvironment as an example. The entry file is main_dev, then our packaging command becomes:

flutter build web -t lib/main_dev.dart

After the execution of this line of command is completed, an error is reported, and the error message is as follows:

This is an icon data loading problem, we can add --no-tree-shake-icons. Execute the command as follows:

flutter build web -t lib/main_dev.dart --no-tree-shake-icons

Then we will find this folder buildunder the folder of the project root directory , which corresponds to the folder typed out by the front end . Contains the following files:webwebdist

The compiled product is available, so how to deploy it?

4.2. Deployment

The official deployment method is as follows:
https://flutter.cn/docs/deployment/web#deploying-to-the-web
After reading the official documentation, I found that these three deployment methods are not suitable for our project. Due to CDNthe advantages of improving website performance and user experience, and reducing the load on the original server, our team has already built a CDNdeployment platform. That being the case, our deployment plan also needs to rely on this aspect.

4.2.1. Solution 1 - Modify index.html

Let me briefly explain FlutterWebthe compiled product first, with two key points: flutter.jsand main.dart.js. Which flutter.jsis the entry jsfile, we can open webthe directory index.html:

<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="flutter_web">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="favicon.png"/>

  <title>flutter_web</title>
  <link rel="manifest" href="manifest.json">
  <script>
    // The value below is injected by flutter build, do not touch.
    var serviceWorkerVersion = null;
  </script>
  <!-- This script adds the flutter initialization JS code --></script>-->
  <script src="flutter.js" defer></script>
</head>
<body>
  <script>
    window.addEventListener('load', function(ev) {
    
    
      // Download main.dart.js
      _flutter.loader.loadEntrypoint({
    
    
        serviceWorker: {
    
    
          serviceWorkerVersion: serviceWorkerVersion,
        },
        onEntrypointLoaded: function(engineInitializer) {
    
    
          engineInitializer.initializeEngine({
    
    
        }).then(function(appRunner) {
    
    
            appRunner.runApp();
          });
        }
      });
    });
  </script>
</body>
</html>


See <script src="flutter.js" defer></script>this line. It ismain.dart.js the file that our dartbusiness code is compiled into js. and other files flutter.jswill be loaded . main.dart.jsBy default, flutter.jsall files, including resource files ( assets), are loaded using relative paths. The first is loadEntrypoint ()to load main.dart.jsthis file through the method:

//flutter.js
async loadEntrypoint(options) {
    
    
      const {
    
     entrypointUrl = `${
    
    baseUri}main.dart.js`, onEntrypointLoaded } =
        options || {
    
    };

      return this._loadEntrypoint(entrypointUrl, onEntrypointLoaded);
    }

But we found that it seems entrypointUrlthat we can pass it by ourselves, so we found 自定义web应用初始化the link from the official website document:
https://flutter.cn/docs/platform-integration/web/initialization
has the following parameters to pass:

Where loadEntrypoint()methods can be passed entrypointUrlparameters to specify main.dart.jsthe path. The method initializeEngine()can assetBasespecify CDNthe resource path by passing parameters. main.dart.jsSo it seems that we can solve the problem of loading and CDNresource paths by setting these two parameters as absolute paths . It should be noted that initializeEngine()the method is Flutter3.7.0only supported at the beginning.
Let's change it index.html:

    window.addEventListener('load', function(ev) {
    
    
      // Download main.dart.js
      _flutter.loader.loadEntrypoint({
    
    
        serviceWorker: {
    
    
          serviceWorkerVersion: serviceWorkerVersion,
        },
        entrypointUrl: "YOUR_CDN_ABSOLUTE_PATH/main.dart.js",
        onEntrypointLoaded: function(engineInitializer) {
    
    
          engineInitializer.initializeEngine({
    
    
          assetBase: "YOUR_CDN_ABSOLUTE_PATH"
        }).then(function(appRunner) {
    
    
            appRunner.runApp();
          });
        }
      });
    });

If we make another package, it will still report an error and cannot find it flutter.js, or because of the path problem. The processing method is simpler, just index.htmlconfigure it as an absolute path in . Icon-192.pngIn addition , we found favicon.pngthat manifest.jsonthese files are also relative paths, so we change them to absolute paths at once:

<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="flutter_web">
  <link rel="apple-touch-icon" href="YOUR_CDN_ABSOLUTE_PATH/icons/Icon-192.png">

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="YOUR_CDN_ABSOLUTE_PATH/favicon.png"/>

  <title>flutter_web</title>
  <link rel="manifest" href="YOUR_CDN_ABSOLUTE_PATH/manifest.json">
  <script>
    // The value below is injected by flutter build, do not touch.
    var serviceWorkerVersion = null;
  </script>
  <!-- This script adds the flutter initialization JS code -->
  <script src="YOUR_CDN_ABSOLUTE_PATH/flutter.js" defer></script>
</head>

Make another package and upload it CDN, um, everything is normal~
It looks perfect up to here, but suddenly I think it’s wrong. We distinguish between development/testing/production environments, and the corresponding CDNpaths are also different. The modification index.htmlmethod specifies absolute paths, which do not meet our needs. After research, another way was found.

4.2.2 Scheme 2———base-href

Looking at index.htmlthe code again, I found the top note:

  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">

It probably means that we can flutter builduse the value --base-hrefspecified by the parameter when using the package base href. Quickly check out base hrefthe relevant instructions:

The base tag is a base link tag and is a single tag. Used to change the parameter defaults for all link tags in the document. It can only be applied between tags and .
All [relative paths] on your web page will be prepended with the address pointed to by the base link when linking.

In this case, let's try it~
The packaging command is updated as follows:

flutter build web -t lib/main_dev.dart --base-href YOUER_CDN_PATH --no-tree-shake-icons

It should be noted that it is YOUER_CDN_PATHnot an absolute path, but a removed hostpath. For example, your absolute path is:

https://cdn-path.com/your/business/path/dev/
Then your YOUER_CDN_PATHshould be:

/your/business/path/dev/

Make another package and upload it to the CDNwebsite, everything is really perfect~

5. Summary

We have Fluttercompleted webthe development of a project and deployed it to CDN. In addition, webthere are some common problems on the end, such as cross-domain problems, which need to be solved together with the server-side classmates, and they are all ready-made solutions. FlutterWebIn fact, it has been stable for a long time, but it has not developed due to the lack of usage scenarios. But existence is reasonable. For our client development, after we have acquired the skills, we can completely expand our business scope, carry out partial end development, and add more business possibilities for our team, Flutterexcept for the familiar Androidand cross-end development.iOSweb

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here I would like to share with you a set of "Advanced Notes on the Eight Major Modules of Android" written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

Welcome everyone to support with one click and three links. If you need the information in the article, you can directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓

PS: There is also a ChatGPT robot in the group, which can answer your work or technical questions
picture

Guess you like

Origin blog.csdn.net/weixin_43440181/article/details/131834776