code-abyss 1.6.16 → 1.7.0
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/package.json +2 -2
- package/skills/SKILL.md +24 -16
- package/skills/domains/ai/SKILL.md +2 -2
- package/skills/domains/ai/prompt-and-eval.md +279 -0
- package/skills/domains/architecture/SKILL.md +2 -3
- package/skills/domains/architecture/security-arch.md +87 -0
- package/skills/domains/data-engineering/SKILL.md +188 -26
- package/skills/domains/development/SKILL.md +1 -4
- package/skills/domains/devops/SKILL.md +3 -5
- package/skills/domains/devops/performance.md +63 -0
- package/skills/domains/devops/testing.md +97 -0
- package/skills/domains/frontend-design/SKILL.md +12 -3
- package/skills/domains/frontend-design/claymorphism/SKILL.md +117 -0
- package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/skills/domains/frontend-design/engineering.md +287 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +138 -0
- package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +135 -0
- package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +141 -0
- package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/skills/domains/infrastructure/SKILL.md +174 -34
- package/skills/domains/mobile/SKILL.md +211 -21
- package/skills/domains/orchestration/SKILL.md +1 -0
- package/skills/domains/security/SKILL.md +4 -6
- package/skills/domains/security/blue-team.md +57 -0
- package/skills/domains/security/red-team.md +54 -0
- package/skills/domains/security/threat-intel.md +50 -0
- package/skills/orchestration/multi-agent/SKILL.md +195 -46
- package/skills/run_skill.js +134 -0
- package/skills/tools/gen-docs/SKILL.md +6 -4
- package/skills/tools/gen-docs/scripts/doc_generator.js +349 -0
- package/skills/tools/verify-change/SKILL.md +8 -6
- package/skills/tools/verify-change/scripts/change_analyzer.js +270 -0
- package/skills/tools/verify-module/SKILL.md +6 -4
- package/skills/tools/verify-module/scripts/module_scanner.js +145 -0
- package/skills/tools/verify-quality/SKILL.md +5 -3
- package/skills/tools/verify-quality/scripts/quality_checker.js +276 -0
- package/skills/tools/verify-security/SKILL.md +7 -5
- package/skills/tools/verify-security/scripts/security_scanner.js +133 -0
- package/skills/__pycache__/run_skill.cpython-312.pyc +0 -0
- package/skills/domains/COVERAGE_PLAN.md +0 -232
- package/skills/domains/ai/model-evaluation.md +0 -790
- package/skills/domains/ai/prompt-engineering.md +0 -703
- package/skills/domains/architecture/compliance.md +0 -299
- package/skills/domains/architecture/data-security.md +0 -184
- package/skills/domains/data-engineering/data-pipeline.md +0 -762
- package/skills/domains/data-engineering/data-quality.md +0 -894
- package/skills/domains/data-engineering/stream-processing.md +0 -791
- package/skills/domains/development/dart.md +0 -963
- package/skills/domains/development/kotlin.md +0 -834
- package/skills/domains/development/php.md +0 -659
- package/skills/domains/development/swift.md +0 -755
- package/skills/domains/devops/e2e-testing.md +0 -914
- package/skills/domains/devops/performance-testing.md +0 -734
- package/skills/domains/devops/testing-strategy.md +0 -667
- package/skills/domains/frontend-design/build-tools.md +0 -743
- package/skills/domains/frontend-design/performance.md +0 -734
- package/skills/domains/frontend-design/testing.md +0 -699
- package/skills/domains/infrastructure/gitops.md +0 -735
- package/skills/domains/infrastructure/iac.md +0 -855
- package/skills/domains/infrastructure/kubernetes.md +0 -1018
- package/skills/domains/mobile/android-dev.md +0 -979
- package/skills/domains/mobile/cross-platform.md +0 -795
- package/skills/domains/mobile/ios-dev.md +0 -931
- package/skills/domains/security/secrets-management.md +0 -834
- package/skills/domains/security/supply-chain.md +0 -931
- package/skills/domains/security/threat-modeling.md +0 -828
- package/skills/run_skill.py +0 -153
- package/skills/tests/README.md +0 -225
- package/skills/tests/SUMMARY.md +0 -362
- package/skills/tests/__init__.py +0 -3
- package/skills/tests/__pycache__/test_change_analyzer.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_doc_generator.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_module_scanner.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_quality_checker.cpython-312.pyc +0 -0
- package/skills/tests/__pycache__/test_security_scanner.cpython-312.pyc +0 -0
- package/skills/tests/test_change_analyzer.py +0 -558
- package/skills/tests/test_doc_generator.py +0 -538
- package/skills/tests/test_module_scanner.py +0 -376
- package/skills/tests/test_quality_checker.py +0 -516
- package/skills/tests/test_security_scanner.py +0 -426
- package/skills/tools/gen-docs/scripts/__pycache__/doc_generator.cpython-312.pyc +0 -0
- package/skills/tools/gen-docs/scripts/doc_generator.py +0 -520
- package/skills/tools/verify-change/scripts/__pycache__/change_analyzer.cpython-312.pyc +0 -0
- package/skills/tools/verify-change/scripts/change_analyzer.py +0 -529
- package/skills/tools/verify-module/scripts/__pycache__/module_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-module/scripts/module_scanner.py +0 -321
- package/skills/tools/verify-quality/scripts/__pycache__/quality_checker.cpython-312.pyc +0 -0
- package/skills/tools/verify-quality/scripts/quality_checker.py +0 -481
- package/skills/tools/verify-security/scripts/__pycache__/security_scanner.cpython-312.pyc +0 -0
- package/skills/tools/verify-security/scripts/security_scanner.py +0 -374
|
@@ -1,795 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: cross-platform
|
|
3
|
-
description: 跨平台移动开发。React Native、Flutter、性能对比、原生模块桥接、状态管理。当用户提到跨平台、React Native、Flutter、混合开发时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 🌉 跨平台开发 · Cross-Platform Development
|
|
7
|
-
|
|
8
|
-
## 框架对比
|
|
9
|
-
|
|
10
|
-
### React Native vs Flutter
|
|
11
|
-
|
|
12
|
-
| 维度 | React Native | Flutter |
|
|
13
|
-
|------|--------------|---------|
|
|
14
|
-
| 语言 | JavaScript/TypeScript | Dart |
|
|
15
|
-
| 渲染 | 原生组件 | 自绘引擎 (Skia) |
|
|
16
|
-
| 性能 | 接近原生 (桥接开销) | 接近原生 (直接编译) |
|
|
17
|
-
| 热重载 | ✅ Fast Refresh | ✅ Hot Reload |
|
|
18
|
-
| 生态 | 成熟 (npm) | 快速增长 (pub.dev) |
|
|
19
|
-
| 学习曲线 | 低 (Web 开发者友好) | 中 (需学 Dart) |
|
|
20
|
-
| UI 一致性 | 跟随系统 | 完全一致 |
|
|
21
|
-
| 包体积 | 较小 (~7MB) | 较大 (~15MB) |
|
|
22
|
-
| 社区 | Meta + 社区 | Google + 社区 |
|
|
23
|
-
|
|
24
|
-
### 性能对比
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
启动时间 (冷启动)
|
|
28
|
-
Flutter: ~800ms
|
|
29
|
-
RN: ~1200ms
|
|
30
|
-
Native: ~600ms
|
|
31
|
-
|
|
32
|
-
渲染性能 (60fps)
|
|
33
|
-
Flutter: 58-60fps (自绘)
|
|
34
|
-
RN: 55-60fps (桥接)
|
|
35
|
-
Native: 60fps
|
|
36
|
-
|
|
37
|
-
内存占用
|
|
38
|
-
Flutter: ~50MB
|
|
39
|
-
RN: ~60MB
|
|
40
|
-
Native: ~30MB
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## React Native
|
|
44
|
-
|
|
45
|
-
### 基础组件
|
|
46
|
-
```typescript
|
|
47
|
-
import React, { useState } from 'react';
|
|
48
|
-
import { View, Text, Button, StyleSheet, FlatList } from 'react-native';
|
|
49
|
-
|
|
50
|
-
interface User {
|
|
51
|
-
id: number;
|
|
52
|
-
name: string;
|
|
53
|
-
email: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const UserList: React.FC = () => {
|
|
57
|
-
const [users, setUsers] = useState<User[]>([]);
|
|
58
|
-
const [loading, setLoading] = useState(false);
|
|
59
|
-
|
|
60
|
-
const loadUsers = async () => {
|
|
61
|
-
setLoading(true);
|
|
62
|
-
try {
|
|
63
|
-
const response = await fetch('https://api.example.com/users');
|
|
64
|
-
const data = await response.json();
|
|
65
|
-
setUsers(data);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error(error);
|
|
68
|
-
} finally {
|
|
69
|
-
setLoading(false);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<View style={styles.container}>
|
|
75
|
-
<Button title="Load Users" onPress={loadUsers} />
|
|
76
|
-
|
|
77
|
-
<FlatList
|
|
78
|
-
data={users}
|
|
79
|
-
keyExtractor={(item) => item.id.toString()}
|
|
80
|
-
renderItem={({ item }) => (
|
|
81
|
-
<View style={styles.item}>
|
|
82
|
-
<Text style={styles.name}>{item.name}</Text>
|
|
83
|
-
<Text style={styles.email}>{item.email}</Text>
|
|
84
|
-
</View>
|
|
85
|
-
)}
|
|
86
|
-
/>
|
|
87
|
-
</View>
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const styles = StyleSheet.create({
|
|
92
|
-
container: {
|
|
93
|
-
flex: 1,
|
|
94
|
-
padding: 16,
|
|
95
|
-
},
|
|
96
|
-
item: {
|
|
97
|
-
padding: 16,
|
|
98
|
-
borderBottomWidth: 1,
|
|
99
|
-
borderBottomColor: '#ccc',
|
|
100
|
-
},
|
|
101
|
-
name: {
|
|
102
|
-
fontSize: 18,
|
|
103
|
-
fontWeight: 'bold',
|
|
104
|
-
},
|
|
105
|
-
email: {
|
|
106
|
-
fontSize: 14,
|
|
107
|
-
color: '#666',
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Hooks
|
|
113
|
-
```typescript
|
|
114
|
-
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
115
|
-
|
|
116
|
-
const UserScreen: React.FC = () => {
|
|
117
|
-
const [users, setUsers] = useState<User[]>([]);
|
|
118
|
-
const [filter, setFilter] = useState('');
|
|
119
|
-
|
|
120
|
-
// useEffect: 副作用
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
loadUsers();
|
|
123
|
-
}, []);
|
|
124
|
-
|
|
125
|
-
// useCallback: 缓存函数
|
|
126
|
-
const loadUsers = useCallback(async () => {
|
|
127
|
-
const data = await fetchUsers();
|
|
128
|
-
setUsers(data);
|
|
129
|
-
}, []);
|
|
130
|
-
|
|
131
|
-
// useMemo: 缓存计算结果
|
|
132
|
-
const filteredUsers = useMemo(() => {
|
|
133
|
-
return users.filter(u =>
|
|
134
|
-
u.name.toLowerCase().includes(filter.toLowerCase())
|
|
135
|
-
);
|
|
136
|
-
}, [users, filter]);
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<View>
|
|
140
|
-
<TextInput
|
|
141
|
-
value={filter}
|
|
142
|
-
onChangeText={setFilter}
|
|
143
|
-
placeholder="Search..."
|
|
144
|
-
/>
|
|
145
|
-
<FlatList data={filteredUsers} {...} />
|
|
146
|
-
</View>
|
|
147
|
-
);
|
|
148
|
-
};
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Navigation
|
|
152
|
-
```typescript
|
|
153
|
-
import { NavigationContainer } from '@react-navigation/native';
|
|
154
|
-
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
155
|
-
|
|
156
|
-
type RootStackParamList = {
|
|
157
|
-
Home: undefined;
|
|
158
|
-
Detail: { userId: number };
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const Stack = createNativeStackNavigator<RootStackParamList>();
|
|
162
|
-
|
|
163
|
-
const App: React.FC = () => {
|
|
164
|
-
return (
|
|
165
|
-
<NavigationContainer>
|
|
166
|
-
<Stack.Navigator>
|
|
167
|
-
<Stack.Screen
|
|
168
|
-
name="Home"
|
|
169
|
-
component={HomeScreen}
|
|
170
|
-
/>
|
|
171
|
-
<Stack.Screen
|
|
172
|
-
name="Detail"
|
|
173
|
-
component={DetailScreen}
|
|
174
|
-
/>
|
|
175
|
-
</Stack.Navigator>
|
|
176
|
-
</NavigationContainer>
|
|
177
|
-
);
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
// 使用
|
|
181
|
-
const HomeScreen: React.FC<NativeStackScreenProps<RootStackParamList, 'Home'>> = ({ navigation }) => {
|
|
182
|
-
return (
|
|
183
|
-
<Button
|
|
184
|
-
title="Go to Detail"
|
|
185
|
-
onPress={() => navigation.navigate('Detail', { userId: 1 })}
|
|
186
|
-
/>
|
|
187
|
-
);
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const DetailScreen: React.FC<NativeStackScreenProps<RootStackParamList, 'Detail'>> = ({ route }) => {
|
|
191
|
-
const { userId } = route.params;
|
|
192
|
-
return <Text>User ID: {userId}</Text>;
|
|
193
|
-
};
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### 状态管理 (Redux Toolkit)
|
|
197
|
-
```typescript
|
|
198
|
-
import { createSlice, createAsyncThunk, configureStore } from '@reduxjs/toolkit';
|
|
199
|
-
|
|
200
|
-
// Async Thunk
|
|
201
|
-
export const fetchUsers = createAsyncThunk(
|
|
202
|
-
'users/fetch',
|
|
203
|
-
async () => {
|
|
204
|
-
const response = await fetch('https://api.example.com/users');
|
|
205
|
-
return response.json();
|
|
206
|
-
}
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Slice
|
|
210
|
-
const userSlice = createSlice({
|
|
211
|
-
name: 'users',
|
|
212
|
-
initialState: {
|
|
213
|
-
items: [] as User[],
|
|
214
|
-
loading: false,
|
|
215
|
-
error: null as string | null,
|
|
216
|
-
},
|
|
217
|
-
reducers: {
|
|
218
|
-
addUser: (state, action) => {
|
|
219
|
-
state.items.push(action.payload);
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
extraReducers: (builder) => {
|
|
223
|
-
builder
|
|
224
|
-
.addCase(fetchUsers.pending, (state) => {
|
|
225
|
-
state.loading = true;
|
|
226
|
-
})
|
|
227
|
-
.addCase(fetchUsers.fulfilled, (state, action) => {
|
|
228
|
-
state.loading = false;
|
|
229
|
-
state.items = action.payload;
|
|
230
|
-
})
|
|
231
|
-
.addCase(fetchUsers.rejected, (state, action) => {
|
|
232
|
-
state.loading = false;
|
|
233
|
-
state.error = action.error.message || 'Failed';
|
|
234
|
-
});
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
export const { addUser } = userSlice.actions;
|
|
239
|
-
|
|
240
|
-
// Store
|
|
241
|
-
export const store = configureStore({
|
|
242
|
-
reducer: {
|
|
243
|
-
users: userSlice.reducer,
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// 使用
|
|
248
|
-
import { useDispatch, useSelector } from 'react-redux';
|
|
249
|
-
|
|
250
|
-
const UserList: React.FC = () => {
|
|
251
|
-
const dispatch = useDispatch();
|
|
252
|
-
const { items, loading } = useSelector((state: RootState) => state.users);
|
|
253
|
-
|
|
254
|
-
useEffect(() => {
|
|
255
|
-
dispatch(fetchUsers());
|
|
256
|
-
}, []);
|
|
257
|
-
|
|
258
|
-
return <FlatList data={items} {...} />;
|
|
259
|
-
};
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### 原生模块桥接
|
|
263
|
-
```typescript
|
|
264
|
-
// NativeModules (调用原生代码)
|
|
265
|
-
import { NativeModules } from 'react-native';
|
|
266
|
-
|
|
267
|
-
const { BiometricAuth } = NativeModules;
|
|
268
|
-
|
|
269
|
-
const authenticate = async () => {
|
|
270
|
-
try {
|
|
271
|
-
const result = await BiometricAuth.authenticate('Unlock App');
|
|
272
|
-
console.log('Auth success:', result);
|
|
273
|
-
} catch (error) {
|
|
274
|
-
console.error('Auth failed:', error);
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
// iOS (Swift)
|
|
279
|
-
@objc(BiometricAuth)
|
|
280
|
-
class BiometricAuth: NSObject {
|
|
281
|
-
@objc
|
|
282
|
-
func authenticate(_ reason: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
283
|
-
let context = LAContext()
|
|
284
|
-
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in
|
|
285
|
-
if success {
|
|
286
|
-
resolver(["success": true])
|
|
287
|
-
} else {
|
|
288
|
-
rejecter("AUTH_FAILED", error?.localizedDescription, error)
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Android (Kotlin)
|
|
295
|
-
class BiometricAuthModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
296
|
-
override fun getName() = "BiometricAuth"
|
|
297
|
-
|
|
298
|
-
@ReactMethod
|
|
299
|
-
fun authenticate(reason: String, promise: Promise) {
|
|
300
|
-
val executor = ContextCompat.getMainExecutor(reactApplicationContext)
|
|
301
|
-
val biometricPrompt = BiometricPrompt(currentActivity!!, executor,
|
|
302
|
-
object : BiometricPrompt.AuthenticationCallback() {
|
|
303
|
-
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
|
304
|
-
promise.resolve(mapOf("success" to true))
|
|
305
|
-
}
|
|
306
|
-
override fun onAuthenticationFailed() {
|
|
307
|
-
promise.reject("AUTH_FAILED", "Authentication failed")
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
|
313
|
-
.setTitle(reason)
|
|
314
|
-
.setNegativeButtonText("Cancel")
|
|
315
|
-
.build()
|
|
316
|
-
|
|
317
|
-
biometricPrompt.authenticate(promptInfo)
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## Flutter
|
|
323
|
-
|
|
324
|
-
### Widget 基础
|
|
325
|
-
```dart
|
|
326
|
-
import 'package:flutter/material.dart';
|
|
327
|
-
|
|
328
|
-
class UserList extends StatefulWidget {
|
|
329
|
-
@override
|
|
330
|
-
_UserListState createState() => _UserListState();
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
class _UserListState extends State<UserList> {
|
|
334
|
-
List<User> users = [];
|
|
335
|
-
bool loading = false;
|
|
336
|
-
|
|
337
|
-
@override
|
|
338
|
-
void initState() {
|
|
339
|
-
super.initState();
|
|
340
|
-
loadUsers();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
Future<void> loadUsers() async {
|
|
344
|
-
setState(() => loading = true);
|
|
345
|
-
try {
|
|
346
|
-
final response = await http.get(Uri.parse('https://api.example.com/users'));
|
|
347
|
-
final data = jsonDecode(response.body) as List;
|
|
348
|
-
setState(() {
|
|
349
|
-
users = data.map((json) => User.fromJson(json)).toList();
|
|
350
|
-
});
|
|
351
|
-
} catch (e) {
|
|
352
|
-
print('Error: $e');
|
|
353
|
-
} finally {
|
|
354
|
-
setState(() => loading = false);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
@override
|
|
359
|
-
Widget build(BuildContext context) {
|
|
360
|
-
return Scaffold(
|
|
361
|
-
appBar: AppBar(title: Text('Users')),
|
|
362
|
-
body: loading
|
|
363
|
-
? Center(child: CircularProgressIndicator())
|
|
364
|
-
: ListView.builder(
|
|
365
|
-
itemCount: users.length,
|
|
366
|
-
itemBuilder: (context, index) {
|
|
367
|
-
final user = users[index];
|
|
368
|
-
return ListTile(
|
|
369
|
-
title: Text(user.name),
|
|
370
|
-
subtitle: Text(user.email),
|
|
371
|
-
);
|
|
372
|
-
},
|
|
373
|
-
),
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### Provider 状态管理
|
|
380
|
-
```dart
|
|
381
|
-
import 'package:provider/provider.dart';
|
|
382
|
-
|
|
383
|
-
// Model
|
|
384
|
-
class UserProvider extends ChangeNotifier {
|
|
385
|
-
List<User> _users = [];
|
|
386
|
-
bool _loading = false;
|
|
387
|
-
String? _error;
|
|
388
|
-
|
|
389
|
-
List<User> get users => _users;
|
|
390
|
-
bool get loading => _loading;
|
|
391
|
-
String? get error => _error;
|
|
392
|
-
|
|
393
|
-
Future<void> loadUsers() async {
|
|
394
|
-
_loading = true;
|
|
395
|
-
_error = null;
|
|
396
|
-
notifyListeners();
|
|
397
|
-
|
|
398
|
-
try {
|
|
399
|
-
final response = await http.get(Uri.parse('https://api.example.com/users'));
|
|
400
|
-
final data = jsonDecode(response.body) as List;
|
|
401
|
-
_users = data.map((json) => User.fromJson(json)).toList();
|
|
402
|
-
} catch (e) {
|
|
403
|
-
_error = e.toString();
|
|
404
|
-
} finally {
|
|
405
|
-
_loading = false;
|
|
406
|
-
notifyListeners();
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// 注册
|
|
412
|
-
void main() {
|
|
413
|
-
runApp(
|
|
414
|
-
MultiProvider(
|
|
415
|
-
providers: [
|
|
416
|
-
ChangeNotifierProvider(create: (_) => UserProvider()),
|
|
417
|
-
],
|
|
418
|
-
child: MyApp(),
|
|
419
|
-
),
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// 使用
|
|
424
|
-
class UserList extends StatelessWidget {
|
|
425
|
-
@override
|
|
426
|
-
Widget build(BuildContext context) {
|
|
427
|
-
return Consumer<UserProvider>(
|
|
428
|
-
builder: (context, provider, child) {
|
|
429
|
-
if (provider.loading) {
|
|
430
|
-
return Center(child: CircularProgressIndicator());
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (provider.error != null) {
|
|
434
|
-
return Center(child: Text('Error: ${provider.error}'));
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return ListView.builder(
|
|
438
|
-
itemCount: provider.users.length,
|
|
439
|
-
itemBuilder: (context, index) {
|
|
440
|
-
final user = provider.users[index];
|
|
441
|
-
return ListTile(
|
|
442
|
-
title: Text(user.name),
|
|
443
|
-
subtitle: Text(user.email),
|
|
444
|
-
);
|
|
445
|
-
},
|
|
446
|
-
);
|
|
447
|
-
},
|
|
448
|
-
);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Riverpod (推荐)
|
|
454
|
-
```dart
|
|
455
|
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
456
|
-
|
|
457
|
-
// Provider
|
|
458
|
-
final userRepositoryProvider = Provider((ref) => UserRepository());
|
|
459
|
-
|
|
460
|
-
final usersProvider = FutureProvider<List<User>>((ref) async {
|
|
461
|
-
final repository = ref.watch(userRepositoryProvider);
|
|
462
|
-
return repository.getUsers();
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
// 使用
|
|
466
|
-
class UserList extends ConsumerWidget {
|
|
467
|
-
@override
|
|
468
|
-
Widget build(BuildContext context, WidgetRef ref) {
|
|
469
|
-
final usersAsync = ref.watch(usersProvider);
|
|
470
|
-
|
|
471
|
-
return usersAsync.when(
|
|
472
|
-
data: (users) => ListView.builder(
|
|
473
|
-
itemCount: users.length,
|
|
474
|
-
itemBuilder: (context, index) {
|
|
475
|
-
return ListTile(title: Text(users[index].name));
|
|
476
|
-
},
|
|
477
|
-
),
|
|
478
|
-
loading: () => Center(child: CircularProgressIndicator()),
|
|
479
|
-
error: (error, stack) => Center(child: Text('Error: $error')),
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// StateNotifier (复杂状态)
|
|
485
|
-
class UserNotifier extends StateNotifier<AsyncValue<List<User>>> {
|
|
486
|
-
UserNotifier(this.repository) : super(const AsyncValue.loading()) {
|
|
487
|
-
loadUsers();
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
final UserRepository repository;
|
|
491
|
-
|
|
492
|
-
Future<void> loadUsers() async {
|
|
493
|
-
state = const AsyncValue.loading();
|
|
494
|
-
state = await AsyncValue.guard(() => repository.getUsers());
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
Future<void> refresh() async {
|
|
498
|
-
loadUsers();
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
final userNotifierProvider = StateNotifierProvider<UserNotifier, AsyncValue<List<User>>>((ref) {
|
|
503
|
-
return UserNotifier(ref.watch(userRepositoryProvider));
|
|
504
|
-
});
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
### Navigation
|
|
508
|
-
```dart
|
|
509
|
-
import 'package:go_router/go_router.dart';
|
|
510
|
-
|
|
511
|
-
final router = GoRouter(
|
|
512
|
-
routes: [
|
|
513
|
-
GoRoute(
|
|
514
|
-
path: '/',
|
|
515
|
-
builder: (context, state) => HomeScreen(),
|
|
516
|
-
),
|
|
517
|
-
GoRoute(
|
|
518
|
-
path: '/detail/:id',
|
|
519
|
-
builder: (context, state) {
|
|
520
|
-
final id = state.pathParameters['id']!;
|
|
521
|
-
return DetailScreen(userId: int.parse(id));
|
|
522
|
-
},
|
|
523
|
-
),
|
|
524
|
-
],
|
|
525
|
-
);
|
|
526
|
-
|
|
527
|
-
void main() {
|
|
528
|
-
runApp(MaterialApp.router(
|
|
529
|
-
routerConfig: router,
|
|
530
|
-
));
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// 使用
|
|
534
|
-
context.go('/detail/123');
|
|
535
|
-
context.push('/detail/123');
|
|
536
|
-
context.pop();
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
### Platform Channels (原生桥接)
|
|
540
|
-
```dart
|
|
541
|
-
// Flutter 端
|
|
542
|
-
import 'package:flutter/services.dart';
|
|
543
|
-
|
|
544
|
-
class BiometricAuth {
|
|
545
|
-
static const platform = MethodChannel('com.example.app/biometric');
|
|
546
|
-
|
|
547
|
-
static Future<bool> authenticate(String reason) async {
|
|
548
|
-
try {
|
|
549
|
-
final result = await platform.invokeMethod('authenticate', {'reason': reason});
|
|
550
|
-
return result['success'] as bool;
|
|
551
|
-
} on PlatformException catch (e) {
|
|
552
|
-
print('Error: ${e.message}');
|
|
553
|
-
return false;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// iOS (Swift)
|
|
559
|
-
class BiometricAuthPlugin: NSObject, FlutterPlugin {
|
|
560
|
-
static func register(with registrar: FlutterPluginRegistrar) {
|
|
561
|
-
let channel = FlutterMethodChannel(name: "com.example.app/biometric", binaryMessenger: registrar.messenger())
|
|
562
|
-
let instance = BiometricAuthPlugin()
|
|
563
|
-
registrar.addMethodCallDelegate(instance, channel: channel)
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
|
567
|
-
if call.method == "authenticate" {
|
|
568
|
-
let args = call.arguments as! [String: Any]
|
|
569
|
-
let reason = args["reason"] as! String
|
|
570
|
-
|
|
571
|
-
let context = LAContext()
|
|
572
|
-
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in
|
|
573
|
-
DispatchQueue.main.async {
|
|
574
|
-
result(["success": success])
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Android (Kotlin)
|
|
582
|
-
class BiometricAuthPlugin: FlutterPlugin, MethodCallHandler {
|
|
583
|
-
private lateinit var channel: MethodChannel
|
|
584
|
-
|
|
585
|
-
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
|
586
|
-
channel = MethodChannel(binding.binaryMessenger, "com.example.app/biometric")
|
|
587
|
-
channel.setMethodCallHandler(this)
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
override fun onMethodCall(call: MethodCall, result: Result) {
|
|
591
|
-
if (call.method == "authenticate") {
|
|
592
|
-
val reason = call.argument<String>("reason")!!
|
|
593
|
-
// BiometricPrompt 实现...
|
|
594
|
-
result.success(mapOf("success" to true))
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
## 架构对比
|
|
601
|
-
|
|
602
|
-
### React Native 架构
|
|
603
|
-
```
|
|
604
|
-
JavaScript Thread
|
|
605
|
-
↓
|
|
606
|
-
Bridge (JSON)
|
|
607
|
-
↓
|
|
608
|
-
Native Thread (iOS/Android)
|
|
609
|
-
↓
|
|
610
|
-
UI Rendering
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
### Flutter 架构
|
|
614
|
-
```
|
|
615
|
-
Dart Code
|
|
616
|
-
↓
|
|
617
|
-
Dart VM / AOT
|
|
618
|
-
↓
|
|
619
|
-
Skia Engine
|
|
620
|
-
↓
|
|
621
|
-
Platform (OpenGL/Metal/Vulkan)
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
### 新架构 (React Native 0.68+)
|
|
625
|
-
```
|
|
626
|
-
JavaScript
|
|
627
|
-
↓
|
|
628
|
-
JSI (JavaScript Interface)
|
|
629
|
-
↓
|
|
630
|
-
C++ Turbo Modules
|
|
631
|
-
↓
|
|
632
|
-
Native (直接调用,无序列化)
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
## 性能优化
|
|
636
|
-
|
|
637
|
-
### React Native
|
|
638
|
-
```typescript
|
|
639
|
-
// 1. 使用 memo 避免重渲染
|
|
640
|
-
const UserItem = React.memo<{ user: User }>(({ user }) => {
|
|
641
|
-
return (
|
|
642
|
-
<View>
|
|
643
|
-
<Text>{user.name}</Text>
|
|
644
|
-
</View>
|
|
645
|
-
);
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
// 2. FlatList 优化
|
|
649
|
-
<FlatList
|
|
650
|
-
data={users}
|
|
651
|
-
renderItem={({ item }) => <UserItem user={item} />}
|
|
652
|
-
keyExtractor={(item) => item.id.toString()}
|
|
653
|
-
initialNumToRender={10}
|
|
654
|
-
maxToRenderPerBatch={10}
|
|
655
|
-
windowSize={5}
|
|
656
|
-
removeClippedSubviews={true}
|
|
657
|
-
getItemLayout={(data, index) => ({
|
|
658
|
-
length: ITEM_HEIGHT,
|
|
659
|
-
offset: ITEM_HEIGHT * index,
|
|
660
|
-
index,
|
|
661
|
-
})}
|
|
662
|
-
/>
|
|
663
|
-
|
|
664
|
-
// 3. 使用 Hermes 引擎
|
|
665
|
-
// android/app/build.gradle
|
|
666
|
-
project.ext.react = [
|
|
667
|
-
enableHermes: true
|
|
668
|
-
]
|
|
669
|
-
|
|
670
|
-
// 4. 图片优化
|
|
671
|
-
<Image
|
|
672
|
-
source={{ uri: url }}
|
|
673
|
-
resizeMode="cover"
|
|
674
|
-
style={{ width: 200, height: 200 }}
|
|
675
|
-
/>
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
### Flutter
|
|
679
|
-
```dart
|
|
680
|
-
// 1. const 构造函数
|
|
681
|
-
const Text('Hello'); // 编译时常量,不会重建
|
|
682
|
-
|
|
683
|
-
// 2. ListView.builder (懒加载)
|
|
684
|
-
ListView.builder(
|
|
685
|
-
itemCount: items.length,
|
|
686
|
-
itemBuilder: (context, index) {
|
|
687
|
-
return ItemWidget(items[index]);
|
|
688
|
-
},
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
// 3. RepaintBoundary (隔离重绘)
|
|
692
|
-
RepaintBoundary(
|
|
693
|
-
child: ExpensiveWidget(),
|
|
694
|
-
);
|
|
695
|
-
|
|
696
|
-
// 4. 缓存图片
|
|
697
|
-
CachedNetworkImage(
|
|
698
|
-
imageUrl: url,
|
|
699
|
-
placeholder: (context, url) => CircularProgressIndicator(),
|
|
700
|
-
errorWidget: (context, url, error) => Icon(Icons.error),
|
|
701
|
-
);
|
|
702
|
-
|
|
703
|
-
// 5. 使用 Keys
|
|
704
|
-
ListView.builder(
|
|
705
|
-
itemBuilder: (context, index) {
|
|
706
|
-
return ItemWidget(
|
|
707
|
-
key: ValueKey(items[index].id),
|
|
708
|
-
item: items[index],
|
|
709
|
-
);
|
|
710
|
-
},
|
|
711
|
-
);
|
|
712
|
-
```
|
|
713
|
-
|
|
714
|
-
## 包体积优化
|
|
715
|
-
|
|
716
|
-
### React Native
|
|
717
|
-
```bash
|
|
718
|
-
# Android
|
|
719
|
-
# 启用 Proguard
|
|
720
|
-
android {
|
|
721
|
-
buildTypes {
|
|
722
|
-
release {
|
|
723
|
-
minifyEnabled true
|
|
724
|
-
shrinkResources true
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
# 分包 (App Bundle)
|
|
730
|
-
./gradlew bundleRelease
|
|
731
|
-
|
|
732
|
-
# iOS
|
|
733
|
-
# 启用 Bitcode
|
|
734
|
-
ENABLE_BITCODE = YES
|
|
735
|
-
```
|
|
736
|
-
|
|
737
|
-
### Flutter
|
|
738
|
-
```bash
|
|
739
|
-
# 分析包体积
|
|
740
|
-
flutter build apk --analyze-size
|
|
741
|
-
flutter build ios --analyze-size
|
|
742
|
-
|
|
743
|
-
# 移除未使用资源
|
|
744
|
-
flutter build apk --tree-shake-icons
|
|
745
|
-
|
|
746
|
-
# 分架构打包
|
|
747
|
-
flutter build apk --split-per-abi
|
|
748
|
-
```
|
|
749
|
-
|
|
750
|
-
## 选型建议
|
|
751
|
-
|
|
752
|
-
| 场景 | 推荐 | 理由 |
|
|
753
|
-
|------|------|------|
|
|
754
|
-
| 团队有 Web 背景 | React Native | 学习成本低 |
|
|
755
|
-
| 追求极致性能 | Flutter | 自绘引擎,性能稳定 |
|
|
756
|
-
| UI 高度定制 | Flutter | 完全控制渲染 |
|
|
757
|
-
| 快速原型 | React Native | 生态成熟,库丰富 |
|
|
758
|
-
| 复杂动画 | Flutter | 60fps 保证 |
|
|
759
|
-
| 需要大量原生交互 | React Native | 桥接成熟 |
|
|
760
|
-
| 长期维护 | Flutter | Google 官方支持 |
|
|
761
|
-
|
|
762
|
-
## 工具清单
|
|
763
|
-
|
|
764
|
-
| 工具 | React Native | Flutter |
|
|
765
|
-
|------|--------------|---------|
|
|
766
|
-
| IDE | VS Code / WebStorm | Android Studio / VS Code |
|
|
767
|
-
| 调试 | Flipper / React DevTools | Flutter DevTools |
|
|
768
|
-
| 状态管理 | Redux / MobX / Zustand | Provider / Riverpod / Bloc |
|
|
769
|
-
| 导航 | React Navigation | go_router |
|
|
770
|
-
| 网络 | Axios / Fetch | http / dio |
|
|
771
|
-
| 存储 | AsyncStorage / MMKV | shared_preferences / Hive |
|
|
772
|
-
| 图片 | react-native-fast-image | cached_network_image |
|
|
773
|
-
| 测试 | Jest / Detox | flutter_test / integration_test |
|
|
774
|
-
|
|
775
|
-
## 最佳实践
|
|
776
|
-
|
|
777
|
-
### React Native
|
|
778
|
-
- ✅ 使用 TypeScript 提升类型安全
|
|
779
|
-
- ✅ Hermes 引擎提升性能
|
|
780
|
-
- ✅ FlatList 替代 ScrollView
|
|
781
|
-
- ✅ memo/useMemo/useCallback 优化渲染
|
|
782
|
-
- ✅ 新架构 (JSI) 减少桥接开销
|
|
783
|
-
- ✅ Flipper 调试网络和布局
|
|
784
|
-
- ✅ Fastlane 自动化部署
|
|
785
|
-
|
|
786
|
-
### Flutter
|
|
787
|
-
- ✅ const 构造函数减少重建
|
|
788
|
-
- ✅ ListView.builder 懒加载
|
|
789
|
-
- ✅ Riverpod 管理状态
|
|
790
|
-
- ✅ go_router 声明式路由
|
|
791
|
-
- ✅ freezed 生成不可变模型
|
|
792
|
-
- ✅ flutter_test 单元测试
|
|
793
|
-
- ✅ 使用 Keys 优化列表
|
|
794
|
-
|
|
795
|
-
---
|