flutter

flutter

01 安装

1.1 配置环境变量

安装工具:flutter_windows_v1.9.1+hotfix.6-stable

创建fluterDiv文件夹存放工具包解压

打开环境变量

新增到系统变量的path:

D:\program\fluterDev\flutter\bin

D:\program\fluterDev\flutter\bin\cache\dart-sdk\bin

点击启动文件:D:\program\fluterDev\flutter\flutter_console.bat

命令行运行

flutter doctor

1.2 jdk安装

下载jdk,去往oracle官网注册:

https://login.oracle.com/mysso/signon.jsp

创建文件夹:D:\program\fluterDev\javase

里面分别创建文件夹:jdk、jre

首个安装选择jdk文件夹,安装完成选择jre文件夹

检测安装

java -version

添加环境变量

D:\program\fluterDev\javase\jdk\bin

打包命令

keytool

1.3 androidStudio安装

安装勾选去掉,不安装安卓虚拟设备

首次打开选择第二个,更新到最新版本

弹出报错点击取消cancel

下一步,Custom自定义安装

风格选择略过

勾选最后一个Android

切换SDK地址到D:\program\fluterDev\androidsdk

配置下一步,finish

安装完毕configure>sdk Manager

环境变量的系统变量新增:

变量名:ANDROID_HOME

变量值:D:\program\fluterDev\androidsdk

环境变量的系统变量的path编辑-新增:

D:\program\fluterDev\androidsdk\platform-tools

安卓协议

flutter doctor --android-licenses # 一路yes

打开Android Studio的configure的pulgins里面安装Fluter

1.4 安装模拟器

网易木木模拟器:http://mumu.163.com/

1.5 创建项目

flutter create app_01_test # 创建项目

cd ./app_01_test # 进入项目

flutter doctor # 加载模拟器

flutter run # 运行项目

1.6 配置Gradle镜像地址

# 1. 项目 android/build.gradle
repositories {
    // 注释添加下面
     // google()
     // jcenter()
     maven { url 'https://maven.aliyun.com/repository/google' }
     maven { url 'https://maven.aliyun.com/repository/jcenter' }
     maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
}

allprojects {
    repositories {
          // 注释添加下面
        // google()
        // jcenter()
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
    }
}
   
# 2. flutter sdk目录 
你的sdk目录\flutter\packages\flutter_tools\gradle
repositories {
    // google()
    // jcenter()
    maven { url 'https://maven.aliyun.com/repository/google' }
    maven { url 'https://maven.aliyun.com/repository/jcenter' }
    maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
}

02 第一个程序

2.1 开始编译

创建first.dart文件

var lang = 'dart语言';

void main(){
	print(lang);
}

运行dart

$ dart first.dart

在web端使用编译

$ dart2js first.dart

2.2 定义主题

lib / dart.main

import 'package:flutter/material.dart';

void main() => runApp(MyDream());

// flutter没有组件都叫部件,flutter由一个个部件组成
// stless 快捷键
class MyDream extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Scaffold(
        body: Text('data'),
      ),
    );
  }
}

2.3 结构拆分

import 'package:flutter/material.dart';

void main() => runApp(MyDream());

// flutter没有组件都叫部件,flutter由一个个部件组成
// stless 快捷键
class MyDream extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        // 主题颜色
        primaryColor: Colors.blue,
        // 画布颜色
        canvasColor: Colors.red,
      ),
      home: MyDreamPage(),
    );
  }
}

// 类 快捷键 stful
class MyDreamPage extends StatefulWidget {
  @override
  _MyDreamPageState createState() => _MyDreamPageState();
}

class _MyDreamPageState extends State {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text(''),
    );
  }
}

2.4 变量使用

import 'package:flutter/material.dart';

void main() => runApp(MyDream());
var title1 = '1';

// flutter没有组件都叫部件,flutter由一个个部件组成
// stless 快捷键
class MyDream extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        // 主题颜色
        primaryColor: Colors.blue,
        // 画布颜色
        canvasColor: Colors.red,
      ),
      home: MyDreamPage(),
    );
  }
}

// 类 快捷键 stful
class MyDreamPage extends StatefulWidget {
  final title3 = '导航栏';
  @override
  _MyDreamPageState createState() => _MyDreamPageState();
}

class _MyDreamPageState extends State {
  // const 在类里面要加static
  static const title2 = '2';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        // 导航栏
      appBar: AppBar(
//        title: Text(title1),
        title: Text(widget.title3),
      ),
      body: Text(title2),
      // 返回顶部
      floatingActionButton: FloatingActionButton(
        // 事件函数
        onPressed: null,
        // 按住按键提示
        tooltip: '累加',
        // 图标
        child: Icon(Icons.add),
      ),
    );
  }
}

2.5 回到顶部

// 类 快捷键 stful
class MyDreamPage extends StatefulWidget {
  @override
  _MyDreamPageState createState() => _MyDreamPageState();
}

class _MyDreamPageState extends State {
  static const title = '导航栏';
  int _count = 0;

  // 添加函数方法
  void _addCount() {
    // setState里面写逻辑代码
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Text('$_count'),
      // 返回顶部
      floatingActionButton: FloatingActionButton(
        // 事件函数
        onPressed: _addCount,
        // 按住按键提示
        tooltip: '累加',
        // 图标
        child: Icon(Icons.add),
      ),
    );
  }
}

2.6 布局

body: Center(
    // 子集,纵向
    child: Column(
      // 纵向排列方式
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text('1'),
        Text('2'),
        Text('3'),
      ],
    ),
  ),

2.7 导航

抽屉

  • 头像
  • 用户名
  • 邮箱

导航

  • 标题
  • 图标按钮
  • 文本按钮
import 'package:flutter/material.dart';

void main() => runApp(MyDream());

class MyDream extends StatefulWidget {
  bool colorOffon = false;
  @override
  _MyDreamState createState() => _MyDreamState();
}

class _MyDreamState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primaryColor: widget.colorOffon ? Colors.red : Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            '导航栏',
            style: TextStyle(fontSize: 16),
          ),
          // 按钮
          actions: [
            // 图案图标
            IconButton(
                icon: Icon(Icons.colorize),
                onPressed: () => {
                      setState(() {
                        widget.colorOffon = !widget.colorOffon;
                      })
                    }),
            // 文字图标
            IconButton(icon: Icon(Icons.title), onPressed: null)
          ],
        ),
        // 抽屉-侧拉窗
        drawer: Drawer(
          child: ListView(
            // 设置内边距为0
            padding: EdgeInsets.all(0),
            children: [
              UserAccountsDrawerHeader(
                // 头像图片
                currentAccountPicture: CircleAvatar(
                  // NetworkImage 使用网络图片
                  backgroundImage:
                      NetworkImage('http://www.webzzw.xyz/static/0.jpg'),
                ),
                // 用户名
                accountName: Text('用户名'),
                // 邮箱
                accountEmail: Text('[email protected]'),
              ),
            ],
          ),
        ),
        body: Text('内容'),
      ),
    );
  }
}

抽屉菜单

import 'package:flutter/material.dart';

void main() => runApp(MyDream());

class MyDream extends StatefulWidget {
  bool colorOffon = false;
  List menuList = ['设置图片', '设置颜色', '跳转'];
  @override
  _MyDreamState createState() => _MyDreamState();
}

class _MyDreamState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primaryColor: widget.colorOffon ? Colors.red : Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            '导航栏',
            style: TextStyle(fontSize: 16),
          ),
          // 按钮
          actions: [
            // 图案图标
            IconButton(
                icon: Icon(Icons.colorize),
                onPressed: () => {
                      setState(() {
                        widget.colorOffon = !widget.colorOffon;
                      })
                    }),
            // 文字图标
            IconButton(icon: Icon(Icons.title), onPressed: null)
          ],
        ),
        // 抽屉-侧拉窗
        drawer: Drawer(
            child: ListView.builder(
                itemCount: widget.menuList.length,
                itemBuilder: (BuildContext context, int index) {
                  // 头像数据
                  if (index == 0) {
                    return UserAccountsDrawerHeader(
                      // 头像图片
                      currentAccountPicture: CircleAvatar(
                        // NetworkImage 使用网络图片
                        backgroundImage:
                            NetworkImage('http://www.webzzw.xyz/static/0.jpg'),
                      ),
                      // 用户名
                      accountName: Text('用户名'),
                      // 邮箱
                      accountEmail: Text('[email protected]'),
                    );
                  }

                  // 菜单
                  return ListTile(
                    title: Text(widget.menuList[index]),
                    trailing: Icon(Icons.settings),
                  );
                })),
        body: Text('内容'),
      ),
    );
  }
}

2.8 页面跳转

lib下创建pages页面文件夹,里面创建subPage.dart文件

// main.dart
import 'package:app_01_test/pages/subPage.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyDream());

class MyDream extends StatefulWidget {
  bool colorOffon = false;
  List menuList = ['设置图片', '设置颜色', '跳转'];
  @override
  _MyDreamState createState() => _MyDreamState();
}

class _MyDreamState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primaryColor: widget.colorOffon ? Colors.red : Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            '导航栏',
            style: TextStyle(fontSize: 16),
          ),
          // 按钮
          actions: [
            // 图案图标
            IconButton(
                icon: Icon(Icons.colorize),
                onPressed: () => {
                      setState(() {
                        widget.colorOffon = !widget.colorOffon;
                      })
                    }),
            // 文字图标
            IconButton(icon: Icon(Icons.title), onPressed: null)
          ],
        ),
        // 抽屉-侧拉窗
        drawer: Drawer(
            child: ListView.builder(
                itemCount: widget.menuList.length,
                itemBuilder: (BuildContext context, int index) {
                  // 头像数据
                  if (index == 0) {
                    return UserAccountsDrawerHeader(
                      // 头像图片
                      currentAccountPicture: CircleAvatar(
                        // NetworkImage 使用网络图片
                        backgroundImage:
                            NetworkImage('http://www.webzzw.xyz/static/0.jpg'),
                      ),
                      // 用户名
                      accountName: Text('用户名'),
                      // 邮箱
                      accountEmail: Text('[email protected]'),
                    );
                  }

                  // 菜单,使用事件
                  return GestureDetector(
                    onTap: () {
                      // 跳转页面
                      Navigator.push(context, MaterialPageRoute(
                        builder: (BuildContext context) {
                          // 跳转的页面
                          return SubPage(
                            id: 1,
                            title: widget.menuList[index],
                          );
                        },
                      ));
                    },
                    child: ListTile(
                      title: Text(widget.menuList[index]),
                      trailing: Icon(Icons.settings),
                    ),
                  );
                })),
        body: Text('内容'),
      ),
    );
  }
}

跳转的页面

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

class SubPage extends StatefulWidget {
  // 接收其他页面传来的参数
  final id;
  final title;
  // @required 必须传的参数
  SubPage({Key key, @required this.id, this.title});

  @override
  _SubPageState createState() => _SubPageState();
}

class _SubPageState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
      ),
    );
  }
}

2.9 Hello word

打开程序运行入口文件main文件,删掉所有代码,重新构建

// 引入material风格库,是自动按需要引入的
import 'package:flutter/material.dart';

// 入口函数,学过其它语言的同学不陌生,自执行
void main() {
  // 最小的Flutter应用程序只是调用runApp()函数与一个小部件,该部件会将其设为小部件树的根部件
  // flutter框架根部件会强制根部件覆盖屏幕,这意味着文本“ Hello,world”最终以屏幕为中心
  // 
  runApp(
    Center(
      child: Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

03 项目结构

    android目录
        这里存放的是Flutter与android原生交互的一些代码
    build目录
        存储 iOS 和 Android 构建文件
    ios目录
        这里存放的是Flutter与ios原生交互的一些代码
    lib目录
        应用源文件,存放的是我们用Dart语言编写程序的源代码
        main.dart
        应用程序运行入口文件
    test目录
        测试文件
    pubspec.yaml文件
        相当其它技术栈框架的package.json文件,是配置项目依赖项的文件,比如配置远程pub仓库的依赖库,或者指定本地资源(图片、字体、音频、视频等)

04 MaterialApp路由

  • 为了继承主题数据,配置全局路由、路由守卫和一些其它配置,通常我们会把MaterialApp作为整个应用程序根部件使用
  • MaterialApp 窗口小部件完全是可选的,但是是一种很好的做法
  • 其命名参数有:
MaterialApp({
  Key key,
  this.title = '', // 设备用于为用户识别应用程序的单行描述
  this.home, // 应用程序默认路由的小部件,用来定义当前应用打开的时候,所显示的界面
  this.color, // 在操作系统界面中应用程序使用的主色。
  this.theme, // 应用程序小部件使用的颜色。
  this.routes = const {}, // 应用程序的顶级路由表
  this.navigatorKey, // 在构建导航器时使用的键。
  this.initialRoute, // 如果构建了导航器,则显示的第一个路由的名称
  this.onGenerateRoute, // 应用程序导航到指定路由时使用的路由生成器回调
  this.onUnknownRoute, // 当 onGenerateRoute 无法生成路由(initialRoute除外)时调用
  this.navigatorObservers = const [], // 为该应用程序创建的导航器的观察者列表
  this.builder, // 用于在导航器上面插入小部件,但在由WidgetsApp小部件创建的其他小部件下面插入小部件,或用于完全替换导航器
  this.onGenerateTitle, // 如果非空,则调用此回调函数来生成应用程序的标题字符串,否则使用标题。
  this.locale, // 此应用程序本地化小部件的初始区域设置基于此值。
  this.localizationsDelegates, // 这个应用程序本地化小部件的委托。
  this.localeListResolutionCallback, // 这个回调负责在应用程序启动时以及用户更改设备的区域设置时选择应用程序的区域设置。
  this.localeResolutionCallback, // 
  this.supportedLocales = const [Locale('en', 'US')], // 此应用程序已本地化的地区列表 
  this.debugShowMaterialGrid = false, // 打开绘制基线网格材质应用程序的网格纸覆盖
  this.showPerformanceOverlay = false, // 打开性能叠加
  this.checkerboardRasterCacheImages = false, // 打开栅格缓存图像的棋盘格
  this.checkerboardOffscreenLayers = false, // 打开渲染到屏幕外位图的图层的棋盘格
  this.showSemanticsDebugger = false, // 打开显示框架报告的可访问性信息的覆盖
  this.debugShowCheckedModeBanner = true, // 在选中模式下打开一个小的“DEBUG”横幅,表示应用程序处于选中模式
}) 

05 脚手架

Scaffold是我们布局的主要支撑部件,每一个用户界面都应该有一个Scaffold根部件,通过Scaffold脚手架快速搭建我们的用户界面结构,提供了用于显示drawer、snackbar和底部sheet的API

appBar	   //    头部导航栏
body	       //  主体
floatingActionButton	   //  悬浮按钮
floatingActionButtonLocation	   //  悬浮按钮位置
floatingActionButtonAnimator	   //  悬浮按钮动画
persistentFooterButtons	     // 显示在底部的一组按钮
drawer	                  // 侧拉抽屉菜单
endDrawer	               // 侧拉抽屉菜单 与上面属性相反
bottomNavigationBar	         //  显示在底部的导航栏
bottomSheet	                  //  要显示的持久底部工作表
backgroundColor	             // 背景颜色
resizeToAvoidBottomPadding	 // 已废弃
resizeToAvoidBottomInset	  //   为true时:浮动小部件自动调整,以避免弹出键盘时被遮盖
primary	                    默认true
drawerDragStartBehavior	   // 默认DragStartBehavior.start
extendBody	                 // 默认false
drawerScrimColor	         //  抽屉打开时用来遮盖主要内容的涂布颜色

06 界面结构

6.1 头部导航

AppBar({
    Key key,
    this.leading,//在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮
    this.automaticallyImplyLeading = true,
    this.title,//Toolbar 中主要内容,通常显示为当前界面的标题文字
    this.actions,//一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单
    this.flexibleSpace,//一个显示在 AppBar 下方的控件,高度和 AppBar 高度一样,可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用
    this.bottom,//一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
    this.elevation = 4.0,//纸墨设计中控件的 z 坐标顺序,默认值为 4,对于可滚动的 SliverAppBar,当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值
    this.backgroundColor,//APP bar 的颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用
    this.brightness,//App bar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness
    this.iconTheme,//App bar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData.primaryIconTheme
    this.textTheme,//App bar 上的文字样式。默认值为 ThemeData.primaryTextTheme
    this.primary = true,
    this.centerTitle,//标题是否居中显示,默认值根据不同的操作系统,显示方式不一样,true居中 false居左
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,
    this.toolbarOpacity = 1.0,
    this.bottomOpacity = 1.0,
})
抽屉
  • 左侧抽屉

    // appBar 同级
    drawer: Drawer(
        child: ListView(
          children: [
            UserAccountsDrawerHeader(
              accountName: Text('Zzw'),
              accountEmail: Text('[email protected]'),
              currentAccountPicture: CircleAvatar(
                backgroundImage:
                    NetworkImage('http://www.webzzw.xyz/static/4.jpg'),
              ),
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage('http://www.webzzw.xyz/static/2.jpg'),
                  fit: BoxFit.cover,
                ),
              ),
            ),
            ListTile(
              onTap: () {},
              title: Text('用户反馈'),
              trailing: Icon(Icons.feedback),
            ),
            ListTile(
              onTap: () {},
              title: Text('系统设置'),
              trailing: Icon(Icons.settings),
            ),
            ListTile(
              onTap: () {},
              title: Text('文章发布'),
              trailing: Icon(Icons.send),
            ),
            // 分割线
            Divider(
              color: Colors.blue,
            ),
            ListTile(
              onTap: () {},
              title: Text('退出'),
              trailing: Icon(Icons.exit_to_app),
            ),
          ],
        ),
      ),
    
  • 打开抽屉方法

    import 'package:flutter/material.dart';
    
    class StudyDrawer extends StatelessWidget {
      // 抽屉key
      GlobalKey _globalKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          // 添加状态key
          key: _globalKey,
          appBar: AppBar(
            title: Text('抽屉'),
            centerTitle: true,
          ),
          drawer: Drawer(...),
          body: IconButton(
            icon: Icon(Icons.open_in_new),
            onPressed: () {
                // 打开抽屉
              _globalKey.currentState.openDrawer();
            },
          ),
        );
      }
    }
    
    
  • 右侧自定义抽屉

    // appBar 同级
    endDrawer: Container(
        width: 300,
        color: Colors.pinkAccent,
        child: Column(
          children: [
            UserAccountsDrawerHeader(
              accountName: Text('Zzw'),
              accountEmail: Text('[email protected]'),
              currentAccountPicture: CircleAvatar(
                backgroundImage:
                    NetworkImage('http://www.webzzw.xyz/static/4.jpg'),
              ),
              decoration: BoxDecoration(
                image: DecorationImage(
                    image: NetworkImage('http://www.webzzw.xyz/static/2.jpg'),
                    fit: BoxFit.cover,
                    // 背景颜色透明
                    colorFilter: ColorFilter.mode(
                      Colors.green.withOpacity(0.8),
                      BlendMode.color,
                 )),
              ),
            ),
          ],
        ),
      )
    

03 app打包

3.1 网络权限

android/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.movies">

    
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="movies"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            intent-filter>
        activity>
    application>

	
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
manifest>

3.2 签名

创建 keystore

$ keytool -genkey -v -keystore 英文名.keystore -alias 别名 -keyalg RSA -keysize 2048 -validity 10000 -storepass 密码 -keypass 密码 

例:
$ keytool -genkey -v -keystore article.keystore -alias article -keyalg RSA -keysize 2048 -validity 10000 -storepass article -keypass article 

引用应用程序中的keystore,生成的 英文名.keystore 文件放到 android/app/下

创建一个名为/android/key.properties的文件,其中包含对密钥库的引用

# /android/key.properties

storePassword=密码
keyPassword=密码
keyAlias=别名
storeFile=英文名.keystore

3.3 在gradle中配置签名

通过编辑/android/app/build.gradle文件为您的应用配置签名

替换:

android {

为:

def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

android {

替换:

buildTypes {
    release {
        // TODO: Add your own signing config for the release build.
        // Signing with the debug keys for now, so `flutter run --release` works.
        signingConfig signingConfigs.debug
    }
}

为:

signingConfigs {
    release {
        keyAlias keystoreProperties['keyAlias']
        keyPassword keystoreProperties['keyPassword']
        storeFile file(keystoreProperties['storeFile'])
        storePassword keystoreProperties['storePassword']
    }
}
buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}

3.4 打包

切换到项目根目录

$ flutter build apk

打包好的发布APK位于/build/app/outputs/apk/app-release.apk

你可能感兴趣的:(前端开发)