前言:架构模式、框架、设计模式的概念
iOS—架构模式、框架、设计模式的理解
架构模式:架构模式的出现是为了管理复杂的应用程序,这样可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。我们经常说的MVC架构、MVVM架构属于此类。
框架:这个最好理解了,通常是代码重用。框架与设计模式的概念容易弄混,两者有相似之处,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述规范,它比框架更抽象;框架为已经解决问题的具体实现方法,能直接执行或复用;设计模式是比框架更小的元素,一个框架中往往含有一种或多种设计模式。Xcode自带的Foundation、UIKit,以及我们经常使用的AFNetworking,MJExtension,SVProgressHUD就属于这一类。
设计模式:设计模式可以通俗的理解为实现/解决某些问题,而形成的解决方案规范。增加代码的可重用性,让代码能更容易理解和可靠。我们通常说所的代理模式、迭代器模式、策略模式就属于这一类。对各种设计模式的了解可以帮助我们更快的解决编程过程中遇到的问题。
三者关系:架构(动词)>框架>设计模式。
软件通过架构,可以设计出很多不同的框架。在一个框架中,也可以使用很多的设计模式。设计模式不是哪儿哪儿都可以用的,只有当出现了某一特定的问题时,才利用设计模式去解决。设计模式不是用的越多越好,在维护的时候,过多的设计模式会极大的增添维护成本。
一、架构模式
1、架构模式的演变
1.1、MVC
1、架构的设计其实是为了更好的维护和迭代,而不是只考虑眼前当下的开发。
2、最基本的架构是MVC,试想下如果我一个应用的所有功能都是像”关于“功能的,那我还需要其他架构干嘛?显然MVC就已经很足够,而且还显得不冗余(这里指的是设计或者粒度不冗余)。
3、其他的架构都是从MVC演变而来。再讲其他架构的演变之前,我们先明确最原始的MVC代码是如何的。
①、首先M主要负责数据、V主要负责视图、C主要负责数据的视图显示。而这里的M是原始的瘦Model。
所以,我们拿常见的”我的”页面来举例,部分原始的MVC代码一般为如下样子:
1 2 3 4 5 6 7 8 9
| UserModel
View
ViewController self.userInfoView.name = user.name; self.userInfoView.sexString = user.sex == 1? "女" :"男";
|
4、在MVC+瘦Model的演变下,还有MVC+胖Model
胖Model就是瘦Model+部分弱业务逻辑(这些弱业务重复一般都是经常出现,或者说是要求可复用性的,如根据枚举获取性别字符串)。它使得Controller可以从胖Model这里拿到数据之后,不用额外做操作或者只要做非常少的操作,就能够将数据直接应用在View上.
1 2 3 4 5 6 7 8 9
| UserModel + (NSString *)sexStringFrom:(int)sex;
View
ViewController self.userInfoView.name = user.name; self.userInfoView.sexString = [UserModel sexStringFrom:user.sex];
|
1.2、MVP?
5、有时候在MVC+瘦Model的演变下,不是转成MVC+胖Model,而是MVC+瘦Model+Helper
其实这个思路已经很接近MVP了、但是还差提点。MVP还需要为View提供数据
1 2 3 4 5 6 7 8 9 10
| UserModel
View
UserHelper + (NSString *)sexStringFrom:(int)sex;
ViewController self.userInfoView.name = user.name; self.userInfoView.sexString = [UserHelper sexStringFrom:user.sex];
|
1.3、MVVM
6、关于MVC+瘦Model+Helper,还可以改为MVC+瘦Model+ViewModel
刚才的胖Model只从Controller移植走了一些简单的弱业务。
而ViewModel则干脆把数据的处理全部从Controller移植了出去。
1 2 3 4 5 6 7 8 9 10 11 12 13
| UserModel
View
UserViewModel name sexString - (id)initWithName:(NSString *)name sex:(int)sex;
ViewController self.userInfoView.name = userViewModel.name; self.userInfoView.sexString = userViewModel.sexString;
|
1.4、MVCS -> MVVM+S
拿有数据操作的”购物车“页面来说,
假设其除了有网络数据请求外,还有本地数据库处理。(附:购物车是否需要本地数据库,个人认为是基于服务端的压力来考虑,不然一般是放在服务端合适点。压力设想如下,千万级用户,购物车加减商品频繁,假设放在后台,则操作和计算也就频繁,压力也就大了。如果放在前端,则后台只需要负责是否可加减商品的检验,而不用再建购物车数据表和计算价格等,压力就小了。)
每个页面一般都会有网络请求,这些网络请求最原始的时候,是放在ViewController,也就是MVC的C中。
为了避免MVC中的ViewController后期变得十分臃肿。我们肯定要在MVC的基础上额外增加一层来处理这个。
综合考虑后,我们选用MVCS来处理。
其中S代表着Store,且我们这里的S代表着是整个模块的S,而不是每个页面都有一个S。其下层又包含着Storage和Service,即 数据库DB部分 和 网络Network部分 。
Store类名,个人习惯是使用Manager来命令。如UserManager。

所以,最终我们选用的是 MVCS+MVVM 或者说 MVVM+S。
S层(service 层)提供一种和外界(比如远程服务 API 或文件系统)交互的独立机制。
MVVM+S 纵向的数据流就不用多说,横向的数据流,我们采用自定义的类系统通知。区别在于它有着系统Notification的一对多方便,又有着delegate的接口对接方便。

抛开数据共享问题(如每个请求都要带userToken),每个页面
有一个iOS的app的购物车功能,添加的商品会放到购物车中,可以在购物车中对该商品进行数量变更,变更后会重新计算价格。购物车可添加多种商品计算,请问这个计算应该是请求接口让后台计算,还是后台提供每个商品的单价(和折扣),然后前端计算?
购物车的价格计算方式选择 前端计算 还是 后端计算,取决于业务需求和系统设计,以下是两种方案的分析:
✅ 方案 1:前端计算(客户端计算总价)
方式:
• 后端提供每个商品的单价、折扣、活动信息等数据。
• 客户端在 数量变更 时,直接 本地计算 商品总价(单价 * 数量),无需请求后端。
适用场景:
✅ 前端交互体验要求高(如希望用户调整数量后,立即看到价格变更,无需等待网络请求)。
✅ 价格计算逻辑简单(单价 * 数量,没有复杂促销规则)。
✅ 减少服务器压力(减少频繁的请求)。
缺点:
❌ 价格可能不准确,如果 单价变更、促销活动 发生变化,用户的本地价格可能与后端不同。
❌ 容易被篡改,黑客可以修改前端逻辑,伪造价格(需要后端校验最终订单金额)。
✅ 方案 2:后端计算(每次变更数量都请求接口)
方式:
• 客户端每次数量变更时,向后端发送请求,后端返回最新的价格(包括折扣、活动计算)。
适用场景:
✅ 涉及复杂促销计算(如满减、阶梯折扣、优惠券等)。
✅ 商品价格变化频繁(避免用户本地计算价格不一致)。
✅ 安全要求高(防止价格被篡改,确保支付金额正确)。
缺点:
❌ 用户体验下降(每次调整数量都要请求后端,可能会有延迟)。
❌ 服务器压力增加(每次改数量都要请求后端)。
🚀 最优解:前端 + 后端结合
建议方案:前端预计算 + 后端校验
• 前端 先本地计算实时显示价格,让用户调整数量时立即看到变化(提升体验)。
• 提交订单时,后端最终计算总价,避免前端被篡改价格,确保安全。
• 定期刷新(比如每次进入购物车页面时请求一次后端最新价格),防止前端数据过期。
示例流程:
1. 用户点击 + / - 修改商品数量时,前端本地计算价格,界面立即更新。
2. 后台定期提供 最新单价、促销信息,前端数据保持同步。
3. 下单时,后端再次计算总价,如果价格被修改过(例如后台有最新优惠),前端更新价格,并提醒用户。
🎯 总结
| 方案 |
优势 |
劣势 |
适用场景 |
| 前端计算 |
快速、减少网络请求 |
价格可能不准确、安全性较低 |
简单购物车、价格变动少 |
| 后端计算 |
确保价格准确、安全性高 |
影响体验、增加服务器压力 |
复杂促销、多变商品价格 |
| 前端 + 后端结合(推荐) |
体验流畅,保证安全 |
需做好数据同步策略 |
需要兼顾体验和准确性 |
👉 最佳方案是 “前端计算 + 后端最终校验”,这样既保证了用户体验,又确保了价格的正确性!🚀
二、架构分层(Architectural Layering)
架构分层是一种将系统分解为多个逻辑层次的方法,每一层都有特定的职责和功能。
- 架构分层有助于实现关注点分离(Separation of Concerns),使得系统的不同部分可以独立开发和维护。
- 典型的分层包括表示层(或用户界面层)、业务逻辑层、数据访问层等。
图片来源于 《架构分层.graffle》中的【一、架构分层】
其他图片见我的项目 CJStandardProject 中的 Screenshots
其他参考文章
iOS:
三、常见的项目目录结构
常见的项目目录结构:
项目目录结构规范说明 请点击本链接跳转下文附录进行查看
完整的 项目目录结构树 请点击链接,跳转到本问附文中查看。
四、页面与服务类设计
1、核心理念
页面执行自己的动作,调用Service服务类。无需关心数据请求、数据请求结束后是否需要缓存等等。
Service服务中心,内部包含请求和可能的数据存储等处理,不对外暴露。
2、设计举例
页面调用服务类举例
2.1、设计
图片来源于 《架构分层.graffle》中的【二、页面与服务类设计】
2.2、服务类中的代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class UserService { static login_normal(String mobile, String smsCode) { return UserRequest.login_normal( mobile: mobile, smsCode: smsCode, completeBlock: (UserModel userModel) { UserInfoManager().loginSuccessWithUserModel(userModel); }, ); } }
class UserRequest { static login_normal({ String mobile, String smsCode, void Function(UserModel userModel) completeBlock, }) { return AppNetworkKit.post( UrlPath.doLogin, params: { "mobile": mobile, "smsCode": smsCode, "grantType": "sms_code", }, ).then((ResponseModel responseModel) { if (responseModel.isSuccess) { User_manager_bean baseUserModel; if (responseModel.result != null) { baseUserModel = UserModel.fromJson(responseModel.result); } else { baseUserModel = null; } completeBlock(baseUserModel); } else { completeBlock(null); } }); } }
|
附一:项目目录结构规范说明
一个完整的项目目录结构一定至少包含有以下几个方面。
附:完整的 项目目录结构树 请点击链接,跳转到本问附文中查看。
1、程序入口
2、依赖库package
1 2 3 4 5
| ├─ package │ ├─ network │ └─ route │ ├─ errors │ └─ manager
|
项目依赖库,统一存放在package下。
3、资源文件assets
1 2 3 4 5 6 7 8 9
| ├─ assets │ ├─ fonts │ ├─ images │ │ ├─ base │ │ ├─ order │ │ └─ user │ └─ json │ ├─ config │ └─ mock
|
资源文件:统一存放在assets下。区分字体fonts、图片images、json(eg城市配置信息)
4、公共组件common
1 2 3 4 5 6 7 8 9 10
| ├─ lib │ ├─ common │ │ ├─ extensions │ │ │ └─ num_extension.dart │ │ ├─ styles │ │ │ └─ colors.dart │ │ │ └─ typography.dart │ │ └─ widgets │ │ ├─ common_button.dart │ │ └─ common_text.dart
|
common/:包含通用的小部件、样式和颜色等。
——-widgets:包含通用的小部件,例如按钮、文本、图标等。
——-styles: 包含通用的颜色和字体等。例如,colors.dart 文件中可以定义一些通用的颜色常量,typography.dart 文件中可以定义一些通用的字体样式(RegularTextStyle、BoldTextStyle、MediumTextStyle、DDINPROBoldTextStyle)。
——-extensions:系统类的扩展方法(eg: 20.w_pt_bj)
5、通用工具util
1 2
| │ └─ util │ └─ textsize_util.dart
|
utils/:包含一些通用的工具函数或类,例如日期格式化、字符串处理、数学计算等。
6、数据模型models
1 2 3 4 5 6 7 8 9 10 11 12
| │ ├─ model │ │ ├─ global_config │ │ │ ├─ app_config_model.dart │ │ │ ├─ game_config_model.dart │ │ │ ├─ global_config_model.dart │ │ │ └─ web_config_model.dart │ │ ├─ order │ │ │ ├─ order_base_model.dart │ │ │ └─ order_detail_model.dart │ │ └─ user │ │ ├─ user_base_model.dart │ │ └─ user_detail_model.dart
|
models/:包含应用程序的数据模型,例如用户、订单等。
7、服务类service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| │ ├─ service │ │ ├─ global_config │ │ │ ├─ manager │ │ │ │ └─ global_config_service.dart │ │ │ ├─ request │ │ │ │ └─ global_config_request.dart │ │ │ └─ cache │ │ │ └─ global_config_cache.dart │ │ └─ user │ │ ├─ manager │ │ │ └─ user_service.dart │ │ ├─ request │ │ │ └─ user_info_request.dart │ │ └─ cache │ │ └─ user_info_cache.dart
|
services/:包含应用程序的服务类或者管理中心,例如用户信息中心、配置信息中心等。
——-manager: 管理中心
——-request: 管理中心会需要的请求功能
——-cache: 管理中心可能需要的存储功能
8、模块功能module
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| │ ├─ module │ │ ├─ auth │ │ │ ├─ pages │ │ │ │ ├─ login_page │ │ │ │ │ └─ login_page.dart │ │ │ │ └─ register_page │ │ │ │ └─ register_page.dart │ │ │ ├─ routes │ │ │ │ ├─ auth_route_handel.dart │ │ │ │ ├─ auth_route_interceptor.dart │ │ │ │ └─ auth_route_name.dart │ │ │ └─ widgets │ │ │ ├─ code_input_widget.dart │ │ │ ├─ name_input_widget.dart │ │ │ └─ tel_input_widget.dart
|
modules/:包含应用程序的不同模块,例如身份验证、主页和个人资料等。
——-page: 页面
——-routes: 路由
——-widgets: 视图部件
附1、项目目录结构树
项目目录结构(以Flutter为例).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
| std_demo ├─ .gitignore ├─ .metadata ├─ README.md ├─ analysis_options.yaml ├─ android │ ├─ .gitignore │ ├─ .gradle │ │ ├─ 7.5 │ │ │ ├─ checksums │ │ │ │ └─ checksums.lock │ │ │ ├─ dependencies-accessors │ │ │ │ ├─ dependencies-accessors.lock │ │ │ │ └─ gc.properties │ │ │ ├─ executionHistory │ │ │ │ └─ executionHistory.lock │ │ │ ├─ fileChanges │ │ │ │ └─ last-build.bin │ │ │ ├─ fileHashes │ │ │ │ └─ fileHashes.lock │ │ │ ├─ gc.properties │ │ │ └─ vcsMetadata │ │ ├─ buildOutputCleanup │ │ │ ├─ buildOutputCleanup.lock │ │ │ └─ cache.properties │ │ └─ vcs-1 │ │ └─ gc.properties │ ├─ app │ │ ├─ build.gradle │ │ └─ src │ │ ├─ debug │ │ │ └─ AndroidManifest.xml │ │ ├─ main │ │ │ ├─ AndroidManifest.xml │ │ │ ├─ java │ │ │ │ └─ io │ │ │ │ └─ flutter │ │ │ │ └─ plugins │ │ │ │ └─ GeneratedPluginRegistrant.java │ │ │ ├─ kotlin │ │ │ │ └─ com │ │ │ │ └─ example │ │ │ │ └─ std_demo1 │ │ │ │ └─ MainActivity.kt │ │ │ └─ res │ │ │ ├─ drawable │ │ │ │ └─ launch_background.xml │ │ │ ├─ drawable-v21 │ │ │ │ └─ launch_background.xml │ │ │ ├─ mipmap-hdpi │ │ │ │ └─ ic_launcher.png │ │ │ ├─ mipmap-mdpi │ │ │ │ └─ ic_launcher.png │ │ │ ├─ mipmap-xhdpi │ │ │ │ └─ ic_launcher.png │ │ │ ├─ mipmap-xxhdpi │ │ │ │ └─ ic_launcher.png │ │ │ ├─ mipmap-xxxhdpi │ │ │ │ └─ ic_launcher.png │ │ │ ├─ values │ │ │ │ └─ styles.xml │ │ │ └─ values-night │ │ │ └─ styles.xml │ │ └─ profile │ │ └─ AndroidManifest.xml │ ├─ build.gradle │ ├─ gradle │ │ └─ wrapper │ │ ├─ gradle-wrapper.jar │ │ └─ gradle-wrapper.properties │ ├─ gradle.properties │ ├─ gradlew │ ├─ gradlew.bat │ ├─ local.properties │ └─ settings.gradle ├─ assets │ ├─ fonts │ ├─ images │ │ ├─ base │ │ ├─ order │ │ └─ user │ └─ json │ ├─ config │ └─ mock ├─ ios │ ├─ .gitignore │ ├─ Flutter │ │ ├─ AppFrameworkInfo.plist │ │ ├─ Debug.xcconfig │ │ ├─ Generated.xcconfig │ │ ├─ Release.xcconfig │ │ └─ flutter_export_environment.sh │ ├─ Runner │ │ ├─ AppDelegate.swift │ │ ├─ Assets.xcassets │ │ │ ├─ AppIcon.appiconset │ │ │ │ ├─ Contents.json │ │ │ │ ├─ Icon-App-1024x1024@1x.png │ │ │ │ ├─ Icon-App-20x20@1x.png │ │ │ │ ├─ Icon-App-20x20@2x.png │ │ │ │ ├─ Icon-App-20x20@3x.png │ │ │ │ ├─ Icon-App-29x29@1x.png │ │ │ │ ├─ Icon-App-29x29@2x.png │ │ │ │ ├─ Icon-App-29x29@3x.png │ │ │ │ ├─ Icon-App-40x40@1x.png │ │ │ │ ├─ Icon-App-40x40@2x.png │ │ │ │ ├─ Icon-App-40x40@3x.png │ │ │ │ ├─ Icon-App-60x60@2x.png │ │ │ │ ├─ Icon-App-60x60@3x.png │ │ │ │ ├─ Icon-App-76x76@1x.png │ │ │ │ ├─ Icon-App-76x76@2x.png │ │ │ │ └─ Icon-App-83.5x83.5@2x.png │ │ │ └─ LaunchImage.imageset │ │ │ ├─ Contents.json │ │ │ ├─ LaunchImage.png │ │ │ ├─ LaunchImage@2x.png │ │ │ ├─ LaunchImage@3x.png │ │ │ └─ README.md │ │ ├─ Base.lproj │ │ │ ├─ LaunchScreen.storyboard │ │ │ └─ Main.storyboard │ │ ├─ GeneratedPluginRegistrant.h │ │ ├─ GeneratedPluginRegistrant.m │ │ ├─ Info.plist │ │ └─ Runner-Bridging-Header.h │ ├─ Runner.xcodeproj │ │ ├─ project.pbxproj │ │ ├─ project.xcworkspace │ │ │ ├─ contents.xcworkspacedata │ │ │ └─ xcshareddata │ │ │ ├─ IDEWorkspaceChecks.plist │ │ │ └─ WorkspaceSettings.xcsettings │ │ └─ xcshareddata │ │ └─ xcschemes │ │ └─ Runner.xcscheme │ └─ Runner.xcworkspace │ ├─ contents.xcworkspacedata │ └─ xcshareddata │ ├─ IDEWorkspaceChecks.plist │ └─ WorkspaceSettings.xcsettings ├─ lib │ ├─ common │ │ ├─ extensions │ │ │ └─ num_extension.dart │ │ ├─ styles │ │ │ ├─ colors.dart │ │ │ └─ typography.dart │ │ └─ widgets │ │ ├─ common_button.dart │ │ └─ common_text.dart │ ├─ main.dart │ ├─ model │ │ ├─ evaluate │ │ │ └─ evaluate_model.dart │ │ ├─ global_config │ │ │ ├─ app_config_model.dart │ │ │ ├─ game_config_model.dart │ │ │ ├─ global_config_model.dart │ │ │ └─ web_config_model.dart │ │ ├─ goods │ │ │ ├─ goods_base_model.dart │ │ │ └─ goods_detail_model.dart │ │ ├─ order │ │ │ ├─ order_base_model.dart │ │ │ └─ order_detail_model.dart │ │ ├─ user │ │ │ ├─ user_base_model.dart │ │ │ └─ user_detail_model.dart │ │ └─ wish │ │ ├─ wish_base_model.dart │ │ └─ wish_detail_model.dart │ ├─ module │ │ ├─ auth │ │ │ ├─ pages │ │ │ │ ├─ login_page │ │ │ │ │ └─ login_page.dart │ │ │ │ └─ register_page │ │ │ │ └─ register_page.dart │ │ │ ├─ routes │ │ │ │ ├─ auth_route_handel.dart │ │ │ │ ├─ auth_route_interceptor.dart │ │ │ │ └─ auth_route_name.dart │ │ │ └─ widgets │ │ │ ├─ code_input_widget.dart │ │ │ ├─ name_input_widget.dart │ │ │ └─ tel_input_widget.dart │ │ ├─ game │ │ │ ├─ routes │ │ │ │ ├─ game_route_handle.dart │ │ │ │ ├─ game_route_interceptor.dart │ │ │ │ └─ game_route_name.dart │ │ │ └─ widgets │ │ ├─ mall │ │ │ ├─ pages │ │ │ │ └─ mall_home_page │ │ │ │ └─ mall_home_page.dart │ │ │ ├─ routes │ │ │ │ └─ mall_route_handle.dart │ │ │ └─ widgets │ │ ├─ order │ │ │ ├─ pages │ │ │ ├─ routes │ │ │ └─ widgets │ │ ├─ profile │ │ │ ├─ pages │ │ │ │ └─ profile_page │ │ │ │ └─ profile_page.dart │ │ │ └─ widgets │ │ │ └─ profile_avatar.dart │ │ ├─ web │ │ │ └─ routes │ │ │ ├─ web_route_handel.dart │ │ │ ├─ web_route_interceptor.dart │ │ │ └─ web_route_name.dart │ │ └─ wish │ │ ├─ pages │ │ │ ├─ wish_create_add_sku_page │ │ │ │ └─ wish_create_add_sku_page.dart │ │ │ ├─ wish_create_page │ │ │ │ └─ wish_ceate_page.dart │ │ │ ├─ wish_detail_dark_page │ │ │ │ └─ wish_detail_dark_page.dart │ │ │ ├─ wish_detail_light_page │ │ │ │ └─ wish_detail_light_page.dart │ │ │ ├─ wish_goods_control_page │ │ │ │ └─ wish_goods_control_page.dart │ │ │ └─ wish_home_page │ │ │ └─ wish_home_page.dart │ │ └─ widgets │ │ ├─ wish_create_add_sku_widget1.dart │ │ └─ wish_create_add_sku_widget2.dart │ ├─ service │ │ ├─ global_config │ │ │ ├─ cache │ │ │ │ └─ global_config_cache.dart │ │ │ ├─ manger │ │ │ │ └─ global_config_service.dart │ │ │ └─ request │ │ │ └─ global_config_request.dart │ │ ├─ order │ │ │ ├─ cache │ │ │ │ └─ order_cache.dart │ │ │ ├─ manager │ │ │ │ └─ order_service.dart │ │ │ └─ request │ │ │ └─ order_request.dart │ │ ├─ publish │ │ │ ├─ cache │ │ │ │ └─ publish_cache.dart │ │ │ ├─ manager │ │ │ │ └─ publish_service.dart │ │ │ └─ request │ │ │ └─ publish_request.dart │ │ └─ user │ │ ├─ cache │ │ │ └─ user_info_cache.dart │ │ ├─ manager │ │ │ └─ user_service.dart │ │ └─ request │ │ └─ user_info_request.dart │ └─ util │ └─ textsize_util.dart ├─ linux │ ├─ .gitignore │ ├─ CMakeLists.txt │ ├─ flutter │ │ ├─ CMakeLists.txt │ │ ├─ generated_plugin_registrant.cc │ │ ├─ generated_plugin_registrant.h │ │ └─ generated_plugins.cmake │ ├─ interceptors │ │ ├─ game_interceptor.dart │ │ └─ login_interceptor.dart │ ├─ main.cc │ ├─ my_application.cc │ └─ my_application.h ├─ macos │ ├─ .gitignore │ ├─ Flutter │ │ ├─ Flutter-Debug.xcconfig │ │ ├─ Flutter-Release.xcconfig │ │ ├─ GeneratedPluginRegistrant.swift │ │ └─ ephemeral │ │ ├─ Flutter-Generated.xcconfig │ │ └─ flutter_export_environment.sh │ ├─ Runner │ │ ├─ AppDelegate.swift │ │ ├─ Assets.xcassets │ │ │ └─ AppIcon.appiconset │ │ │ ├─ Contents.json │ │ │ ├─ app_icon_1024.png │ │ │ ├─ app_icon_128.png │ │ │ ├─ app_icon_16.png │ │ │ ├─ app_icon_256.png │ │ │ ├─ app_icon_32.png │ │ │ ├─ app_icon_512.png │ │ │ └─ app_icon_64.png │ │ ├─ Base.lproj │ │ │ └─ MainMenu.xib │ │ ├─ Configs │ │ │ ├─ AppInfo.xcconfig │ │ │ ├─ Debug.xcconfig │ │ │ ├─ Release.xcconfig │ │ │ └─ Warnings.xcconfig │ │ ├─ DebugProfile.entitlements │ │ ├─ Info.plist │ │ ├─ MainFlutterWindow.swift │ │ └─ Release.entitlements │ ├─ Runner.xcodeproj │ │ ├─ project.pbxproj │ │ ├─ project.xcworkspace │ │ │ └─ xcshareddata │ │ │ └─ IDEWorkspaceChecks.plist │ │ └─ xcshareddata │ │ └─ xcschemes │ │ └─ Runner.xcscheme │ └─ Runner.xcworkspace │ ├─ contents.xcworkspacedata │ └─ xcshareddata │ └─ IDEWorkspaceChecks.plist ├─ package │ ├─ network │ └─ route │ ├─ errors │ └─ manager ├─ pubspec.lock ├─ pubspec.yaml ├─ test │ └─ widget_test.dart ├─ web │ ├─ favicon.png │ ├─ icons │ │ ├─ Icon-192.png │ │ ├─ Icon-512.png │ │ ├─ Icon-maskable-192.png │ │ └─ Icon-maskable-512.png │ ├─ index.html │ └─ manifest.json └─ windows ├─ .gitignore ├─ CMakeLists.txt ├─ flutter │ ├─ CMakeLists.txt │ ├─ generated_plugin_registrant.cc │ ├─ generated_plugin_registrant.h │ └─ generated_plugins.cmake └─ runner ├─ CMakeLists.txt ├─ Runner.rc ├─ flutter_window.cpp ├─ flutter_window.h ├─ main.cpp ├─ resource.h ├─ resources │ └─ app_icon.ico ├─ runner.exe.manifest ├─ utils.cpp ├─ utils.h ├─ win32_window.cpp └─ win32_window.h
|
END
好文分享: