本人学生一个,菜鸡一枚,对Flutter非常感兴趣,断断续续学了大概一年,在掘金仰观各位大佬的文章,学到了很多,自己也做了一两个APP,每次想着都要重新写工具类就很麻烦,就写了当前这个项目,为的能够更快搭建一个Flutter项目。
项目东西比较杂,代码的侵入性也很强,所以只建议搭建简单App时使用,同时可能存在bug,本人能力有限😂,大家clone代码可以自己修改,希望能够有所帮助,如果觉得有帮助可以帮忙点个star
介绍
一个简单的脚手架项目,你可以通过clone该项目,进行一个快速的Flutter项目开发,该脚手架
项目提供了常用的功能封装,包括Http、WebSocket、Sqlite、File、Camera、Permission等功能的使用,同时提供了非常多的工具库, 协助开发者进行使用
(部分工具库参照本人的JavaSkyeUtil的库进行编写,较为方便)
主要目录的功能
lib/configuration: 包含相关功能的配置方式及配置信息auto_configuration: 主要为实现自动配置的类,其不需要修改,相关的配置信息在application.yaml中进行修改,主要包含sqlite,websocket,http其余文件: 实现相关的配置信息,主要包含:国际化、initializer、路由
lib/expand: 主要是对原有功能的拓展部分class_extension: 对于相关原有类的拓展,实现功能的增强,主要包含list,listview,map,string,widgetdata_structure: 一些新增的数据结构,主要包含 二维表格构widget: 一些新增的组件,主要包含 状态保存组件、方向控制组件
lib/initiaializer: 包含所有的初始化类,其控制初始化逻辑,及相关工具service: 服务性初始化任务,主要包含sqlite.http,websocket初始化器ui: 界面性初始化器,主要包含 状态栏颜色控制
lib/standard: 主要包含所有的全局统一UI标准,主要为颜色,字体,组件lib/store: 编写相关存储的部分entity: 存放相关实体类的目录bo: business objectpo: persistence objectdto: data transfer objectvo: view objectmap_struct: map_struct转换器,包含所有的转换对象impl: 使用smart_struct生成的转换实体类
http: 向上提供Http服务api: 向Controller层提供对应的Http Api服务interceptor: 主要是存放相关的request拦截器和response拦截器
sqlite: 向上提供sqlite服务api: 向Controller层提供对应的Sqlite Api服务
lib/system: 提供相关与系统紧密相关的服务flie: 提供硬盘文件读写服务hardware: 提供相关的硬件支持,主要包含相机http: http服务的底层封装,以及提供异步解码器等功能resource: 提供对于resource目录下文件操作的支持yaml: 提供对于yaml文件解析的支持
sqlite: sqlite服务的相关封装websocket:websocket服务的相关封装
lib/ui: 编写界面的目录lib/util: 提供相关的工具类service: 提供服务性的工具event_bus: 对于事件总线的封装serialize: 对于序列化的支持smart_struct: 对于smart_struct的支持其他文件:包含剪切板、SharedPreference、权限、Isolate的封装
resoure: 相关的资源文件data: 需要使用到的数据文件,主要包含emoji文件image: 静态照片application.yaml: 全局配置文件sqlite_table.yaml: sqlite 数据表的生成工具
简单工具类
业务工具
日志工具
可以自定义日志前缀名
必选参数:
- author: 前缀名称
Logger logger = Log.getInstance(author = "alien");
可以直接打印对应的日志
必选参数:
- message: 消息内容
可选参数:
- authorName: 前缀名,默认值为 Skye
直接调用则会使用默认前缀
Log.i("this is an info logger");
Log.d("this is a debug logger");
Log.w("this is a warning logger");
Log.e("this is an error logger");
资源工具
读取resource文件夹下的字符串文件
必选参数:
- fileName: 文件名
String assetStr = await AssetUtil.readDataFile("emoji.json");
读取resource文件夹下的照片文件,并转换为AssetImage对象
必选参数:
- fileName: 文件名
AssetImage assetImage = AssetUtil.readDataImage("asset_image.png");
缓存工具
存对象
必选参数:
- key: 键
- value: 值
CacheUtil.put("key","value");
取对象
必选参数:
- key: 键
dynamic value = CacheUtil.get("key");
删除对象
必选参数:
- key: 键
CacheUtil.remove("key");
剪切板工具
剪切板写入数据
必选参数:
- data: 需要写入剪切板的数据
ClipboardUtil.put("data");
剪切板获取数据,只会获得最新的数据
String data = await ClipboardUtil.get();
时间工具
获得当前的时间
// 获得DateTime对象
DateTime nowDateTime = DatetimeUtil.now();
// 获得当前的时间戳
int nowTimeStamp = DatetimeUtil.nowTimeStamp();
将时间戳转换为DateTime对象
必选参数:
- timeStamp: 时间戳
DateTime nowDateTime = DatetimeUtil.fromTimeStamp(nowTimeStamp);
字符串转时间对象
必选参数:
- datetimeString: 时间字符串
DateTime dateTime = DatetimeUtil.convertStringToDate("2022-12-10");
时间对象转字符串
必选参数:
- dateTime: 时间对象
- formatString: 格式化字符串
String dateStr = DatetimeUtil.convertDateToString(dateTime, "yyyy-mm-dd");
数字处理工具
获得指定范围内的一个随机数字
可选参数:
- ceil: 最大值,默认为1000
- floor: 最小值,默认为0
int number = NumberUtil.createRandomNumber(ceil = 100, floor = 0);
对象工具
单个判空操作
必选参数:
- obj: 目标对象
// 对象是否为空
bool result = ObjectUtil.isEmpty(obj);
// 对象是否不为空
bool result = ObjectUtil.isNotEmpty(obj);
集合判空操作
必选参数:
- <List> objList: 目标对象列表
// 集合是否全为空
bool result = ObjectUtil.isAllEmpty(objList);
// 集合存在空值
bool result = ObjectUtil.isAnyEmpty(objList);
对象默认值判断
必选参数:
- obj: 目标对象
// 该对象是否为默认值
bool result = ObjectUtil.isDefaultValue(obj);
集合默认值判断
必选参数:
- <List> objList: 目标对象列表
// 集合中所有值是否为默认值
bool result = ObjectUtil.isAllDefaultValue(objList);
字符串工具
生成一个UUID
String uuid = StringUtil.getUUID();
分割字符串同时保留连接符在数组中
必选参数:
- str: 目标字符串
- reg: 用于分割的正则表达式
// 返回["www",".","google",".","com"]
List<String> list = StringUtil.splitAndJoin("www.google.com", ".");
计时工具
延迟执行任务
必选参数:
- delaySeconds: 延迟毫秒数
- function: 任务方法
// 任务将会在1s后执行
TimerUtil.delayExecuteTask(1000,function);
周期执行任务
必选参数:
- intervalSeconds: 执行间隔毫秒数
- function: 任务方法
可选参数:
- count: 重复次数,默认值3
- delaySeconds: 延迟毫秒数,默认为0
// 任务将会在0.5S后开始周期执行,中间的间隔时间为1S,总共需要执行的次数为3次
TimerUtil.periodExecuteTask(
intervalSeconds: 1000,
function: myFunction,
count: 3,
delaySeconds: 500);
字节工具
将字符串转换成字节
必选参数:
- hexData: 字符串数据
Uint8List uList = ByteUtil.stringToUList("Hello World!");
将字节转换成字符串
必选参数:
- uint8list: 字节数据
String str = ByteUtil.ulistToString(uList);
将二进制字符串转换成字节
必选参数:
- binaryString: 二进制字符串
Uint8List uList = ByteUtil.binaryStringToUList("101010");
将十六进制字符串转换成字节
必选参数:
- hexString: 十六进制字符串
Uint8List uList = ByteUtil.hexStringToUList("7F1A0B");
将int列表转成字节列表
必选参数:
- <List> list: int列表
Uint8List uList = ByteUtil.listToUList([1,2,3,16]);
将字节列表转成int列表
必选参数:
- uint8list: 字节列表
List<int> list = ByteUtil.ulistToList(ulist);
UI工具
屏幕参数工具
获得Material Design的AppBar高度
double height = ScreenUtil.getAppBarHeight();
获得状态栏的高度
double height = ScreenUtil.getStatusBarHeight();
获得Scaffold主体高度
double height = ScreenUtil.getScaffoldBodyHeight();
获得弹出的软键盘高度
double height = ScreenUtil.getSoftKeyboardHeight();
Sliver工具
删除List自带的上方Padding
MediaQuery mediaQuery = SliverUtil.removeTop(listView, context);
系统ui工具
是否为竖屏状态
必选参数:
- context: 上下文对象
bool isPortrait = SystemUiUtil.isPortrait(context);
设置屏幕方向
必选参数:
- screenDirection: 屏幕方向
SystemUiUtil.setScreenDirection(ScreenDirection.Portrait);
SystemUiUtil.setScreenDirection(ScreenDirection.Landscape);
设置是否隐藏状态栏
必选参数:
- operationBarState: 操作栏状态
SystemUiUtil.setOperationBarState(OperationBarState.Hide);
SystemUiUtil.setOperationBarState(OperationBarState.Show);
判断软键盘是否打开
bool result = softKeyboardIsOpen();
关闭软键盘
SystemUiUtil.closeSoftKeyboard();
显示Toast
必选参数:
- errorMsg: 错误信息
可选参数:
- <String?> successMsg: 成功信息,默认为""
- state: 状态,默认为null
// 根据state的值选择内容显示
SystemUiUtil.showToast("error message",successMsg="success message",state=isTrue);
组件工具
创建一个具有高斯模糊背景的组件
必选参数:
- widget: 组件对象
可选参数:
- sigmaX:X轴模糊半径,默认10
- sigmaY:Y轴模糊半径,默认10
Widget widget = convertToGaussBlurWidget(widget);
颜色工具
创建一个符合material规范的颜色
必选参数:
- color: 主题色对象
MaterialColor color = ColorUtil.createMaterialColor(color);
获得一个随机颜色
Color color = ColorUtil.getRandomColor();
获得主题对象
可选参数:
- isDark: 是否为夜间模式,false
// 获得夜间模式主题
ThemeData themeData = ColorUtil.getThemeData(isDark = true);
获得适配当前主题的指定色
必选参数:
- adaptColorType: 颜色类型
可选参数:
- reverse: 是否翻转颜色模式,默认为false
Color color = ColorUitl.getAdaptColor(AdaptColorType.ThemeColor, reverse = false)
Serialize
该部分为该工具类核心部分,该包部分工具基于该包的实现,该包提供了对于对象的序列化和反序列化操作
创建一个符合序列规则的类
该目标类应当继承EmptySerializable类,实现相关的抽象接口,如下所示:
考虑到每次实现较为复杂,此处提供了一个Windows应用,帮助快速生成该文件内容, 安装包为to_dart_bean.msix
class User extends EmptySerializable{
String? account;
String? password;
User();
User.create({
this.account,
this.password,
});
@override
User fromJson(Map<String,dynamic> json) => User.create(
account:SerializeUtil.asT<String>(json['account']),
password:SerializeUtil.asT<String>(json['password']),
);
@override
Map<String, dynamic> toJson() => <String, dynamic>{
'account':account,
'password':password,
};
@override
bool mapPair(Map<String, dynamic> json) => super.simpleMapPair(json, [
"account",
"password",
]);
}
SerializeUtil的使用
将对象转换为基础对象,也就是dart内置基本类型
必选参数:
- oldObj: 待转换的对象
List<String> basicObj = SerializeUtil.asBasic(obj);
将基础对象转换为自定义类对象
必选参数:
- object: 待转换的对象
- targetObj: 待转换目标类的示范对象
User user = SerializeUtil.asCustomized<User>(obj, User());
将对象转换为json字符串
必选参数:
- obj: 待序列化的对象
String? json = SerializeUtil.serialize(user);
将json字符串反序列化成目标对象
必选参数:
- obj: 待序列化的对象
- targetObj: 待转换目标类的示范对象
User user = SerializeUtil.deserialize<User>(json, User());
类型转换
必选参数:
- value: 待转换的对象
double? data = SerializeUtil.asT<double>("123.0");
Shared Preference的使用
对于
Shared Preference对象的初始化工作将会在第一个使用Shared Preference时完成
本工具基于同个包中的
SerializeUtil实现,因此当目标为自定义类时,应当符合序列化工具要求
放数据
必选参数:
- key: 键
- value: 值
SharedPreferenceUtil.put("key","value");
取数据
必选参数:
- key: 键
可选参数:
- targetObj: 值需要转换的类的一个范例对象
dynamic value = await SharedPreferenceUtil.get("key");
文件操作
本库提供了对于文件的便捷的操作方式,同时支持多个目录操作
简单使用
- 获得一个文件操作对象
必选参数:
- fileName: 文件名
可选参数:
- directoryType: 文件所在的目录,默认为应用的文档目录
Operator operator = await FileUtil.operate("aa.txt");
- 使用操作对象操作文件
- 二进制形式读文件内容
List<int> content = await operator.readFileAsBytes();
- 字符串形式读取文件内容
String content = await operator.readFileAsString();
- 读取文件内容并转化为目标对象
可选参数:
- targetObject: 目标类实例对象,默认为null
dynamic content = await opertor.readFileAsObject(User());
- 往文件写入二进制内容
必选参数:
- content: 字节内容
可选参数:
- needCover: 是否覆盖,默认为false
operator.writeFileBytes(content);
- 往文件写入字符串内容
必选参数:
- content: 字符串内容
可选参数:
- needCover: 是否覆盖,默认为false
operator.writeFileString(content);
- 往文件写入对象内容
必选参数:
- content: 对象内容
可选参数:
- needCover: 是否覆盖,默认为false
opertor.writeFileAsObject(user);
Isolate
本类提供了一个方便工具,能够帮助你方便地开启一个新的线程来运行对应的函数
- 声明一个函数 (该函数必须为静态函数或者为非类函数)
该函数的声明是被限制死的,必须为static FutureOr<dynamic> function(List<dynamic> parameter) async
被调用时,参数将会被打包成List传入
static FutureOr<dynamic> function(List<dynamic> parameter) async {
// 此处为函数内容
// ...
}
- 使用该工具将当前的函数在新线程中运行
该工具类采用建造者模式搭建,可以通过setParameter()方法添加参数,最后都会被打包到一个List中传入目标函数
dynamic result = await IsolateUtil.builder(function)
.setParameter(1)
.setParameter(2)
.run();
EventBus
简单使用
- 在
BusEventType.dart文件中定义需要的总线事件类型 - 创建一个总线事件对象
BusEvent busEvent = BusEvent(BusEventType.Default,data);
- 发送总线事件
必选参数:
- busEvent: 总线事件对象
EventBusUtil.send(busEvent);
- 设置监听总线事件
必选参数:
- busEventType: 监听的总线事件类型
- <void Function(BusEvent event)?> onData: 处理事件的函数
可选参数:
- <Function?> onError: 出现异常时的回调函数
- <void Function()?> onDone: 发送完成时的回调函数
- <bool?> cancelOnError: 出现异常时是否取消发送
EventBusUtil.listen(
BusEventType.Default,
onData = onDataFunction,
onError = onErrorFunction,
onDone = onDoneFuntion,
cancelOnError = false
);
硬件操作
Camera工具
能够方便地进行拍摄照片或录制视频
拍摄一张照片
必选参数:
- <void Function(XFile?) callback> callback: 拍摄完照片后的回调函数
可选参数:
- cameraDevice: 拍摄使用的镜头,默认为 CameraDevice.rear,
- <int?> imageQuality: 压缩后的照片质量,默认为null
CameraUtil.takePhoto(callback);
录制一段视频
必选参数:
- <void Function(XFile?) callback> callback: 录制后的回调函数
可选参数:
- cameraDevice: 拍摄使用的镜头,默认为 CameraDevice.rear,
- <int?> maxDuration: 最大录制时长,默认为null
CameraUtil.takeVideo(callback);
选取一张照片
必选参数:
- <void Function(XFile?) callback> callback: 选取照片后的回调函数
可选参数:
- <int?> imageQuality: 压缩后的照片质量,默认为null
CameraUtil.selectPhoto(callback);
选取多张照片
必选参数:
- <void Function(List) callback> callback: 选取照片后的回调函数
可选参数:
- <int?> imageQuality: 压缩后的照片质量,默认为null
CameraUtil.selectMultiPhoto(callback);
选取一段录像
必选参数:
- <void Function(XFile>) callback> callback: 选取录像后的回调函数
可选参数:
- <int?> maxDuration: 最大录像时长,默认为null
CameraUtil.selectVideo(callback);
HTTP的使用
该工具对Http工具进行了一定程度的封装,使其更加简洁易用
使用该包进行请求时,由于对响应做了封装操作,因此应当使得响应符合以下的格式
{
"code" : 200,
"script" : "这是一个成功请求",
"responseData" : {
//数据内容
}
}
该类编写的上层Api类应当编写在
lib/store/http/api/文件夹下
使用
- 在
resource/application.yaml中编写相关配置信息
http:
# 是否开启http功能
status: true
# 激活的环境
activeProfile: mock
# 匿名请求时的请求前缀,例如:http://100.10.10.10:3004/anony/...
anonymousPrefix: anony
# 认证成功后的请求前缀,例如:http://100.10.10.10:3004/user/...
identityPrefix: user
# mock环境配置
mock:
protocol: https
host: console-mock.apipost.cn
port: /app/mock/project/8deeb012-ac45-46b5-c0f1
# 本地环境配置
local:
protocol: http
host: 10.2.2.2
port: 10035
# 生产环境配置
development:
protocol: http
host: vaccum.ltd
port: 10035
- 编写一个类来进行请求
HttpClient中提供了很多的方法来进行请求,部分方法可以实现对于返回数据的反序列化
class UserApi {
// 这个请求的总前缀
static const String urlPrefix = "user";
static Future<User> login(User user) async {
// 拼接获得当前请求的uri
var uri = HttpClient.join(urlPrefix, "login");
// 获得HttpClient对象
HttpClient httpClient = Get.find<HttpClient>();
// 使用该请求发起请求
User resultUser = await httpClient.toPostAndDecode<User, User>(
uri: uri,
body: FormData({"username": user.username, "password": user.password}),
modelObj: User());
// 返回对象
return resultUser;
}
*3. 可以通过编写请求拦截器和响应拦截器在过程中进行操作
- 编写拦截器 以下为一个请求拦截器
class TokenInterceptor extends RequestInterceptor {
@override
FutureOr<Request> intercept(Request request) {
// 操作请求对象
return request;
}
}
以下为一个响应拦截器
class ErrorInterceptor extends ResponseInterceptor {
@override
FutureOr<Response> intercept(Request request, Response response) {
// 操作响应对象
return response;
}
}
- 将拦截器在初始化方法中添加
在/initializer/HttpInitializer.dart中创建HttpClient对象时传入
HttpClient httpClient = HttpClient.uriBuilder(
uri:instance.baseUrl,
requestInterceptorList:[TokenInterceptor()],
responseInterceptorList:[ErrorInterceptor()]);
WebSocket使用
本仓库对Websocket进行了一定程度的封装,方便用户进行使用,本工具代码侵入性较强,适合新建项目进行使用,同时搭配本人仓库SkyeJavaUtil使用,能够减少编写压力
该类编写的Api类应当
由于为了更好的能够使用该包,本库对于传入的包结构做了要求,具体详见WebSocketPackage这个工具类,以下只做简单阐述
<String?> id : 当前包的主键id
<String?> responseId : 响应包的主键id
content : 主要内容
<int?> time : 发送时间
<String?> loop : 大主题
<String?> subject : 小主题
<String?> webSocketPackageType : 包的类型
<Map<String , dynamic>?> additionalInfos : 附加信息
使用
- 在
resource/application.yaml中配置相关的信息
websocket:
# 是否开启websocket功能
status: true
# 请求的前缀
identityPrefix: socket
# 心跳的间隔时间,当前为15s
heartBeatPeriod: 15
# 激活的环境
activeProfile: development
# 本地环境的配置信息
local:
protocol: ws
host: 10.0.2.2
port: 10035
# 生产环境的配置信息
development:
protocol: ws
host: console-mock.apipost.cn
port: /app/mock/project/8deeb012-ac45-46b5-c0f1-e4cab750ddf0
- 编写一个
WebSocket的发送器
class TestWebSocketClientSender extends WebSocketClientSender{
String getLoop() => "TestLoop";
String getSubject() => "TestSubject";
lazy WebSocketClient webSocketClient;
@override
void bind(WebSocketClient webSocketClient){
// 会传入已经绑定的webSocketClient,相当于初始化方法
// 通常会用来保存WebSocketClient对象
this.webSocketClient=webSocketClient;
}
@override
void send(WebSocketPackage webSocketPackage){
// 编写具体的发送方法逻辑
// 最后需要使用绑定的WebSocketClient发送包
webSocketClient.send(webSocketPackage);
}
}
- 编写一个
WebSocket的接受器
class TestWebSocketClientSender extends WebSocketClientReceiver{
String getLoop() => "TestLoop";
String getSubject() => "TestSubject";
lazy WebSocketClient webSocketClient;
@override
void bind(WebSocketClient webSocketClient){
// 会传入已经绑定的webSocketClient,相当于初始化方法
// 通常会用来保存WebSocketClient对象
this.webSocketClient=webSocketClient;
}
@override
void receive(WebSocketPackage webSocketPackage){
// 编写接收到数据包的处理逻辑
}
}
- 注册上面编写的接收器和发送器
// 获得默认的WebSocketClient平台
WebSocketClient webSocketClient = Get.find<WebSocketClient>();
// 生成对应客户端
TestWebSocketClientSender testWebSocketClientSender = TestWebSocketClientSender();
TestWebSocketClientReceiver testWebSocketClientReceiver = TestWebSocketClientReceiver();
//进行注册
webSocketClient.register(testWebSocketClientSender);
webSocketClient.register(testWebSocketClientReceiver);
//发送数据包
testWebSocketClientSender.send(WebSocketPackage())
SQLite使用
本工具对Sqlite进行了封装,方便使用,同时考虑到存在多用户登录的情况,为了保证外键的统一,因此对于库表有部分约束
该类编写的上层Api类应当编写在
lib/store/sqlite/api/文件夹下
使用
- 在
resource/application.yaml中进行配置
sqlite:
# 是否开启sqlite功能
status: true
# 数据库名
databaseName: test_database
# 登录用户的标识字段
identitySign: loginUserId
# 标识字段的类型
identitySignType: TEXT
- 在
resource/sqlite_table.yaml中配置所有表信息
sqlite:
# 第一张为User表
- tableName: User
# 主键列为 userId
primaryColumn: userId
# 所有的列信息
columns:
# 第一个字段为userId
- name: userId
# 类型为 INTEGER
type: INTEGER
# 第二个字段为username
- name: username
# 类型为 Text
type: TEXT
# 第二张为 book表
- tableName: book
primaryColumn: id
# 是否需要插入登录用户的标识列
loginDifference: true
columns:
- name: id
type: TEXT
- 获得默认注入的
Database对象
CustomDatabase database = Get.find<CustomDatabaase>();
- 基本的CRUD 插入一条数据
必选参数:
- tableName: 表名
- obj: 需要插入的对象
可选参数:
- <ConflictAlgorithm?> conflictAlgorithm: 冲突策略,默认为null
int influenceRows = await database.insert("user",user);
根据id查找一条数据
必选参数:
- tableName: 表名
- id: 主键值
- targetObj: 目标类的示例对象
User user = await database.findOneById<User>("User","1",user);
查找登录用户的所有数据
必选参数:
- tableName: 表名
- <String?> loginUserId: 登录用户辨识列值
- targetObj: 目标类的示例对象
List<User> userList = await database.findAll<User>("User","skye",User());
更新一个用户
必选参数:
- tableName: 表名
- <String?> id: 更新记录的主键id值
- targetObj: 目标类的示例对象
int count = await database.updateOneById<User>("User","1",user);
判断记录是否存在
必选参数:
- tableName: 表名
- <String?> id: 记录的主键id值
bool isExist = await database.isExistById<User>("User","1");
删除一条记录
必选参数:
- tableName: 表名
- <String?> id: 更新记录的主键id值
int count = awaitdatabse.deleteOneById<User>("User", "1");
- 原生SQL操作 原生查询
必选参数:
- sql: sql语句
- <List<Object?>?> arguments: 参数值
List<Map<String, dynamica>> data = database.rawQuery(sql, ["1"]);
原生更新
必选参数:
- sql: sql语句
- <List<Object?>?> arguments: 参数值
int count = database.rawUpdate(sql, ["1", "aa"]);
原生插入
必选参数:
- sql: sql语句
- <List<Object?>?> arguments: 参数值
int count = database.rawInsert(sql, ["1", "aa"]);
原生删除
必选参数:
- sql: sql语句
- <List<Object?>?> arguments: 参数值
int count = database.rawDelete(sql, ["1", "aa"]);
Map_Struct
由于在编码过程中存在实体类分层问题,本仓库基于smart_struct进行修改,并且融入了其代码,帮助能够更快地生成转换类
此处感谢smotastic的库
具体的其他可用方法,参照smart_struct
如果想要对生成位置等进行修改,需要定制化build.yaml文件
简单使用
- 修改
build.yaml文件,将部分内容改成自己的包
builders:
mapper:
# set the buildr file which will be called
# 此处要改成自己的包名
import: "package:skye_utils/util/service/smart_struct/builder.dart"
# define the builder factories name
builder_factories: ["smartStructBuilder"]
# define the file extension reflection
build_extensions: { ".dart": [".g.dart"] }
# scope of the action
auto_apply: all_packages
# the created file store location
build_to: source
# the preceding builder
runs_before: ["injectable_generator|injectable_builder"]
# which file will be handle at last
required_inputs: [".g.dart"]
# define the target rule
targets:
# the default run rule
$default:
# the apply source directory
sources:
- lib/**
# the rule of the builder
builders:
# you should use the project name here
# 此处要改成自己的包名
skye_utils|mapper:
options:
# define the file where is created
build_extensions: { "lib/store/entity/map_struct/{{}}.dart": "lib/store/entity/map_struct/impl/{{}}.g.dart" }
- 编写对应的抽象接口
import '../../../util/service/smart_struct/annotations.dart';
import '../bo/user_bo.dart';
import '../dto/user_dto.dart';
part 'impl/user_mapper.g.dart';
@Mapper()
abstract class UserMapper {
@Mapping(source: "password", target: "password", isStraight: true)
UserBO? dto2bo(UserDTO userDTO, String? password);
UserDTO? bo2dto(UserBO userBO);
}
- 运行对应的命令
> dart run builde_runner build
- 可以发现在
lib/store/entity/map_struct/impl下已经生成了对应的转换类
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../user_mapper.dart';
// **************************************************************************
// MapperGenerator
// **************************************************************************
class UserMapperImpl extends UserMapper {
UserMapperImpl() : super();
@override
UserBO? dto2bo(
UserDTO userDTO,
String? password,
) {
final userbo = UserBO.create(
userDTO.username,
password,
);
return userbo;
}
@override
UserDTO? bo2dto(UserBO userBO) {
final userdto = UserDTO.create(userBO.username);
return userdto;
}
}
*依赖介绍
dart版本
2.18.5
flutter版本
3.3.9
生产依赖
get: ^4.6.5
flutter_screenutil: ^5.6.0
flutter_smart_dialog: ^4.7.1
responsive_builder: ^0.4.3
shared_preferences: ^2.0.15
uuid: ^3.0.7
date_format: ^2.0.7
path_provider: ^2.0.11
logger: ^1.1.0
event_bus: ^2.0.0
sqflite: ^2.2.2
permission_handler: ^10.2.0
image_picker: ^0.8.6
yaml: ^3.1.0
开发依赖
flutter_lints: ^2.0.1
build_runner: ^2.1.7
freezed: ^1.1.1
injectable_generator: ^1.5.3
test: ^1.20.1
source_gen_test: ^1.0.2
analyzer: ^3.2.0
build: ^2.2.1
code_builder: ^4.1.0
path: ^1.8.1
source_gen: ^1.2.1
freezed_annotation: ^1.1.0