flutter 基于get的模版项目(python脚本)

1,269 阅读13分钟

Git地址:flutter模板项目命令

搭配 VS Code 页面生成插件 效果更佳。

更新 24/06/19

先说抱歉,之前写文件生成的时候用的 Windows 办公,脚本选取上用了 bat,然而在 MacOS 上并不适用,所以现在重新梳理一下,选择使用了 python 来干这件事(ps:Windows我还没测试过,理论没啥问题)。

这次把模版文件做了区分,分为单页面的架子和tabs复合页面的架子(.yaml暂时没做修改,自己增删就行了)。

后续可能会把更多的基础功能加进模版中

  • 检测网络变化;
  • 页面状态处理;
  • ...

直接上图:

CleanShot 2024-06-19 at 10.36.00@2x.png

更新 24/04/02

原模版template_getx没有更新了,这里直接通过bat的生成项目进行迭代。

项目去掉了一些没啥用的文件,规整了项目结构,往更纯粹的模板走了一小步。

核心插件:
  • 集大成者:get,可以说是包罗万千了状态管理、路由、国际化、主题切换等等,用着还是蛮爽的,嘿嘿。 顺便吐槽下,作者好像很久没发版了,有点瑟瑟发抖...,在想要不要重新投入 riverpod 的怀抱;

  • 网络请求:dio + retrofit, 之前有个文章写到过有兴趣可以看看;

  • 刷新加载:easy_refresh + infinite_scroll_pagination,前者不用多说,后者是一个分页控制器,之前也写过,唯一不同就是分页控制的使用,反正合理选择吧;

  • 数据模型:freezed 也是注解操作,比较简单,就是文件太多之后就有点慢了,生成太多了...,推荐一个 json -> freezed 的工具网站;

大致就这样吧,其他pubspec.yaml 一些常用插件,没用的可以删掉;

部分插件阐述和个人理解:
  • 本地存储插件替换: hive 4.0 -> get_storage

    其实 hiveget_storage 使用都是十分简洁的,这里做替换的目的是减少额外插件的应用,hive 4.0 需要外应用插件 isar_flutter_libssp挺好,但内置方法基本都是异步操作,个人感觉用起来不方便,没有同步来得快,某些场景同步确实好用点(虽然没啥太大的区别)。

  • 引入 persistent_bottom_nav_bar_v2 创建项目根路径,与 get route 结合使用:

    persistent_bottom_nav_bar_v2 样式蛮多的,大多数需求应该都可以满足了。

    原来的 tabbar 是自己写的,多少还是整复杂了些,这两天过了一下 pub 的库,干脆就选了一个做了一下修改, persistent_bottom_nav_bar_v2 本身是基于 go_router 的,非常强大的库,最早写项目也是用的 provider / riverpod (注解模式是真的棒)go_router 这两黄金搭档。但后来入职公司同事们都用 get 大缸了,那没办法按部就班的干呗。

    这里说下赋值 GetPage 中的 binding 可以减少 controller 书写创建相关的代码,或者说 Bind.lazyPut(...) 后就不用特别去关心了,所以为了方便路由选择方面,也就使用了 get route 了,但是个人理解来讲根导航是真没get到作者的点,所以重写 tabbar 也是必经之路。

    get 5.0 中从作者的插件demo中可以了解到,bind (升级前是:binding)controller 两已然成为了不可分割的一个整体了,毕竟在 GetPage 属性 binding 继承于 abstract class BindingsInterface<dynamic>? ,一个抽象类型,没错必须自己创建并继承他,我们才能更 偷懒 规范的书写路由配置列表。是的 get 4.0 直接通过block赋值的操作没有了。

注:tabbar各个主页面的路由就不用写入 routes->app_pages.dart中了,直接在TabbarBinding 中进行注入。

class TabbarBinding extends Binding {
  @override
  List<Bind> dependencies() {
    return [
      Bind.lazyPut<TabbarController>(
        () => TabbarController(),
      ),
      // tabbar 分页懒加载binding
      ...HomeBinding().dependencies(),
      ...MessageBinding().dependencies(),
      ...MineBinding().dependencies(),
    ];
  }

部分贴图,没力码字了。

GIF 2024-4-2 16-15-26.gif79b5554632aea6d5fc34b51942aff0d.png
553b97055c139a38442cac848a0c68c.pngcd00c08c2f2fe47eb86caa74392a8e4.png

更新 23/09/13

文章中项目生成脚本同步升级。

原模版template_getx项目,使用get_cli生成页面文件后目录结构过于复杂,现在更新基于 get: ^5.0.0-release-candidate-5 的VSCode文件生成插件 vsc_getx_create 生成对应文件结构(view.dart、page.dart、controller.dart ...),更灵活也更快捷。

vsc_getx_create插件属于二次修改的VSCode插件,属于本地插件导入,详情可参见 README.md

具体结构如下图所示:

image.png 企业微信截图_16945700529194.png

企业微信截图_16945700696036.png

企业微信截图_16945700879559.png

企业微信截图_16945700958494.png

前言

对于flutter项目的配置从官方角度来说,其实已经够简单了。但是从实际业务出发,我们往往会多出一些公共的配置、插件、归纳甚至更多自定义的东西。这就对我们新起项目造成了不小的困扰:

  • 公共的文件迁移(复制到新项目后一堆警告与错误);
  • 公共插件的引入,在.yaml中补全插件;
  • 多文件的相互引用(import有时候会拼接项目名称,例如:import 'package:xxx/xxx.dart,或者相对路径层级不对);
  • 对新项目main.dart文件的修改(这个其实可以抽离实现主体,在main.dart文件中直接runApp(...),不做其他操作);
  • 基础图片资源的重复导入;
  • 或者其他;

上述问题相信看到这里的小伙伴多少有点感同身受吧。博主一直想写一个自用模板项目的脚本,但苦于对文件生成脚本生疏(主要还是太懒 ( ̄▽ ̄)"),一直没有实现这个伟大的抱负,直到遇见了她 # batch: flutter插件工程模版的创建,好嘛,该我()大()显()身()手()的时候到了!!!

正文

我们先抛开文件的创建,文件内容的填充或者整体文件夹的复制,这些实际脚本操作是如何实现的。优先梳理一下对于我们想要生成的最终产物,需要得到些什么需要做什么。

这里针对我自己的模板项目 template_getx 而言

  • 首先我们需要创建基础的项目结构flutter create xxx ...
  • 然后再往创建的结构中添加下列内容(添加顺序随意):
  1. 常用插件的引入;
  2. 项目模块(文件夹分类)的划分;
  3. 公共文件的引入;
  4. main.dart文件的修改;
  5. 基础资源Assets文件的引入;
  • 完成添加后执行相应的flutter命令;
  • 最后得到完整的项目

最终得到的产物是一个可直接运行,带tabbar的模板项目。

GIF 2023-6-25 18-04-25.gif

1、使用脚本的过程

1694571438971.jpg

2、生成的模板项目结构

下面开始具体说说batch的实现,因为不熟悉batch的所有命令,所以这里只对使用到的阐述一下( ( ̄▽ ̄)",其他使用可以谷歌、可以ChatGPT)。

1、脚本静态展示(LOGO+提示文本)


echo +---------------------------------------------------------------------------------+
call :showLogo
echo This script will guide you through creating a flutter project with specified 
echo dependencies and file directories.
echo.
echo +---------------------------------------------------------------------------------+

echo:可以为终端输出显示,后续也用到输出具体内容到目标文件

:showLogo:自定义的标签,具体实现是为了显示打开终端显示自定义的LOGO;

:showLogo
if not exist .outlogo (
echo CiAgX18gICAgICAgX19fX18gICAgIF9fX19fXyAgICAgIF9fX19fICAgIAogL1xfXCAgICAgKSBfX18gKCAgIC9fL1xfX19cICAgICkgX19fICggICAKKCAoICggICAgLyAvXF8vXCBcICApICkgX19fLyAgIC8gL1xfL1wgXCAgCiBcIFxfXCAgLyAvXy8gKF9cIFwvXy8gLyAgX19fIC8gL18vIChfXCBcIAogLyAvIC9fX1wgXCApXy8gLyAvXCBcIFxfL1xfX1xcIFwgKV8vIC8gLyAKKCAoX19fX18oXCBcL19cLyAvICApXykgIFwvIF8vIFwgXC9fXC8gLyAgCiBcL19fX19fLyApX19fX18oICAgXF9cX19fXy8gICAgKV9fX19fKCAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK>.logo
certutil -decode .logo .outlogo>nul
del .logo
)
type .outlogo
goto :eof

判断是否添加自定义的LOGO,如果没有则输出默认内容。

.outlogo:自己添加的LOGO内容的文件

goto :eof:继续执行后续脚本

2、提示输入项目名称

:inputProjectName
set /p projectName= Input project name:
if "%projectName%"=="" goto input
if "%projectName%"=="test" (
	call :error "'test' is not allowed as a project name, enter another name."
	goto inputProjectName
)

给定固定的提示语句,提示用户输入需要生成的flutter项目名称,如果不输入则重复提示输入。

goto inputProjectName:指定执行bat命令的标签(提示重复输入)

3、提示输入flutter项目的组织机构

:inputProjecOrg
set /p projectOrg= Input project organization (such as com.example), or press Entry to use default:
if "%projectOrg%"=="" (
    set "projectOrg=com.example"
)

定义变量projectOrg接收用户输入内容,如果不输入则使用默认的组织机构名称,set "projectOrg=com.example"为设置默认组织机构。

4、提示输入项目输出路径

:inputProject
set /p v= Input project path(such as D:\FlutterWorkspace\Porjects), or press Entry to use default:
if not "%v%"=="" call :changeDir %v%
set projectPath=%cd%\%projectName%
echo [INFO] Project path is: %projectPath%

提示输入项目输出路径,如果不输入则默认创建到create.bat脚本的同级目录下,建议测试命令是否正常输出可以不输入,正常项目还是有必要输入具体的项目路径的。

:changeDir:创建输入的项目路径,如果创建失败则返回重新输入。

5、执行flutter create

call :print "Start creating new flutter plugin project..."
echo flutter create --platforms=ios,android --org %projectOrg% --pub %projectName%>temp.bat
call temp.bat
if errorlevel 1 (
	echo [INFO] Your flutter version is too low please update.
	echo flutter create --org %projectOrg%  --pub %projectName%>temp.bat
	call temp.bat
)
del temp.bat

这里主要是创建基本的项目结构,方便后续修改为自己的项目模板。 flutter create --platforms=ios,android --org %projectOrg% --pub %projectName%该命令可以拼接其他的操作,输入需要用书输入则可以提供终端输入变量的模式。

6、插入模板项目的文件(夹)

:createFolders
call :print "Generate configuration files..."
  
xcopy "%scriptPath%\files" "%1\lib\" /E /I /Y

set "source_folder=%scriptPath%\assets"
xcopy "%source_folder%" "%projectPath%\assets" /S /I /Y /V >nul

goto :eof

%1:是标签:createFolders传递的变量%projectPath%具体值为flutter项目路径;

%scriptPath%:是当前脚本所在的目录路径;

xcopy "%scriptPath%\files" "%1\lib\" /E /I /Y:复制当前脚本同级文件夹files下的所有内容至,flutter项目路径lib下;

xcopy "%source_folder%" "%projectPath%\assets" /S /I /Y /V >nul:复制静态资源至项目路径;

  • /E:复制包括子文件夹和空文件夹在内的所有文件和文件夹;
  • /I:如果目标目录不存在,则会自动创建目标文件夹;
  • /Y:确认所有覆盖操作,即在目标文件夹中存在同名文件时自动覆盖;
  • /S 参数表示递归复制子文件夹中的文件;
  • /V参数用于显示详细的复制操作日志;

7、.yaml文件中添加常用插件

@REM 添加设置依赖
:addFlutterDependency
call :print "Insert dependency..."

set pubspec=%1\pubspec.yaml

REM 读取 pubspec.yaml 文件内容
for /f "eol== delims=" %%a in (%pubspec%) do (
    set "line=%%a"
    setlocal enabledelayedexpansion

	REM 将当前行写入临时文件
	echo !line!>> %pubspec%.tmp

    REM 查找 cupertino_icons 行
	echo !line! | findstr /i /c:"cupertino_icons:" >nul
	if !errorlevel! equ 0 (
		REM 在 cupertino_icons 行之后插入新的依赖项
		@REM echo !line!>> %pubspec%.tmp
		echo   flutter_localizations:>> %pubspec%.tmp
		echo     sdk: flutter>> %pubspec%.tmp
		echo   get: ^^5.0.0-release-candidate-4>> %pubspec%.tmp
		echo   json_annotation: ^^4.8.1>> %pubspec%.tmp
		echo   freezed_annotation: ^^2.2.0>> %pubspec%.tmp
		echo   flutter_hooks: ^^0.18.6>> %pubspec%.tmp
		echo   hive_flutter: ^^1.1.0>> %pubspec%.tmp
		echo   bot_toast: ^^4.0.3>> %pubspec%.tmp
		echo   easy_refresh: ^^3.0.5>> %pubspec%.tmp
		echo   dio: ^^5.0.2>> %pubspec%.tmp
		echo   retrofit: ^^4.0.1>> %pubspec%.tmp
		echo   flutter_spinkit: ^^5.1.0>> %pubspec%.tmp
		echo   simple_animations: ^^5.0.0+3>> %pubspec%.tmp
		echo   cached_network_image: ^^3.2.2>> %pubspec%.tmp
		echo   event_bus: ^^2.0.0>> %pubspec%.tmp
		echo   logger: ^^1.2.2>> %pubspec%.tmp
		echo   star_menu: ^^3.1.4>> %pubspec%.tmp
		echo   # 启动图: flutter pub run flutter_native_splash:create>> %pubspec%.tmp
		echo   # flutter_native_splash: ^^2.3.0>> %pubspec%.tmp
	) 

	REM 查找 flutter_lints 行
	echo !line! | findstr /i /c:"flutter_lints:" >nul
	if !errorlevel! equ 0 (
		REM 在 flutter_lints 行之后插入新的依赖项
		@REM echo !line!>> %pubspec%.tmp
		echo   build_runner: ^^2.3.3>> %pubspec%.tmp 
		echo   flutter_gen_runner: ^^5.2.0>> %pubspec%.tmp 
		echo   json_serializable: ^^6.7.0>> %pubspec%.tmp 
		echo   freezed: ^^2.3.5>> %pubspec%.tmp 
		echo   retrofit_generator: ^^6.0.0+1>> %pubspec%.tmp 
		echo   # 一键生成启动图标: flutter pub run flutter_launcher_icons>> %pubspec%.tmp 
		echo   # flutter_launcher_icons: ^^0.13.1>> %pubspec%.tmp 
	) 
	
	REM 查找 assets 行
	echo !line! | findstr /i /c:"uses-material-design:" >nul
	if !errorlevel! equ 0 (
		REM 在 uses-material-design 行之后插入新的依赖项
		echo   assets:>> %pubspec%.tmp 
		echo     - assets/images/>> %pubspec%.tmp 
	) 

	endlocal
)

REM 在文件末尾插入自定义内容
echo.>> %pubspec%.tmp
echo flutter_gen:>> %pubspec%.tmp
echo   output: lib/support_files/>> %pubspec%.tmp
echo   line_length: 80>> %pubspec%.tmp

REM 将临时文件替换回原始文件
move /y %pubspec%.tmp %pubspec% >nul

goto :eof

-for /f "eol== delims=" %%a in (%pubspec%) do :循环遍历.yaml文件每一行内容,判断是否有符合条件的行,并在该行后插入需要添加的插件。文末内容的添加直接添加至循环以外就可以了。

setlocal enabledelayedexpansion:设置本地为延迟扩展。 在cmd执行命令前会对脚本进行预处理,其中有一个过程是变量识别过程,在这个过程中,如果有两个%括起来的如%value%类似这样的变量,就会对其进行识别,并且查找这个变量对应的值,再而将值替换掉这个变量,这个替换值的过程,就叫做变量扩展,然后再执行命令。

echo ... >> %pubspec%.tmp :将内容写入到临时文件,结束所有操作后替换掉项目原有的pubspec.yaml

echo !line! | findstr /i /c:"cupertino_icons:" >nul:执行输出当前行!line!中是否包含cupertino_icons:,如果成功执行则后续判断表示满足我们想要插入的内容的行,否则不插入自定义内容,具体内容按规划插入就可以了。后续的几个判断都是类似的处理方式。

!errorlevel!:为前一句语句的执行状态,0表示执行成功;1表示执行失败。

move /y %pubspec%.tmp %pubspec% >nu:将临时文件替换掉我们原有的项目文件,完成插件插值。

8、执行flutter命令

:flutterCLI
call :print "Run flutter CLI..."

REM 进入指定文件夹
cd /d "%projectPath%"

REM 运行命令

echo flutter pub get>temp.bat
call temp.bat
del temp.bat

echo flutter pub run build_runner build>temp.bat
call temp.bat
del temp.bat

REM 返回到原始目录
cd /d "%~dp0"
exit /b
goto :eof
 

VS Code编辑器下正常来说,我们完成了步骤7编辑器会自动更新pubspec.yaml文件,更新我们的插件管理文件。

但是在这里我的pubspec.yaml文件中包含build_runner的编译内容(retrofit_generatorfreezed等),所以需要额外执行一次flutter pub run build_runner build。由于让编辑器自动更新插件我们无法把握pub get完成的时机,为避免dart命令执行的冲突,这里我直接执行插件更新,然后执行build_runner.

cd /d "%projectPath%":进入到项目路径,cd /d "%~dp0":返回bat脚本路径。

echo flutter pub get>temp.bat:将执行命令写入临时文件temp.batcall temp.bat:执行脚本内容,del temp.bat:执行完毕后移除临时文件。

exit /b:当脚本运行到“exit /b”行时,不会执行此行之后的命令,并且调用当前脚本后的命令将继续执行。

到这里整个执行流程已经完成了。

总结

batch属于Windows下的批量执行命令,在文件操作方面感觉还是挺简单的,前提还是得对它有基本了解,迎()难()而()上,还是蛮累的...( ̄- ̄)"。

  • 模板项目添加的文件内容,全是.dart格式(方便直接读写)打开会有编译错误,但不影响使用。后续可能会对这部分内容进行整改。之前试过使用.txt格式存档文件内容,但是在进行批量复制的时候没办法把文件修改成.dart格式(总是有问题( ̄▽ ̄)"),后面整改的时候再处理吧,哈哈。

  • 后续可能会对 template_getx 项目的使用进行简单的介绍和梳理。

使用ChatGPT附图: 企业微信截图_16877458436465.png

bat使用推荐:BAT 批处理 常用命令 [MD]

模板项目产出灵感:flutter插件工程模版的创建