ai-scaffold-pro 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +86 -0
- package/hooks/check-review-needed.sh +28 -0
- package/hooks/post-edit-tracker.sh +21 -0
- package/i18n/en.json +536 -0
- package/i18n/index.js +27 -0
- package/i18n/zh.json +536 -0
- package/package.json +29 -0
- package/scripts/gen_references.py +877 -0
- package/src/detect.js +320 -0
- package/src/platforms/android.js +206 -0
- package/src/platforms/default.js +26 -0
- package/src/platforms/flutter.js +278 -0
- package/src/platforms/harmonyos.js +26 -0
- package/src/platforms/index.js +40 -0
- package/src/platforms/ios.js +252 -0
- package/src/platforms/react-native.js +26 -0
- package/src/prompts.js +191 -0
- package/src/render.js +459 -0
- package/templates/CHANGELOG.md +21 -0
- package/templates/agents/arch-review.md +78 -0
- package/templates/agents/cpp-memory-review.md +84 -0
- package/templates/agents/proactive-correction.md +204 -0
- package/templates/agents/resource-sync.md +34 -0
- package/templates/rules/conflict_resolution.md +39 -0
- package/templates/rules/project_rule.md +210 -0
- package/templates/settings.json +27 -0
- package/templates/settings.local.json +5 -0
- package/templates/skills/code_review/SKILL.md +117 -0
- package/templates/skills/plan_mode/SKILL.md +92 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
const strings = {
|
|
2
|
+
zh: {
|
|
3
|
+
PLATFORM_RULES_SUMMARY: 'Flutter: Widget树, Provider/Riverpod状态, GoRouter路由, Platform Channel',
|
|
4
|
+
|
|
5
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 Widget 树与组件约束
|
|
6
|
+
|
|
7
|
+
- \`StatelessWidget\` 必须使用 \`const\` 构造函数,除非依赖非 const 数据
|
|
8
|
+
- \`StatefulWidget\` 生命周期严格遵循:\`initState\` → \`didChangeDependencies\` → \`build\` → \`dispose\`
|
|
9
|
+
- 禁止在 \`build()\` 方法中执行副作用(网络请求、文件 IO),副作用应在 \`initState\` 或 \`StateNotifier\` 中处理
|
|
10
|
+
- \`BuildContext\` 安全规则:
|
|
11
|
+
- 禁止在 \`async\` 间隙后使用 \`BuildContext\`(widget 可能已卸载)
|
|
12
|
+
- 使用 \`context\` 前必须检查 \`mounted\` 状态
|
|
13
|
+
- 跨异步操作后使用 Navigator/Theme 等依赖 context 的 API 前必须检查 mounted
|
|
14
|
+
- 列表项必须提供 \`Key\`(\`ValueKey\` 或 \`ObjectKey\`),禁止省略 Key
|
|
15
|
+
- 超过 3 层嵌套的 Widget 树必须提取为独立子组件
|
|
16
|
+
- \`const\` Widget 构造函数优先,有利于框架优化重建
|
|
17
|
+
|
|
18
|
+
### 5.2 状态管理
|
|
19
|
+
|
|
20
|
+
**项目必须选择一种状态管理方案并统一使用,禁止混用**:
|
|
21
|
+
|
|
22
|
+
| 方案 | 适用场景 | 核心 API |
|
|
23
|
+
|------|---------|---------|
|
|
24
|
+
| Provider | 中小型项目 | \`context.watch\` / \`context.read\`, \`ChangeNotifier\` |
|
|
25
|
+
| Riverpod | 中大型项目 | \`ref.watch\` / \`ref.read\`, \`StateNotifierProvider\` |
|
|
26
|
+
| BLoC | 事件驱动场景 | \`BlocBuilder\`, \`BlocListener\`, \`BlocProvider\` |
|
|
27
|
+
|
|
28
|
+
**通用规则**:
|
|
29
|
+
- \`ChangeNotifier\` / \`StateNotifier\` 中禁止直接持有 \`BuildContext\`
|
|
30
|
+
- 状态变更通知必须在数据实际变更后触发,禁止无变更的空通知
|
|
31
|
+
- Provider 的创建位置必须合理(\`main.dart\` 顶层或页面级),禁止在 \`build\` 中创建新 Provider
|
|
32
|
+
- 异步状态使用 \`AsyncValue\` / \`FutureProvider\` / \`StreamProvider\`,禁止手动管理 loading/error 状态
|
|
33
|
+
|
|
34
|
+
### 5.3 布局规范
|
|
35
|
+
|
|
36
|
+
- 间距优先使用 \`SizedBox\`,禁止使用 \`Container\` 仅做间距
|
|
37
|
+
- 内边距使用 \`const EdgeInsets.all/symmetric/only\`,禁止魔法数字
|
|
38
|
+
- 响应式布局:
|
|
39
|
+
- 整体页面尺寸使用 \`MediaQuery.of(context)\`
|
|
40
|
+
- 组件自适应使用 \`LayoutBuilder\`
|
|
41
|
+
- 避免过度嵌套 Column/Row,超过 5 层应提取子组件
|
|
42
|
+
- 使用 \`Flexible\` / \`Expanded\` 正确分配剩余空间
|
|
43
|
+
|
|
44
|
+
### 5.4 路由导航
|
|
45
|
+
|
|
46
|
+
- 使用 GoRouter 进行路由管理,禁止使用 \`Navigator.push\` 直接跳转
|
|
47
|
+
- 路由配置集中定义在 \`lib/routes/app_router.dart\`
|
|
48
|
+
- 页面跳转:
|
|
49
|
+
- \`context.go('/path')\` 替换当前路由
|
|
50
|
+
- \`context.push('/path')\` 压入新路由
|
|
51
|
+
- \`context.pop()\` 返回上一页
|
|
52
|
+
- 路由守卫通过 GoRouter 的 \`redirect\` 实现
|
|
53
|
+
- 深度链接在 GoRouter 的 \`routes\` 中配置
|
|
54
|
+
- 路由参数通过 \`pathParameters\` 和 \`queryParameters\` 传递
|
|
55
|
+
|
|
56
|
+
### 5.5 Platform Channel
|
|
57
|
+
|
|
58
|
+
- 原生通信使用 \`MethodChannel\`(同步请求-响应)或 \`EventChannel\`(流式数据)
|
|
59
|
+
- Channel 名称使用反向域名格式:\`'com.example.app/channel_name'\`
|
|
60
|
+
- 平台端代码放在 \`android/app/src/main/kotlin/\` 和 \`ios/Runner/\`
|
|
61
|
+
- 所有 \`PlatformException\` 必须捕获并处理,禁止未处理的平台异常
|
|
62
|
+
- 原生方法调用必须在主线程外执行(使用 \`compute\` 或 \`Isolate\`)
|
|
63
|
+
|
|
64
|
+
### 5.6 代码组织
|
|
65
|
+
|
|
66
|
+
\`\`\`
|
|
67
|
+
lib/
|
|
68
|
+
├── main.dart # 入口 + Provider 配置
|
|
69
|
+
├── routes/ # 路由配置
|
|
70
|
+
│ └── app_router.dart
|
|
71
|
+
├── models/ # 数据模型
|
|
72
|
+
├── providers/ (或 blocs/) # 状态管理
|
|
73
|
+
├── screens/ # 页面
|
|
74
|
+
├── widgets/ # 可复用组件
|
|
75
|
+
├── services/ # API/业务逻辑
|
|
76
|
+
└── utils/ # 工具类
|
|
77
|
+
\`\`\`
|
|
78
|
+
|
|
79
|
+
- 每个功能模块使用 barrel file(\`index.dart\`)统一导出
|
|
80
|
+
- 禁止在 \`main.dart\` 中编写业务逻辑
|
|
81
|
+
- 模型类使用 \`freezed\` + \`json_serializable\` 生成,禁止手写 \`fromJson\` / \`toJson\``,
|
|
82
|
+
|
|
83
|
+
PLATFORM_FATAL_CHECKS: `- \`BuildContext\` 在 \`async\` 间隙后使用(未检查 mounted)
|
|
84
|
+
- \`setState()\` 在 \`dispose()\` 后调用
|
|
85
|
+
- 缺少 \`super.dispose()\` 调用
|
|
86
|
+
- 未处理的 \`PlatformException\`
|
|
87
|
+
- Provider 在 \`build\` 方法中创建新实例
|
|
88
|
+
- 混用多种状态管理方案(如同时使用 Provider 和 BLoC)`,
|
|
89
|
+
|
|
90
|
+
PLATFORM_WARNING_CHECKS: `- \`StatelessWidget\` 缺少 \`const\` 构造函数
|
|
91
|
+
- 使用 \`Container\` 仅做间距(应用 \`SizedBox\`)
|
|
92
|
+
- Widget 树嵌套超过 5 层未拆分
|
|
93
|
+
- 使用 \`print()\` 调试输出(应用 logging 框架)
|
|
94
|
+
- 列表项缺少 \`Key\` 参数
|
|
95
|
+
- 硬编码字符串/颜色/尺寸(应用主题或常量)`,
|
|
96
|
+
|
|
97
|
+
PLATFORM_SUGGESTION_CHECKS: `- 检查所有可优化的 \`const\` 构造函数
|
|
98
|
+
- 列表项添加 \`Key\` 以支持高效重建
|
|
99
|
+
- 页面转场使用 \`Hero\` 动画
|
|
100
|
+
- 长列表使用 \`ListView.builder\` 懒加载
|
|
101
|
+
- 提取重复 Widget 为独立组件`,
|
|
102
|
+
|
|
103
|
+
PLATFORM_SELF_CHECK_ITEMS: `| F1 | const 构造函数已应用于所有 StatelessWidget? |
|
|
104
|
+
| F2 | BuildContext 未在 async 间隙后使用(或已检查 mounted)? |
|
|
105
|
+
| F3 | 状态管理方案统一(未混用 Provider/BLoC/Riverpod)? |
|
|
106
|
+
| F4 | dispose() 正确重写且调用了 super.dispose()? |
|
|
107
|
+
| F5 | PlatformException 已全部捕获处理? |
|
|
108
|
+
| F6 | pubspec.yaml 依赖版本已锁定? |
|
|
109
|
+
| F7 | 路由使用 GoRouter,无 Navigator.push 直接调用? |
|
|
110
|
+
| F8 | 代码组织符合 feature-based 目录结构? |`,
|
|
111
|
+
|
|
112
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### Flutter 资源同步检查
|
|
113
|
+
|
|
114
|
+
- \`pubspec.yaml\` 中声明的 assets 与实际文件一致
|
|
115
|
+
- 国际化文件(\`l10n.yaml\` / \`.arb\` 文件)覆盖所有支持语言
|
|
116
|
+
- App 图标和启动屏资源齐全(iOS + Android)
|
|
117
|
+
- 图片资源 @2x/@3x 变体齐全(如使用)`,
|
|
118
|
+
|
|
119
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### Flutter 任务模板
|
|
120
|
+
|
|
121
|
+
**新增页面**:
|
|
122
|
+
1. 创建 Screen Widget(StatelessWidget 或 StatefulWidget)
|
|
123
|
+
2. 在 \`app_router.dart\` 中添加路由配置
|
|
124
|
+
3. 创建对应的 Provider/StateNotifier
|
|
125
|
+
4. 如需数据模型,在 \`models/\` 中添加
|
|
126
|
+
|
|
127
|
+
**新增数据模型**:
|
|
128
|
+
1. 创建 Model class(使用 freezed + json_serializable)
|
|
129
|
+
2. 运行 \`build_runner\` 生成代码
|
|
130
|
+
3. 在对应的 Provider 中使用
|
|
131
|
+
|
|
132
|
+
**添加 Platform Channel**:
|
|
133
|
+
1. 定义 MethodChannel 名称
|
|
134
|
+
2. 创建 Dart 端封装类
|
|
135
|
+
3. 实现 Android 端(Kotlin/Java)和 iOS 端(Swift/ObjC)
|
|
136
|
+
4. 处理 PlatformException`,
|
|
137
|
+
},
|
|
138
|
+
en: {
|
|
139
|
+
PLATFORM_RULES_SUMMARY: 'Flutter: Widget tree, Provider/Riverpod state, GoRouter navigation, platform channels',
|
|
140
|
+
|
|
141
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 Widget Tree & Component Constraints
|
|
142
|
+
|
|
143
|
+
- \`StatelessWidget\` must use \`const\` constructors unless depending on non-const data
|
|
144
|
+
- \`StatefulWidget\` lifecycle must follow: \`initState\` → \`didChangeDependencies\` → \`build\` → \`dispose\`
|
|
145
|
+
- Do NOT perform side effects (network, file IO) in \`build()\`; side effects go in \`initState\` or \`StateNotifier\`
|
|
146
|
+
- \`BuildContext\` safety rules:
|
|
147
|
+
- Do NOT use \`BuildContext\` across async gaps (widget may be unmounted)
|
|
148
|
+
- Check \`mounted\` state before using \`context\`
|
|
149
|
+
- After async operations, check mounted before using Navigator/Theme or other context-dependent APIs
|
|
150
|
+
- List items must provide a \`Key\` (\`ValueKey\` or \`ObjectKey\`); omitting Key is prohibited
|
|
151
|
+
- Widget trees with >3 levels of nesting must be extracted into independent sub-components
|
|
152
|
+
- Prefer \`const\` widget constructors for framework rebuild optimization
|
|
153
|
+
|
|
154
|
+
### 5.2 State Management
|
|
155
|
+
|
|
156
|
+
**Projects must choose ONE state management solution and use it consistently; mixing is prohibited**:
|
|
157
|
+
|
|
158
|
+
| Solution | Best For | Core API |
|
|
159
|
+
|----------|----------|----------|
|
|
160
|
+
| Provider | Small-medium projects | \`context.watch\` / \`context.read\`, \`ChangeNotifier\` |
|
|
161
|
+
| Riverpod | Medium-large projects | \`ref.watch\` / \`ref.read\`, \`StateNotifierProvider\` |
|
|
162
|
+
| BLoC | Event-driven scenarios | \`BlocBuilder\`, \`BlocListener\`, \`BlocProvider\` |
|
|
163
|
+
|
|
164
|
+
**General rules**:
|
|
165
|
+
- \`ChangeNotifier\` / \`StateNotifier\` must NOT hold \`BuildContext\` directly
|
|
166
|
+
- State change notifications must only fire after actual data changes; empty notifications are prohibited
|
|
167
|
+
- Provider creation location must be reasonable (top-level in \`main.dart\` or page-level); creating new Providers in \`build\` is prohibited
|
|
168
|
+
- Async state uses \`AsyncValue\` / \`FutureProvider\` / \`StreamProvider\`; manually managing loading/error states is prohibited
|
|
169
|
+
|
|
170
|
+
### 5.3 Layout Standards
|
|
171
|
+
|
|
172
|
+
- Prefer \`SizedBox\` for spacing; using \`Container\` only for spacing is prohibited
|
|
173
|
+
- Use \`const EdgeInsets.all/symmetric/only\` for padding; magic numbers are prohibited
|
|
174
|
+
- Responsive layout:
|
|
175
|
+
- Use \`MediaQuery.of(context)\` for overall page dimensions
|
|
176
|
+
- Use \`LayoutBuilder\` for component-level adaptation
|
|
177
|
+
- Avoid excessive Column/Row nesting; >5 levels should be extracted into sub-components
|
|
178
|
+
- Use \`Flexible\` / \`Expanded\` to correctly distribute remaining space
|
|
179
|
+
|
|
180
|
+
### 5.4 Router Navigation
|
|
181
|
+
|
|
182
|
+
- Use GoRouter for routing; direct \`Navigator.push\` is prohibited
|
|
183
|
+
- Route configuration centralized in \`lib/routes/app_router.dart\`
|
|
184
|
+
- Page navigation:
|
|
185
|
+
- \`context.go('/path')\` replaces current route
|
|
186
|
+
- \`context.push('/path')\` pushes new route
|
|
187
|
+
- \`context.pop()\` goes back
|
|
188
|
+
- Route guards implemented via GoRouter's \`redirect\`
|
|
189
|
+
- Deep linking configured in GoRouter's \`routes\`
|
|
190
|
+
- Route parameters pass via \`pathParameters\` and \`queryParameters\`
|
|
191
|
+
|
|
192
|
+
### 5.5 Platform Channel
|
|
193
|
+
|
|
194
|
+
- Native communication uses \`MethodChannel\` (sync request-response) or \`EventChannel\` (streaming data)
|
|
195
|
+
- Channel names use reverse domain format: \`'com.example.app/channel_name'\`
|
|
196
|
+
- Platform code goes in \`android/app/src/main/kotlin/\` and \`ios/Runner/\`
|
|
197
|
+
- All \`PlatformException\` must be caught and handled; unhandled platform exceptions are prohibited
|
|
198
|
+
- Native method calls must execute off the main thread (use \`compute\` or \`Isolate\`)
|
|
199
|
+
|
|
200
|
+
### 5.6 Code Organization
|
|
201
|
+
|
|
202
|
+
\`\`\`
|
|
203
|
+
lib/
|
|
204
|
+
├── main.dart # Entry + Provider config
|
|
205
|
+
├── routes/ # Route configuration
|
|
206
|
+
│ └── app_router.dart
|
|
207
|
+
├── models/ # Data models
|
|
208
|
+
├── providers/ (or blocs/) # State management
|
|
209
|
+
├── screens/ # Pages
|
|
210
|
+
├── widgets/ # Reusable components
|
|
211
|
+
├── services/ # API/business logic
|
|
212
|
+
└── utils/ # Utilities
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
- Each feature module uses a barrel file (\`index.dart\`) for unified exports
|
|
216
|
+
- Business logic in \`main.dart\` is prohibited
|
|
217
|
+
- Model classes use \`freezed\` + \`json_serializable\` for generation; hand-written \`fromJson\` / \`toJson\` is prohibited`,
|
|
218
|
+
|
|
219
|
+
PLATFORM_FATAL_CHECKS: `- \`BuildContext\` used across async gaps (without checking mounted)
|
|
220
|
+
- \`setState()\` called after \`dispose()\`
|
|
221
|
+
- Missing \`super.dispose()\` call
|
|
222
|
+
- Unhandled \`PlatformException\`
|
|
223
|
+
- New Provider instance created in \`build\` method
|
|
224
|
+
- Multiple state management solutions mixed (e.g., Provider + BLoC together)`,
|
|
225
|
+
|
|
226
|
+
PLATFORM_WARNING_CHECKS: `- \`StatelessWidget\` missing \`const\` constructor
|
|
227
|
+
- \`Container\` used only for spacing (should use \`SizedBox\`)
|
|
228
|
+
- Widget tree nesting >5 levels without extraction
|
|
229
|
+
- Using \`print()\` for debug output (should use logging framework)
|
|
230
|
+
- List items missing \`Key\` parameter
|
|
231
|
+
- Hardcoded strings/colors/dimensions (should use theme or constants)`,
|
|
232
|
+
|
|
233
|
+
PLATFORM_SUGGESTION_CHECKS: `- Check all optimizable \`const\` constructors
|
|
234
|
+
- Add \`Key\` to list items for efficient rebuilding
|
|
235
|
+
- Use \`Hero\` animations for page transitions
|
|
236
|
+
- Use \`ListView.builder\` for lazy loading long lists
|
|
237
|
+
- Extract repeated Widgets into independent components`,
|
|
238
|
+
|
|
239
|
+
PLATFORM_SELF_CHECK_ITEMS: `| F1 | const constructors applied to all StatelessWidgets? |
|
|
240
|
+
| F2 | BuildContext not used across async gaps (or mounted checked)? |
|
|
241
|
+
| F3 | State management solution consistent (not mixing Provider/BLoC/Riverpod)? |
|
|
242
|
+
| F4 | dispose() correctly overridden with super.dispose() called? |
|
|
243
|
+
| F5 | All PlatformExceptions caught and handled? |
|
|
244
|
+
| F6 | pubspec.yaml dependency versions locked? |
|
|
245
|
+
| F7 | Routing uses GoRouter, no direct Navigator.push calls? |
|
|
246
|
+
| F8 | Code organization follows feature-based directory structure? |`,
|
|
247
|
+
|
|
248
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### Flutter Resource Sync Checks
|
|
249
|
+
|
|
250
|
+
- Assets declared in \`pubspec.yaml\` match actual files
|
|
251
|
+
- i18n files (\`l10n.yaml\` / \`.arb\` files) cover all supported languages
|
|
252
|
+
- App icon and splash screen resources complete (iOS + Android)
|
|
253
|
+
- Image resource @2x/@3x variants complete (if used)`,
|
|
254
|
+
|
|
255
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### Flutter Task Templates
|
|
256
|
+
|
|
257
|
+
**Add new screen**:
|
|
258
|
+
1. Create Screen Widget (StatelessWidget or StatefulWidget)
|
|
259
|
+
2. Add route configuration in \`app_router.dart\`
|
|
260
|
+
3. Create corresponding Provider/StateNotifier
|
|
261
|
+
4. Add data model in \`models/\` if needed
|
|
262
|
+
|
|
263
|
+
**Add data model**:
|
|
264
|
+
1. Create Model class (using freezed + json_serializable)
|
|
265
|
+
2. Run \`build_runner\` to generate code
|
|
266
|
+
3. Use in corresponding Provider
|
|
267
|
+
|
|
268
|
+
**Add Platform Channel**:
|
|
269
|
+
1. Define MethodChannel name
|
|
270
|
+
2. Create Dart-side wrapper class
|
|
271
|
+
3. Implement Android side (Kotlin/Java) and iOS side (Swift/ObjC)
|
|
272
|
+
4. Handle PlatformException`,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
export default function getPlatformVars(lang) {
|
|
277
|
+
return strings[lang] || strings.en;
|
|
278
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const strings = {
|
|
2
|
+
zh: {
|
|
3
|
+
PLATFORM_RULES_SUMMARY: 'HarmonyOS: Stage模型, ArkUI组件, ArkTS状态管理, router路由, 资源限定词',
|
|
4
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 Stage 模型与 UIAbility 生命周期\n\n- API 9+ 项目**必须**使用 Stage 模型,禁止使用 FA 模型\n- UIAbility 生命周期严格按顺序执行:\`onCreate\` → \`onWindowStageCreate\` → \`onForeground\` → \`onBackground\` → \`onWindowStageDestroy\` → \`onDestroy\`\n- 禁止在 \`onCreate\` 中执行 UI 操作(此时 Window 尚未创建),UI 初始化必须放在 \`onWindowStageCreate\` 中\n- 禁止在 \`onForeground\` 中执行耗时操作(如网络请求、数据库查询),应仅做 UI 状态恢复\n- \`onBackground\` 中应释放非必要资源,保存临时状态\n- 跨 Ability 页面跳转使用 \`startAbility(want)\`,数据通过 \`want.parameters\` 传递,禁止使用全局变量传参\n\n### 5.2 ArkUI 组件规范\n\n- 自定义组件必须使用 \`@Component struct\` 定义,禁止使用 class 组件\n- \`build()\` 方法中禁止执行副作用操作(网络请求、定时器、文件 IO)\n- 组件属性传递规则:\n - 父→子单向传递使用 \`@Prop\`\n - 父↔子双向绑定使用 \`@Link\`\n - 跨多层组件使用 \`@Provide\` / \`@Consume\`\n- 列表渲染必须使用 \`LazyForEach\` + \`DataSource\`,禁止使用 \`ForEach\` 渲染大量数据\n- 组件复用标记使用 \`@Reusable\`,并在 \`aboutToReuse(params)\` 中更新状态\n- 条件渲染使用 \`if/else\` 和 \`ForEach\`,禁止使用三元表达式渲染复杂组件树\n\n### 5.3 ArkTS 状态管理\n\n| 装饰器 | 用途 | 数据源 | 规则 |\n|--------|------|--------|------|\n| \`@State\` | 组件内状态 | 组件内部 | 可变,触发当前组件重渲染 |\n| \`@Prop\` | 父→子单向 | 父组件 | 子组件深拷贝,修改不影响父组件 |\n| \`@Link\` | 父↔子双向 | 父组件 | 引用类型,修改同步到父组件 |\n| \`@Provide\` / \`@Consume\` | 跨组件 | 祖先组件 | 类似 React Context,需同 key 配对 |\n| \`@Observed\` / \`@ObjectLink\` | 嵌套对象 | 类实例 | 用于 class 对象属性变更观察 |\n| \`@Watch\` | 状态变更监听 | 任意状态装饰器 | 状态变更时执行回调,格式 \`@Watch('methodName')\` |\n\n**关键规则**:\n- \`@Prop\` 装饰的变量禁止直接修改对象内部属性(深拷贝语义),如需修改请使用 \`@Link\`\n- 全局状态使用 \`AppStorage\`(内存)或 \`PersistentStorage\`(持久化),禁止使用全局变量\n- 状态变量必须有初始值,禁止声明未初始化的 \`@State\` / \`@Link\` 变量\n- \`@Watch\` 回调中禁止修改被观察的状态变量本身(避免循环触发)\n\n### 5.4 路由导航\n\n- 路由表配置在 \`resources/base/profile/main_pages.json\` 中\n- 页面跳转使用 \`router.pushUrl({ url: 'pages/PageName' })\`,禁止使用 \`router.push()\`(已废弃)\n- 页面替换使用 \`router.replaceUrl()\`\n- 返回使用 \`router.back()\` 或 \`router.clear()\`(清空路由栈)\n- 路由参数通过 \`params\` 传递,接收方在 \`onPageShow()\` 中获取\n- 模态页面使用 \`openCustomDialog\` / \`openBindSheet\`,禁止用路由模拟弹窗\n\n### 5.5 资源管理\n\n- 所有字符串必须放入 \`resources/base/element/string.json\`,使用 \`$r('app.string.xxx')\` 引用\n- 颜色放入 \`resources/base/element/color.json\`,使用 \`$r('app.color.xxx')\` 引用\n- 图片放入 \`resources/base/media/\`,使用 \`$r('app.media.xxx')\` 引用\n- 原始文件放入 \`resources/rawfile/\`,使用 \`$rawfile('xxx')\` 引用\n- 禁止在代码中硬编码字符串、颜色值、尺寸值\n- 多语言通过资源限定词目录实现(如 \`resources/en_US/\`、\`resources/zh_CN/\`)\n\n### 5.6 构建与依赖\n\n- 构建系统使用 hvigor,依赖声明在 \`oh-package.json5\` 中\n- 共享库引用使用 \`"dependencies"\` 中声明,禁止手动拷贝源码\n- 模块间依赖通过 \`oh-package.json5\` 的 \`dependencies\` 配置\n- 禁止在 \`hvigorfile.ts\` 中硬编码路径,使用相对路径或配置变量`,
|
|
5
|
+
PLATFORM_FATAL_CHECKS: `- UIAbility 在 \`onCreate\` 中执行 UI 操作\n- \`@Prop\` 装饰的变量被直接修改(应使用 \`@Link\` 或回调)\n- 路由表(main_pages.json)中缺少页面注册\n- ArkTS 文件中使用 \`any\` 类型(ArkTS 严格模式禁止)\n- 使用动态属性访问(ArkTS 静态类型语言特性禁止)\n- \`ForEach\` 渲染大量数据(应使用 \`LazyForEach\`)\n- 全局变量替代 \`AppStorage\` / \`PersistentStorage\`\n- 硬编码路由路径字符串`,
|
|
6
|
+
PLATFORM_WARNING_CHECKS: `- 硬编码字符串/颜色/尺寸(应使用 \`$r()\` 引用)\n- \`@State\` 在子组件中使用(应考虑 \`@Prop\` / \`@Link\`)\n- 缺少 \`@Watch\` 监听需要响应变更的状态\n- \`build()\` 方法过于复杂(超过 100 行),应拆分子组件\n- 未使用 \`@Reusable\` 标记可复用组件\n- \`onForeground\` 中执行耗时操作`,
|
|
7
|
+
PLATFORM_SUGGESTION_CHECKS: `- 使用 \`@Reusable\` + \`aboutToReuse\` 优化列表项组件复用\n- 图片使用 \`LazyForEach\` + 懒加载策略\n- 使用 \`AppStorage.Link\` 替代层层 \`@Provide\` / \`@Consume\`\n- 组件拆分遵循单一职责原则\n- 使用 \`@Observed\` / \`@ObjectLink\` 替代深拷贝场景`,
|
|
8
|
+
PLATFORM_SELF_CHECK_ITEMS: `| H1 | UIAbility 生命周期操作放在正确的回调中? |\n| H2 | 状态装饰器选择正确(@State/@Link/@Prop/@Provide)? |\n| H3 | 资源引用使用 $r() / $rawfile(),无硬编码? |\n| H4 | 路由页面已在 main_pages.json 中注册? |\n| H5 | ArkTS 严格模式合规(无 any、无动态属性访问)? |\n| H6 | 列表使用 LazyForEach 而非 ForEach? |\n| H7 | @Prop 变量未被直接修改? |\n| H8 | 全局状态使用 AppStorage / PersistentStorage? |`,
|
|
9
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### HarmonyOS 资源同步检查\n\n- \`resources/base/element/string.json\`:检查所有语言目录下的字符串覆盖一致性\n- \`resources/base/element/color.json\`:检查颜色定义是否完整\n- \`resources/base/media/\`:检查图片资源是否存在,密度变体是否齐全\n- \`resources/base/profile/\`:检查布局文件和路由表配置\n- 多语言目录(如 \`resources/en_US/\`、\`resources/zh_CN/\`):检查各语言资源文件结构一致`,
|
|
10
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### HarmonyOS 任务模板\n\n**新增页面**:\n1. 创建 ArkUI 页面组件(\`@Component struct\`)\n2. 在 \`main_pages.json\` 路由表中注册\n3. 如需独立 Ability,创建 UIAbility 并注册到 \`module.json5\`\n4. 配置页面间数据传递(want.parameters)\n\n**添加共享状态**:\n1. 确定状态层级(组件内 @State / 父子 @Link / 跨组件 @Provide)\n2. 在提供方组件声明 @Provide,在消费方声明 @Consume\n3. 或使用 AppStorage 全局状态方案\n\n**添加 ServiceAbility**:\n1. 创建 ServiceAbility 类并实现生命周期\n2. 在 \`module.json5\` 中注册\n3. 实现 IPC 接口(如需跨进程通信)`,
|
|
11
|
+
},
|
|
12
|
+
en: {
|
|
13
|
+
PLATFORM_RULES_SUMMARY: 'HarmonyOS: Stage model, ArkUI components, ArkTS state management, router navigation, resource qualifiers',
|
|
14
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 Stage Model & UIAbility Lifecycle\n\n- API 9+ projects **must** use Stage model; FA model is prohibited\n- UIAbility lifecycle executes strictly in order: \`onCreate\` → \`onWindowStageCreate\` → \`onForeground\` → \`onBackground\` → \`onWindowStageDestroy\` → \`onDestroy\`\n- Do NOT perform UI operations in \`onCreate\` (Window not yet created); UI initialization must go in \`onWindowStageCreate\`\n- Do NOT perform heavy operations (network requests, DB queries) in \`onForeground\`; only restore UI state\n- Release non-essential resources and save temporary state in \`onBackground\`\n- Cross-Ability navigation uses \`startAbility(want)\`; data passes via \`want.parameters\`; global variables for parameter passing are prohibited\n\n### 5.2 ArkUI Component Standards\n\n- Custom components must be defined with \`@Component struct\`; class components are prohibited\n- Do NOT perform side effects (network, timers, file IO) in \`build()\` method\n- Component property passing rules:\n - Parent→Child one-way: use \`@Prop\`\n - Parent↔Child two-way: use \`@Link\`\n - Cross-component: use \`@Provide\` / \`@Consume\`\n- List rendering must use \`LazyForEach\` + \`DataSource\`; using \`ForEach\` for large datasets is prohibited\n- Component reuse: mark with \`@Reusable\`, update state in \`aboutToReuse(params)\`\n- Conditional rendering uses \`if/else\` and \`ForEach\`; ternary expressions for complex component trees are prohibited\n\n### 5.3 ArkTS State Management\n\n| Decorator | Purpose | Data Source | Rule |\n|-----------|---------|-------------|------|\n| \`@State\` | Component-internal state | Component | Mutable, triggers re-render of current component |\n| \`@Prop\` | Parent→Child one-way | Parent | Deep copy in child; child modification doesn't affect parent |\n| \`@Link\` | Parent↔Child two-way | Parent | Reference type; changes sync to parent |\n| \`@Provide\` / \`@Consume\` | Cross-component | Ancestor | Like React Context; must pair with same key |\n| \`@Observed\` / \`@ObjectLink\` | Nested objects | Class instance | For observing class object property changes |\n| \`@Watch\` | State change listener | Any state decorator | Executes callback on state change; format: \`@Watch('methodName')\` |\n\n**Key rules**:\n- \`@Prop\`-decorated variables must NOT directly modify internal object properties (deep copy semantics); use \`@Link\` if modification is needed\n- Global state uses \`AppStorage\` (memory) or \`PersistentStorage\` (persistent); global variables are prohibited\n- State variables must have initial values; uninitialized \`@State\` / \`@Link\` declarations are prohibited\n- \`@Watch\` callbacks must NOT modify the observed state variable itself (avoid circular triggers)\n\n### 5.4 Router Navigation\n\n- Route table configured in \`resources/base/profile/main_pages.json\`\n- Page navigation uses \`router.pushUrl({ url: 'pages/PageName' })\`; \`router.push()\` is deprecated and prohibited\n- Page replacement uses \`router.replaceUrl()\`\n- Navigation back uses \`router.back()\` or \`router.clear()\` (clear route stack)\n- Route parameters pass via \`params\`; receiver obtains in \`onPageShow()\`\n- Modal pages use \`openCustomDialog\` / \`openBindSheet\`; routing to simulate dialogs is prohibited\n\n### 5.5 Resource Management\n\n- All strings must go into \`resources/base/element/string.json\`, referenced with \`$r('app.string.xxx')\`\n- Colors go into \`resources/base/element/color.json\`, referenced with \`$r('app.color.xxx')\`\n- Images go into \`resources/base/media/\`, referenced with \`$r('app.media.xxx')\`\n- Raw files go into \`resources/rawfile/\`, referenced with \`$rawfile('xxx')\`\n- Hardcoded strings, color values, and dimension values in code are prohibited\n- Multi-language support via resource qualifier directories (e.g., \`resources/en_US/\`, \`resources/zh_CN/\`)\n\n### 5.6 Build & Dependencies\n\n- Build system is hvigor; dependencies declared in \`oh-package.json5\`\n- Shared library references declared in \`dependencies\`; manual source code copying is prohibited\n- Inter-module dependencies configured via \`oh-package.json5\` \`dependencies\`\n- Hardcoded paths in \`hvigorfile.ts\` are prohibited; use relative paths or config variables`,
|
|
15
|
+
PLATFORM_FATAL_CHECKS: `- UIAbility performing UI operations in \`onCreate\`\n- Direct modification of \`@Prop\`-decorated variables (should use \`@Link\` or callbacks)\n- Missing page registration in route table (main_pages.json)\n- Using \`any\` type in ArkTS files (prohibited by ArkTS strict mode)\n- Dynamic property access (prohibited by ArkTS static typing)\n- \`ForEach\` rendering large datasets (should use \`LazyForEach\`)\n- Global variables instead of \`AppStorage\` / \`PersistentStorage\`\n- Hardcoded route path strings`,
|
|
16
|
+
PLATFORM_WARNING_CHECKS: `- Hardcoded strings/colors/dimensions (should use \`$r()\` references)\n- \`@State\` used in child components (consider \`@Prop\` / \`@Link\`)\n- Missing \`@Watch\` on state that needs change observation\n- Overly complex \`build()\` method (>100 lines); should extract sub-components\n- Missing \`@Reusable\` on reusable list item components\n- Heavy operations in \`onForeground\``,
|
|
17
|
+
PLATFORM_SUGGESTION_CHECKS: `- Use \`@Reusable\` + \`aboutToReuse\` for list item component reuse\n- Use \`LazyForEach\` + lazy loading for images\n- Use \`AppStorage.Link\` instead of deep \`@Provide\` / \`@Consume\` chains\n- Follow single-responsibility principle for component extraction\n- Use \`@Observed\` / \`@ObjectLink\` instead of deep copy scenarios`,
|
|
18
|
+
PLATFORM_SELF_CHECK_ITEMS: `| H1 | UIAbility lifecycle operations in correct callbacks? |\n| H2 | State decorators chosen correctly (@State/@Link/@Prop/@Provide)? |\n| H3 | Resource references use $r() / $rawfile(), no hardcoding? |\n| H4 | Route pages registered in main_pages.json? |\n| H5 | ArkTS strict mode compliant (no any, no dynamic property access)? |\n| H6 | Lists use LazyForEach instead of ForEach? |\n| H7 | @Prop variables not directly modified? |\n| H8 | Global state uses AppStorage / PersistentStorage? |`,
|
|
19
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### HarmonyOS Resource Sync Checks\n\n- \`resources/base/element/string.json\`: Check string coverage consistency across all language directories\n- \`resources/base/element/color.json\`: Check color definitions are complete\n- \`resources/base/media/\`: Check image resources exist, density variants complete\n- \`resources/base/profile/\`: Check layout files and route table configuration\n- Multi-language directories (e.g., \`resources/en_US/\`, \`resources/zh_CN/\`): Check resource file structure consistency`,
|
|
20
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### HarmonyOS Task Templates\n\n**Add new page**:\n1. Create ArkUI page component (\`@Component struct\`)\n2. Register in route table (\`main_pages.json\`)\n3. If independent Ability needed, create UIAbility and register in \`module.json5\`\n4. Configure page data passing (want.parameters)\n\n**Add shared state**:\n1. Determine state level (component @State / parent-child @Link / cross-component @Provide)\n2. Declare @Provide in provider component, @Consume in consumer\n3. Or use AppStorage global state solution\n\n**Add ServiceAbility**:\n1. Create ServiceAbility class and implement lifecycle\n2. Register in \`module.json5\`\n3. Implement IPC interface (if cross-process communication needed)`,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default function getPlatformVars(lang) {
|
|
25
|
+
return strings[lang] || strings.en;
|
|
26
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = path.dirname(__filename);
|
|
6
|
+
|
|
7
|
+
const PLATFORM_MAP = {
|
|
8
|
+
'Android': 'android',
|
|
9
|
+
'iOS': 'ios',
|
|
10
|
+
'HarmonyOS': 'harmonyos',
|
|
11
|
+
'Flutter': 'flutter',
|
|
12
|
+
'React Native': 'react-native',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const EMPTY_VARS = {
|
|
16
|
+
PLATFORM_SPECIFIC_RULES: '',
|
|
17
|
+
PLATFORM_FATAL_CHECKS: '',
|
|
18
|
+
PLATFORM_WARNING_CHECKS: '',
|
|
19
|
+
PLATFORM_SUGGESTION_CHECKS: '',
|
|
20
|
+
PLATFORM_SELF_CHECK_ITEMS: '',
|
|
21
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: '',
|
|
22
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: '',
|
|
23
|
+
PLATFORM_RULES_SUMMARY: '',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function getPlatformVars(platform, lang) {
|
|
27
|
+
const key = PLATFORM_MAP[platform] || 'default';
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const mod = await import(path.join(__dirname, `${key}.js`));
|
|
31
|
+
return { ...EMPTY_VARS, ...mod.default(lang) };
|
|
32
|
+
} catch {
|
|
33
|
+
try {
|
|
34
|
+
const fallback = await import(path.join(__dirname, `default.js`));
|
|
35
|
+
return { ...EMPTY_VARS, ...fallback.default(lang) };
|
|
36
|
+
} catch {
|
|
37
|
+
return EMPTY_VARS;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
const strings = {
|
|
2
|
+
zh: {
|
|
3
|
+
PLATFORM_RULES_SUMMARY: 'iOS: SwiftUI/UIKit, MVVM, ARC内存, Swift并发, App Store合规',
|
|
4
|
+
|
|
5
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 SwiftUI / UIKit 组件规范
|
|
6
|
+
|
|
7
|
+
**SwiftUI(推荐新项目使用)**:
|
|
8
|
+
- \`body\` 计算属性中禁止执行副作用,仅构建声明式 UI
|
|
9
|
+
- 状态绑定规则:
|
|
10
|
+
- \`@State\`:视图内部可变状态
|
|
11
|
+
- \`@Binding\`:父→子双向绑定
|
|
12
|
+
- \`@ObservedObject\`:外部传入的可观察对象(不持有生命周期)
|
|
13
|
+
- \`@StateObject\`:视图拥有生命周期的可观察对象(视图内创建)
|
|
14
|
+
- \`@EnvironmentObject\`:跨视图层级注入
|
|
15
|
+
- \`@StateObject\` 与 \`@ObservedObject\` 选择规则:在创建对象的视图中使用 \`@StateObject\`,传递给子视图时使用 \`@ObservedObject\`
|
|
16
|
+
- 视图组合优先于继承,通过 \`ViewModifier\` 和 \`View\` 扩展复用样式
|
|
17
|
+
|
|
18
|
+
**UIKit(维护中的项目)**:
|
|
19
|
+
- \`UIViewController\` 生命周期:\`viewDidLoad\` → \`viewWillAppear\` → \`viewDidAppear\` → \`viewWillDisappear\` → \`viewDidDisappear\`
|
|
20
|
+
- 禁止在 \`viewDidLoad\` 中依赖视图尺寸(使用 \`viewDidLayoutSubviews\`)
|
|
21
|
+
- SwiftUI 与 UIKit 混编使用 \`UIViewRepresentable\` / \`UIViewControllerRepresentable\`
|
|
22
|
+
|
|
23
|
+
### 5.2 ARC 内存管理
|
|
24
|
+
|
|
25
|
+
- 闭包中捕获 self 必须使用 \`[weak self]\` 或 \`[unowned self]\`
|
|
26
|
+
- 默认使用 \`[weak self]\`
|
|
27
|
+
- 仅在确定 self 生命周期覆盖闭包时使用 \`[unowned self]\`
|
|
28
|
+
- delegate 必须声明为 \`weak\` 引用,禁止强引用委托
|
|
29
|
+
- \`deinit\` 中清理通知监听、定时器、KVO 观察者
|
|
30
|
+
- 批量对象创建使用 \`autoreleasepool\` 控制峰值内存
|
|
31
|
+
- Core Foundation 对象必须手动管理(\`Unmanaged\` / \`takeRetainedValue\` / \`takeUnretainedValue\`)
|
|
32
|
+
|
|
33
|
+
### 5.3 Swift 并发(Concurrency)
|
|
34
|
+
|
|
35
|
+
- 异步操作优先使用 \`async/await\`,替代 completion handler
|
|
36
|
+
- 线程安全使用 \`actor\` 替代手动锁(\`NSLock\` / \`DispatchQueue\`)
|
|
37
|
+
- UI 更新必须在主线程执行:
|
|
38
|
+
- SwiftUI:视图自动在主线程更新
|
|
39
|
+
- UIKit:使用 \`@MainActor\` 标记或 \`MainActor.run\`
|
|
40
|
+
- \`Task\` 取消规则:
|
|
41
|
+
- 长时间运行的任务必须检查 \`Task.isCancelled\`
|
|
42
|
+
- 视图消失时取消关联的 \`Task\`(使用 \`task(id:)\` modifier)
|
|
43
|
+
- 禁止在 \`actor\` 中使用 \`DispatchQueue.main.sync\`(死锁风险)
|
|
44
|
+
- 数据竞争防护:共享可变状态必须通过 \`actor\` 保护
|
|
45
|
+
|
|
46
|
+
### 5.4 架构模式(MVVM)
|
|
47
|
+
|
|
48
|
+
- ViewModel 为纯 Swift class,禁止继承 UIViewController
|
|
49
|
+
- ViewModel 与 View 的绑定:
|
|
50
|
+
- SwiftUI:使用 \`@Published\` 属性 + \`@StateObject\` / \`@ObservedObject\`
|
|
51
|
+
- UIKit:使用 \`Combine\` 的 \`@Published\` + \`sink\` 或闭包回调
|
|
52
|
+
- 依赖注入通过协议(Protocol)实现,禁止在 ViewModel 中直接创建服务实例
|
|
53
|
+
- 导航协调使用 Coordinator 模式(UIKit)或 Router 模式(SwiftUI)
|
|
54
|
+
- 网络层通过 \`URLSession\` + \`async/await\` + \`Codable\` 实现
|
|
55
|
+
|
|
56
|
+
### 5.5 App Store 合规
|
|
57
|
+
|
|
58
|
+
- **隐私清单(Privacy Manifest)**:必须包含 \`PrivacyInfo.xcprivacy\`
|
|
59
|
+
- 声明使用的 Required Reason API(UserDefaults、文件时间戳、磁盘空间等)
|
|
60
|
+
- 声明收集的数据类型和用途
|
|
61
|
+
- 禁止使用私有 API(会被 App Store 审核拒绝)
|
|
62
|
+
- 敏感数据存储:
|
|
63
|
+
- 凭据使用 Keychain
|
|
64
|
+
- 用户偏好使用 UserDefaults(非敏感数据)
|
|
65
|
+
- 禁止在 UserDefaults 中存储密码、token 等敏感信息
|
|
66
|
+
- 权限使用说明必须在 \`Info.plist\` 中配置(NSCameraUsageDescription 等)`,
|
|
67
|
+
|
|
68
|
+
PLATFORM_FATAL_CHECKS: `- 闭包中强引用 self 导致循环引用
|
|
69
|
+
- UI 操作在后台线程执行
|
|
70
|
+
- 强制解包(\`!\`)未做空值检查
|
|
71
|
+
- UI 操作缺少 \`@MainActor\` 标记
|
|
72
|
+
- 使用私有 API(App Store 审核拒绝)
|
|
73
|
+
- delegate 未声明为 \`weak\``,
|
|
74
|
+
|
|
75
|
+
PLATFORM_WARNING_CHECKS: `- 使用 \`String(format:)\` 而非 \`LocalizedStringKey\`
|
|
76
|
+
- UI 测试缺少 \`accessibilityIdentifier\`
|
|
77
|
+
- 使用 \`DispatchQueue.main.async\` 而非 \`@MainActor\`
|
|
78
|
+
- 强制类型转换(\`as!\`)未做安全检查
|
|
79
|
+
- \`@StateObject\` 与 \`@ObservedObject\` 使用场景错误`,
|
|
80
|
+
|
|
81
|
+
PLATFORM_SUGGESTION_CHECKS: `- 闭包中使用 \`weak self\`(即使非必须,也建议预防)
|
|
82
|
+
- 使用 \`Result\` 类型替代 optional error 模式
|
|
83
|
+
- 使用 \`async/await\` 替代 completion handler
|
|
84
|
+
- 新视图优先使用 SwiftUI 而非 UIKit
|
|
85
|
+
- 使用 \`ViewModifier\` 复用样式而非复制代码`,
|
|
86
|
+
|
|
87
|
+
PLATFORM_SELF_CHECK_ITEMS: `| iOS1 | 闭包中使用 weak/unowned 捕获 self? |
|
|
88
|
+
| iOS2 | UI 更新在主线程(@MainActor)? |
|
|
89
|
+
| iOS3 | 无强制解包(!)或已做空值检查? |
|
|
90
|
+
| iOS4 | 隐私清单 PrivacyInfo.xcprivacy 已配置? |
|
|
91
|
+
| iOS5 | accessibilityIdentifier 已设置(UI 测试需要)? |
|
|
92
|
+
| iOS6 | 异步操作使用 async/await? |
|
|
93
|
+
| iOS7 | delegate 声明为 weak 引用? |
|
|
94
|
+
| iOS8 | Info.plist 权限说明已配置? |`,
|
|
95
|
+
|
|
96
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### iOS 资源同步检查
|
|
97
|
+
|
|
98
|
+
- \`Assets.xcassets\` 中的图片资源完整性
|
|
99
|
+
- \`Localizable.strings\` 覆盖所有支持语言
|
|
100
|
+
- Launch Screen 配置正确
|
|
101
|
+
- App Icon 尺寸齐全
|
|
102
|
+
- 隐私清单 \`PrivacyInfo.xcprivacy\` 配置完整
|
|
103
|
+
- Info.plist 权限描述完整`,
|
|
104
|
+
|
|
105
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### iOS 任务模板
|
|
106
|
+
|
|
107
|
+
**新增 SwiftUI 页面**:
|
|
108
|
+
1. 创建 SwiftUI View
|
|
109
|
+
2. 创建对应的 ViewModel(ObservableObject)
|
|
110
|
+
3. 配置路由(NavigationLink / Router)
|
|
111
|
+
4. 添加必要的状态绑定
|
|
112
|
+
|
|
113
|
+
**新增网络层**:
|
|
114
|
+
1. 定义 API 接口(URLSession + async/await)
|
|
115
|
+
2. 创建 Codable 数据模型
|
|
116
|
+
3. 实现错误处理(自定义 Error 类型)
|
|
117
|
+
4. 在 ViewModel 中集成
|
|
118
|
+
|
|
119
|
+
**新增 CoreData 实体**:
|
|
120
|
+
1. 在 .xcdatamodeld 中定义 Entity
|
|
121
|
+
2. 生成 NSManagedObject 子类
|
|
122
|
+
3. 创建 Core Data Stack 配置
|
|
123
|
+
4. 实现 CRUD 操作`,
|
|
124
|
+
},
|
|
125
|
+
en: {
|
|
126
|
+
PLATFORM_RULES_SUMMARY: 'iOS: SwiftUI/UIKit, MVVM, ARC memory, Swift concurrency (async/await, actors), App Store compliance',
|
|
127
|
+
|
|
128
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 SwiftUI / UIKit Component Standards
|
|
129
|
+
|
|
130
|
+
**SwiftUI (recommended for new projects)**:
|
|
131
|
+
- Do NOT perform side effects in \`body\` computed property; only build declarative UI
|
|
132
|
+
- State binding rules:
|
|
133
|
+
- \`@State\`: View-internal mutable state
|
|
134
|
+
- \`@Binding\`: Parent↔Child two-way binding
|
|
135
|
+
- \`@ObservedObject\`: Externally provided observable object (doesn't own lifecycle)
|
|
136
|
+
- \`@StateObject\`: View-owned observable object (created within the view)
|
|
137
|
+
- \`@EnvironmentObject\`: Cross-hierarchy injection
|
|
138
|
+
- \`@StateObject\` vs \`@ObservedObject\`: Use \`@StateObject\` where the object is created; use \`@ObservedObject\` when passed to child views
|
|
139
|
+
- Prefer view composition over inheritance; reuse styles via \`ViewModifier\` and \`View\` extensions
|
|
140
|
+
|
|
141
|
+
**UIKit (for maintained projects)**:
|
|
142
|
+
- \`UIViewController\` lifecycle: \`viewDidLoad\` → \`viewWillAppear\` → \`viewDidAppear\` → \`viewWillDisappear\` → \`viewDidDisappear\`
|
|
143
|
+
- Do NOT rely on view dimensions in \`viewDidLoad\` (use \`viewDidLayoutSubviews\`)
|
|
144
|
+
- SwiftUI-UIKit interop uses \`UIViewRepresentable\` / \`UIViewControllerRepresentable\`
|
|
145
|
+
|
|
146
|
+
### 5.2 ARC Memory Management
|
|
147
|
+
|
|
148
|
+
- Closures capturing self must use \`[weak self]\` or \`[unowned self]\`
|
|
149
|
+
- Default to \`[weak self]\`
|
|
150
|
+
- Only use \`[unowned self]\` when self lifecycle is guaranteed to cover the closure
|
|
151
|
+
- delegate must be declared as \`weak\` reference; strong delegate references are prohibited
|
|
152
|
+
- Clean up notification observers, timers, and KVO in \`deinit\`
|
|
153
|
+
- Use \`autoreleasepool\` for batch object creation to control peak memory
|
|
154
|
+
- Core Foundation objects must be manually managed (\`Unmanaged\` / \`takeRetainedValue\` / \`takeUnretainedValue\`)
|
|
155
|
+
|
|
156
|
+
### 5.3 Swift Concurrency
|
|
157
|
+
|
|
158
|
+
- Prefer \`async/await\` for async operations; replace completion handlers
|
|
159
|
+
- Thread safety uses \`actor\` instead of manual locks (\`NSLock\` / \`DispatchQueue\`)
|
|
160
|
+
- UI updates must execute on main thread:
|
|
161
|
+
- SwiftUI: Views auto-update on main thread
|
|
162
|
+
- UIKit: Use \`@MainActor\` annotation or \`MainActor.run\`
|
|
163
|
+
- \`Task\` cancellation rules:
|
|
164
|
+
- Long-running tasks must check \`Task.isCancelled\`
|
|
165
|
+
- Cancel associated \`Task\` when view disappears (use \`task(id:)\` modifier)
|
|
166
|
+
- Do NOT use \`DispatchQueue.main.sync\` inside \`actor\` (deadlock risk)
|
|
167
|
+
- Data race protection: shared mutable state must be protected via \`actor\`
|
|
168
|
+
|
|
169
|
+
### 5.4 Architecture (MVVM)
|
|
170
|
+
|
|
171
|
+
- ViewModel is a plain Swift class; inheriting UIViewController is prohibited
|
|
172
|
+
- ViewModel-View binding:
|
|
173
|
+
- SwiftUI: \`@Published\` properties + \`@StateObject\` / \`@ObservedObject\`
|
|
174
|
+
- UIKit: \`Combine\` \`@Published\` + \`sink\` or closure callbacks
|
|
175
|
+
- Dependency injection via Protocol; directly creating service instances in ViewModel is prohibited
|
|
176
|
+
- Navigation coordination uses Coordinator pattern (UIKit) or Router pattern (SwiftUI)
|
|
177
|
+
- Network layer via \`URLSession\` + \`async/await\` + \`Codable\`
|
|
178
|
+
|
|
179
|
+
### 5.5 App Store Compliance
|
|
180
|
+
|
|
181
|
+
- **Privacy Manifest**: Must include \`PrivacyInfo.xcprivacy\`
|
|
182
|
+
- Declare Required Reason APIs used (UserDefaults, file timestamps, disk space, etc.)
|
|
183
|
+
- Declare data types collected and purposes
|
|
184
|
+
- Private API usage is prohibited (App Store review rejection)
|
|
185
|
+
- Sensitive data storage:
|
|
186
|
+
- Credentials use Keychain
|
|
187
|
+
- User preferences use UserDefaults (non-sensitive data only)
|
|
188
|
+
- Storing passwords, tokens, etc. in UserDefaults is prohibited
|
|
189
|
+
- Usage descriptions must be configured in \`Info.plist\` (NSCameraUsageDescription, etc.)`,
|
|
190
|
+
|
|
191
|
+
PLATFORM_FATAL_CHECKS: `- Strong self reference in closures causing retain cycles
|
|
192
|
+
- UI operations executed on background thread
|
|
193
|
+
- Force unwrapping (\`!\`) without nil check
|
|
194
|
+
- UI operations missing \`@MainActor\` annotation
|
|
195
|
+
- Using private APIs (App Store review rejection)
|
|
196
|
+
- delegate not declared as \`weak\``,
|
|
197
|
+
|
|
198
|
+
PLATFORM_WARNING_CHECKS: `- Using \`String(format:)\` instead of \`LocalizedStringKey\`
|
|
199
|
+
- UI tests missing \`accessibilityIdentifier\`
|
|
200
|
+
- Using \`DispatchQueue.main.async\` instead of \`@MainActor\`
|
|
201
|
+
- Force cast (\`as!\`) without safety check
|
|
202
|
+
- \`@StateObject\` vs \`@ObservedObject\` used in wrong context`,
|
|
203
|
+
|
|
204
|
+
PLATFORM_SUGGESTION_CHECKS: `- Use \`weak self\` in closures (even when not strictly required)
|
|
205
|
+
- Use \`Result\` type instead of optional error patterns
|
|
206
|
+
- Use \`async/await\` over completion handlers
|
|
207
|
+
- Prefer SwiftUI over UIKit for new views
|
|
208
|
+
- Use \`ViewModifier\` for style reuse instead of copying code`,
|
|
209
|
+
|
|
210
|
+
PLATFORM_SELF_CHECK_ITEMS: `| iOS1 | Closures capture self with weak/unowned? |
|
|
211
|
+
| iOS2 | UI updates on main thread (@MainActor)? |
|
|
212
|
+
| iOS3 | No force unwrapping (!) or nil-checked? |
|
|
213
|
+
| iOS4 | Privacy manifest PrivacyInfo.xcprivacy configured? |
|
|
214
|
+
| iOS5 | accessibilityIdentifier set (for UI testing)? |
|
|
215
|
+
| iOS6 | Async operations use async/await? |
|
|
216
|
+
| iOS7 | delegate declared as weak reference? |
|
|
217
|
+
| iOS8 | Info.plist permission descriptions configured? |`,
|
|
218
|
+
|
|
219
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### iOS Resource Sync Checks
|
|
220
|
+
|
|
221
|
+
- \`Assets.xcassets\` image resource completeness
|
|
222
|
+
- \`Localizable.strings\` coverage for all supported languages
|
|
223
|
+
- Launch Screen configuration correct
|
|
224
|
+
- App Icon sizes complete
|
|
225
|
+
- Privacy manifest \`PrivacyInfo.xcprivacy\` fully configured
|
|
226
|
+
- Info.plist permission descriptions complete`,
|
|
227
|
+
|
|
228
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### iOS Task Templates
|
|
229
|
+
|
|
230
|
+
**Add new SwiftUI screen**:
|
|
231
|
+
1. Create SwiftUI View
|
|
232
|
+
2. Create corresponding ViewModel (ObservableObject)
|
|
233
|
+
3. Configure routing (NavigationLink / Router)
|
|
234
|
+
4. Add necessary state bindings
|
|
235
|
+
|
|
236
|
+
**Add network layer**:
|
|
237
|
+
1. Define API interface (URLSession + async/await)
|
|
238
|
+
2. Create Codable data models
|
|
239
|
+
3. Implement error handling (custom Error type)
|
|
240
|
+
4. Integrate in ViewModel
|
|
241
|
+
|
|
242
|
+
**Add CoreData entity**:
|
|
243
|
+
1. Define Entity in .xcdatamodeld
|
|
244
|
+
2. Generate NSManagedObject subclass
|
|
245
|
+
3. Create Core Data Stack configuration
|
|
246
|
+
4. Implement CRUD operations`,
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export default function getPlatformVars(lang) {
|
|
251
|
+
return strings[lang] || strings.en;
|
|
252
|
+
}
|