Flutter 商城App开发指南
Flutter是Google开源的构建用户界面(UI)工具包,帮助开发者通过一套代码库高效构建多平台精美应用。
文章描述我在学习 Flutter 时仿 贪吃商城
开发 Demo 的全过程。旨在帮助有布局基础的 flutter 新手完整地开发一个移动端应用
商城Demo 展示图:
阅读文章你将收获
- Flutter 快速上手能力
- 开发中部分问题的解决方案
- Flutter 数据模型的编写
- 集成 iconfont 字体图标
- 打包 安卓APP 注意事项与具体流程
Flutter 开发环境搭建
项目使用 Flutter 2.10.2
版本,您可使用相近的 Flutter 2.x 版本:
Flutter 2.10.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 097d3313d8 (8 weeks ago) • 2022-02-18 19:33:08 -0600
Engine • revision a83ed0e5e3
Tools • Dart 2.16.1 • DevTools 2.9.2
-
选择要安装 Flutter 的操作系统,并按照官方操作流程进行 Flutter 环境的安装及验证:
- Flutter 官网:docs.flutter.dev/get-started…
- Flutter 中文官网:flutter.cn/docs/get-st…
-
在 VS Code 中开发,(个人建议使用轻量的 vscode 开发)
-
配置编辑器:flutter.cn/docs/get-st…
-
创建 Flutter 项目
Android Studio 中创建新项目:
- 选择 File>New Flutter Project
- 选择 Flutter application 作为 project 类型, 然后点击 Next
- 输入项目名称 (如
myapp
), 然后点击 Next - 点击 Finish
- 等待Android Studio安装SDK并创建项目
VS Code 中创建新项目:
- 在VS Code调用 View>Command Palette(快捷键 F1)
- 输入 ‘flutter’, 然后选择 ‘Flutter: New Project’ action
- 输入项目名称 (如
myapp
), 然后按回车键 - 指定项目的存放位置,然后确定
- 等待项目创建继续,并显示main.dart文件
运行项目
- 准备虚拟机
- mac 电脑可在终端执行
$ open -a Simulator
打开 iphone 虚拟机 - 安装有 Android Studio 的同学可以在 Android Studio 中打开 安卓虚拟机
- 无虚拟机,也可以使用 web 浏览器模式运行开发
- mac 电脑可在终端执行
- 在终端执行指令
flutter run
运行项目
路由导航配置
- 新建
lib/routers/routes.dart
文件:
import 'package:f_mall/views/detail/rank_index.dart';
import 'package:f_mall/views/detail/detail_index.dart';
import 'package:flutter/material.dart';
Route onGenerateRoute(RouteSettings settings) {
switch (settings.name) {
// 详情页面
case '/detail':
return MaterialPageRoute(
builder: (_) => DetailIndex(), settings: settings);
// 排行榜页面
case '/rank':
return MaterialPageRoute(
builder: (_) => RankIndex(), settings: settings);
// 404
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
appBar: AppBar(
title: const Text('404'),
),
body: const Center(child: Text('Not Found.')),
),
);
}
}
- MaterialApp 中 使用路由生成器属性
onGenerateRoute
:
import 'package:f_mall/routers/routes.dart';
...
@override
Widget build(BuildContext context) {
return MaterialApp(
themeMode: ThemeMode.light,
theme: appThemeData(context),
darkTheme: appThemeData(context, isDark: true),
title: 'Foodies Mall',
onGenerateRoute: onGenerateRoute, // 路由生成器
home: NavigationWithView(
items: _navigationWithViewItems,
),
);
}
网络请求与数据模型
Http 请求
使用 dio
库,dio 封装查看: flutter_dio_util
import 'package:dio/dio.dart';
/// More examples see https://github.com/flutterchina/dio/tree/master/example
void main() async {
var dio = Dio();
final response = await dio.get('https://google.com');
print(response.data);
}
// response.data 这里返回的是json字符串,可使用 data['name'] 获取值
// 要想像 Object 一样使用 data.name 获取。需要转换为Dart模型(Json to Dart)
Json to Dart
Person
模型,使用 quicktype 快速将 Json 转换 为 dart 模型
// 假设有如下person数据:
{
"name": "jsdawn",
"age": 18,
"gender": ""
}
// models/person.dart
// To parse this JSON data, do
//
// final person = personFromJson(jsonString);
import 'dart:convert';
Person personFromJson(String str) => Person.fromJson(json.decode(str));
String personToJson(Person data) => json.encode(data.toJson());
class Person {
Person({
this.name,
this.age,
this.gender,
});
String name;
int age;
String gender;
// json中字段不可少,否则需要判空:json["name"] ?? ""
factory Person.fromJson(Map<String, dynamic> json) => Person(
name: json["name"],
age: json["age"],
gender: json["gender"],
);
Map<String, dynamic> toJson() => {
"name": name,
"age": age,
"gender": gender,
};
}
在 flutter 中使用:
// 这里 DefaultAssetBundle 的 loadString 加载json文件,模拟接口调用
String jsonString = await DefaultAssetBundle.of(context)
.loadString('assets/json/data.json');
// 转为 dart model
final person = personFromJson(jsonString);
print(person.name);
字体图标
方案一: 使用 iconfont_builder 工具
# --from 字体文件夹,--to 生成的Iconfont.dart文件存放路径,--family 自定义字体名
$ iconfont_builder --from ./fonts ,--to ./lib/Iconfont.dart --family MyIcon
方案二:手动自定义字体图标(推荐)
- 引入图标字体:从 iconfont.cn 下载图标字体,将 demo_index.html 和 iconfont.ttf 复制到项目文件
my_project/fonts/my_icons
- my_project
- lib
- fonts
- my_icons
demo_index.html
iconfont.ttf
- 配置 flutter 文字资源,编辑
pubspec.yaml
:
fonts:
- family: MyIcons
fonts:
- asset: fonts/my_icons/iconfont.ttf
- 新建
MyIcons
类:
import 'package:flutter/widgets.dart';
/// 自定义 Icons 类
/// iconfont图标字体的 Unicode 可在第一步中的 demo_index.html 查看
class MyIcons {
MyIcons._();
// home iconfont图标字体的 Unicode 为 , IconData对应为 0xe60f
static const IconData home = IconData(0xe60f, fontFamily: 'MyIcons');
// home iconfont图标字体的 Unicode 为 , IconData对应为 0xe610
static const IconData user = IconData(0xe610, fontFamily: 'MyIcons');
}
像官方一样使用
import 'package:f_mall/widgets/common/my_icons.dart';
...
Widget MyHomeIcon() {
return const Padding(
padding: EdgeInsets.all(5.0),
// MyIcons.home
child: Icon(MyIcons.home),
);
}
打包 apk
--no-sound-null-safety
跳过零空安全检查,
--split-per-abi
减少包大小
flutter build apk --no-sound-null-safety --split-per-abi
打包成功后,apk 存放在 build/app/outputs/apk/release/
目录中
- 若安卓打包 apk 后网络图片不显示
在 android/app/src/profile/AndroidManifest.xml
中允许网络权限(若无效则需要在 android/app/src/main/AndroidManifest.xml
也配置一份):
<uses-permission android:name="android.permission.INTERNET"/>
- 安卓app签名(若需要发布 apk 到各应用市场)
- 终端执行下方指令获取秘钥文件,(文件默认在当前目录):
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
将 key.jks 复制到 android/app/
目录。
android/key.properties
文件(没有则新建)
storePassword=<上一步骤中的密码>
keyPassword=<上一步骤中的密码>
keyAlias=key
storeFile=key.jks
android/app/build.gradle
中,android
代码块之前新增内容
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
// android 代码块
android {
...
}
替换 buildTypes
代码块:
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
结语
很荣幸你能看到这里。文章看上去简单,学习的路还是挺坎坷的。老样子,遇到问题的时候各种百度,综合多个解决方案选择最优解。期待你也能做出满意的作品...
转载声明: 请注明作者,注明原文链接,有疑问致邮 kingwyh1993@163.com
转载自:https://juejin.cn/post/7088233741751402532