Flutter随笔(二)——使用Flutter Web + Docker + Nginx打造一个简单的Web项目

三味码屋 2021年10月14日 3,411次浏览

前言

Flutter作为一个跨平台UI框架,功能十分强大,仅用一套代码便能编译出Android、iOS、Web、windows、macOS、Windows、Linux等平台上的应用,各平台应用体验高度一致,目测前途一片光明,形势一片大好。

Flutter支持Android和iOS已经很长一段时间了,相信很多同学对使用Flutter开发Android和iOS应用都已经驾轻就熟了,今天我们就来体验一把Flutter Web。目标是创建一个简单的Flutter Web项目,然后打包部署到服务器,通过浏览器进行访问。

1.创建Flutter工程

首先我们需要创建一个Flutter工程。我使用了Android Studio来创建工程,如下:
image.png
上图中需要注意的地方是Platforms,在Platforms栏中我们要选择程序运行的平台,因为我们最终要打包出Web项目,所以我们务必勾选Web选项。
工程创建好之后的目录结果如下:
image.png
除了我们熟悉的Android和iOS目录外,还多了Web目录,Web目录下存放了Web项目所需要的全部文件。

2.编写flutter代码

接下来,我们编写flutter代码,代码非常简单,仅实现了在主页点击按钮跳转到对应子页面的功能。
主页main.dart的代码如下:

import 'package:flutter/material.dart';

import 'ChildPage.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'xy_flutter',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'xy_flutter'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;
  final List<HomeMenu> menus = [
    HomeMenu('page1', '页面1'),
    HomeMenu('page2', '页面2'),
    HomeMenu('page3', '页面3'),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: ListView.builder(
          itemCount: menus.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(menus[index].title),
              onTap: () {
                HomeMenu homeMenu = menus[index];
                String id = homeMenu.id;
                String title = homeMenu.title;
                if (id == 'page1') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                } else if (id == 'page2') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                } else if (id == 'page3') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                }
              },
            );
          }),
    );
  }
}

class HomeMenu {
  String id;
  String title;

  HomeMenu(this.id, this.title);
}

子页面child_page.dart的代码如下:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class ChildPage extends StatefulWidget {
  final String title;

  const ChildPage({Key key, this.title}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _ChildPageState();
  }
}

class _ChildPageState extends State<ChildPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(widget.title)), body: Text(widget.title));
  }
}

3.打包Web工程

在工程根目录下执行以下命令进行编译打包:

flutter build web

命令执行成功之后,编译生成的文件被输出到了工程根目录/build/web/目录下,如下:
image.png

4.上传Web工程到服务器

通过文件传输工具(例如FileZilla等)将编译后生成的所有文件上传到服务器。我上传到服务器的路径为home/ubuntu/docker/xy_flutter/web/home/ubuntu/docker/xy_flutter/web/目录和工程编译出来的web目录对应,即home/ubuntu/docker/xy_flutter/web/目录下的文件和工程编译出来的web目录下的文件完全一致。

5.创建Nginx Docker容器

接下来,我们在服务器中创建一个Nginx的Docker容器,用来运行Web项目。
如果服务器还没有安装Docker,需要先安装Docker,关于如何安装Docker可以参考我之前整理的资料Docker游记1——安装Docker
如果已经安装好了Docker,但还没有拉取Nginx的Docker镜像,需要先拉取一下镜像,可以通过如下命令拉取最新的Nginx Docker镜像:

docker pull nginx:latest

镜像拉取下来之后,可以通过如下命令查看当前所有已拉取下来的镜像:

docker images

得到的结果如下:

REPOSITORY     TAG       IMAGE ID       CREATED        SIZE
nginx          latest    87a94228f133   2 days ago     133MB

我们可以看到已经有Nginx的镜像了。
接着我们利用拉取下来的镜像创建一个容器,执行以下命令:

docker run --name xy_flutter -p 8088:80 -d nginx

这行命令表示使用Nginx镜像创建并持续运行一个名为xy_flutter的容器,并将服务器的8088端口映射到容器的80端口。创建好之后,可以通过以下命令查看创建好的容器:

docker ps

结果如下:

CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                                       NAMES
0c6f697a8e0c   nginx               "/docker-entrypoint.…"   5 seconds ago   Up 3 seconds   0.0.0.0:8088->80/tcp, :::8088->80/tcp       xy_flutter

容器创建好之后,我们就可以通过浏览器访问容器对应的Nginx服务了,因为我的服务器地址IP地址是http://49.234.163.66/,容器映射的服务器端口是8088,所以访问地址是http://49.234.163.66:8088/,访问后跳转的页面如下:
image.png
已经看到Nginx在欢迎我们了!

6.部署Web工程

我们通过浏览器访问Nginx服务时,跳转的页面其实是容器中的/usr/share/nginx/html/index.html文件,我们可以进入容器查看。
执行以下命令进入容器:

docker exec -it {容器ID} /bin/bash

进入容器后,我们通过cd命名访问/usr/share/nginx/html/目录,目录中的文件如下:
image.png
要部署Web工程,把Web工程中的所有文件复制到容器的/usr/share/nginx/html/目录就可以了,Web工程中的index.html会覆盖/usr/share/nginx/html/index.html文件。我们通过如下命令把服务器本地的文件复制到容器中:

docker cp {服务器中Web工程目录下的所有子文件} {容器ID}:/usr/share/nginx/html

我的服务器中Web工程目录下的所有子文件是home/ubuntu/docker/xy_flutter/web/.,容器ID是0c6f697a8e0c,所以我执行的命令是:

docker cp home/ubuntu/docker/xy_flutter/web/. 0c6f697a8e0c:/usr/share/nginx/html

7.部署完成

在上述步骤中,我们已经将Web工程拷贝到容器中的指定位置了,到这里部署工作其实也就完成了,我们再次在浏览器中输入http://49.234.163.66:8088/访问,可以看到已经可以打开我们的Web工程了,如下:
image.png
image.png
至此,我们就完成了从创建Flutter Web项目到部署至服务器的整个流程!

最后奉上项目地址