1. 性能问题:卡顿和掉帧
问题表现
- 复杂UI滚动时卡顿
- 动画不流畅
- 页面跳转延迟
解决方法
dart
scss
// 1. 使用const构造器
class MyWidget extends StatelessWidget {
// 错误示例
Widget build() => Container(color: Colors.red);
// 正确示例 - 使用const
Widget build() => const SizedBox(width: 50);
}
// 2. 列表优化
ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(index), // 使用Key提高性能
title: Text('Item $index'),
);
},
// 添加以下优化选项
addAutomaticKeepAlives: false,
addRepaintBoundaries: false, // 对简单项可禁用
);
// 3. 使用RepaintBoundary隔离重绘
RepaintBoundary(
child: ExpensiveWidget(),
);
// 4. 异步加载图片
Image.network(
'url',
loadingBuilder: (context, child, progress) {
return progress == null ? child : CircularProgressIndicator();
},
);
性能工具
bash
arduino
# 性能分析
flutter run --profile
flutter run --trace-skia
# 查看性能面板
flutter run --enable-impeller # 新的渲染引擎
2. 状态管理问题
问题表现
- 状态不同步
- 不必要的重建
- 内存泄漏
解决方法
dart
scala
// 1. 选择合适的方案
// 简单应用:Provider + ChangeNotifier
// 中等应用:Riverpod
// 复杂应用:Bloc/Cubit
// 2. Provider最佳实践
final counterProvider = StateProvider<int>((ref) => 0);
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('$count');
}
}
// 3. 避免状态滥用
// 使用StateNotifier替代ChangeNotifier
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}
// 4. 使用Equatable避免重复构建
class User extends Equatable {
final String id;
final String name;
@override
List<Object> get props => [id, name];
}
3. 依赖包冲突
问题表现
pub get失败- 运行时错误
- 功能异常
解决方法
yaml
yaml
# pubspec.yaml配置技巧
dependencies:
# 1. 使用范围版本而非固定版本
http: ^1.0.0 # 而不是 1.0.0
# 2. 手动解决冲突
package_a: ^2.0.0
package_b:
version: ^2.1.0
# 排除冲突的依赖
dependency_overrides:
shared_dependency: ^3.0.0
# 3. 使用any版本(谨慎)
controversial_package: any
命令行工具
bash
csharp
# 1. 分析依赖树
flutter pub deps
flutter pub dependency_overrides
# 2. 升级依赖
flutter pub upgrade --major-versions
# 3. 解决冲突步骤
flutter clean
rm pubspec.lock
flutter pub get
# 4. 查看依赖图表
flutter pub deps --style=tree
4. 平台特定问题
iOS问题解决
bash
lua
# iOS构建问题
cd ios
pod install --repo-update
pod update
# 修改Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
# 解决bitcode问题
config.build_settings['ENABLE_BITCODE'] = 'NO'
# 解决架构问题
config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
end
end
end
Android问题解决
groovy
arduino
// android/app/build.gradle
android {
defaultConfig {
// 解决64位支持
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
// 解决multidex
multiDexEnabled true
}
// 解决编译版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
平台特定代码
dart
dart
import 'dart:io' show Platform;
class PlatformUtils {
static bool get isIOS => Platform.isIOS;
static bool get isAndroid => Platform.isAndroid;
// 平台特定的UI
static Widget getPlatformWidget() {
if (Platform.isIOS) {
return CupertinoButton(...);
} else {
return MaterialButton(...);
}
}
}
5. 构建和发布问题
构建失败解决
bash
bash
# 1. 清理缓存
flutter clean
rm -rf ios/Pods
rm -rf ios/.symlinks
# 2. 重置环境
flutter doctor
flutter doctor --android-licenses
# 3. 分析构建日志
flutter build apk --verbose 2>&1 | tee build.log
# 4. 使用特定渠道
flutter channel stable
flutter upgrade
# 5. 检查Flutter环境
which flutter
flutter --version
常见构建配置
yaml
arduino
# flutter_app/android/app/build.gradle
android {
signingConfigs {
release {
storeFile file("keystore.jks")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyPassword System.getenv("KEY_PASSWORD")
keyAlias "key_alias"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
// 启用代码压缩
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile(
'proguard-android.txt'),
'proguard-rules.pro'
}
}
}
6. 网络请求和数据处理
网络问题解决
dart
dart
// 1. 使用Dio替代HttpClient
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 5),
receiveTimeout: Duration(seconds: 3),
));
// 2. 添加拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 添加token
options.headers['Authorization'] = 'Bearer $token';
return handler.next(options);
},
onError: (DioError e, handler) {
// 错误处理
if (e.type == DioErrorType.connectTimeout) {
// 重试逻辑
}
return handler.next(e);
},
));
// 3. 使用retry机制
Future<T> retryRequest<T>(Future<T> Function() request) async {
for (int i = 0; i < 3; i++) {
try {
return await request();
} catch (e) {
if (i == 2) rethrow;
await Future.delayed(Duration(seconds: 1 << i));
}
}
throw Exception('Max retries exceeded');
}
// 4. 离线处理
class NetworkService {
final Connectivity _connectivity = Connectivity();
Future<bool> get isConnected async {
final result = await _connectivity.checkConnectivity();
return result != ConnectivityResult.none;
}
}
数据处理
dart
dart
// 1. 使用freezed生成不可变模型
@freezed
class User with _$User {
factory User({
required String id,
required String name,
String? email,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
// 2. 使用json_serializable
@JsonSerializable()
class Product {
final String id;
final String name;
Product({required this.id, required this.name});
factory Product.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductToJson(this);
}
// 3. 错误边界处理
class ErrorBoundary extends StatelessWidget {
final Widget child;
@override
Widget build(BuildContext context) {
return ErrorWidget.builder((FlutterErrorDetails details) {
// 记录错误
FirebaseCrashlytics.instance.recordError(
details.exception,
details.stack,
);
// 显示友好错误页面
return ErrorScreen(details.exception);
});
}
}
7. 导航和路由问题
问题表现
- 页面跳转动画卡顿
- 返回栈管理混乱
- 参数传递丢失
- 路由守卫难以实现
解决方法
dart
dart
// 1. 使用命名路由并统一管理
class AppRoutes {
static const home = '/';
static const detail = '/detail';
static const settings = '/settings';
static Map<String, WidgetBuilder> get routes {
return {
home: (context) => HomePage(),
detail: (context) => DetailPage(),
settings: (context) => SettingsPage(),
};
}
}
// 2. 安全的参数传递
class DetailPage extends StatelessWidget {
static const routeName = '/detail';
final String id;
final String title;
const DetailPage({
Key? key,
required this.id,
required this.title,
}) : super(key: key);
// 路由参数检查
static Route<dynamic> route(RouteSettings settings) {
final args = settings.arguments as Map<String, dynamic>?;
if (args == null || args['id'] == null) {
return MaterialPageRoute(
builder: (_) => ErrorPage(message: '缺少必要参数'),
);
}
return MaterialPageRoute(
builder: (_) => DetailPage(
id: args['id'],
title: args['title'] ?? '',
),
);
}
}
// 3. 使用 GoRouter 或 AutoRoute 管理复杂路由
dependencies:
go_router: ^6.0.0
auto_route: ^4.0.0
// 4. 导航守卫/中间件
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomePage(),
redirect: (context, state) {
// 检查登录状态
final isLoggedIn = authProvider.isLoggedIn;
if (!isLoggedIn) return '/login';
return null;
},
),
],
errorBuilder: (context, state) => ErrorPage(
error: state.error,
),
);
8. 国际化 (i18n) 和本地化
问题表现
- 多语言切换不及时更新
- 文案硬编码
- RTL(从右到左)布局问题
- 日期/数字格式化不一致
解决方法
dart
scala
// 1. 使用 intl 包和 ARB 文件
dependencies:
flutter_localizations:
sdk: flutter
intl: ^0.18.0
flutter_localized_locales: ^2.0.0
// 2. 生成本地化代码
# 在 pubspec.yaml 中添加
flutter:
generate: true
# 创建 l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
// 3. 使用生成的本地化类
MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''), // English
Locale('zh', 'CN'), // 简体中文
Locale('ar', ''), // Arabic (RTL)
],
locale: _currentLocale,
localeResolutionCallback: (locale, supportedLocales) {
// 支持的语言回调
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale?.languageCode) {
return supportedLocale;
}
}
return supportedLocales.first;
},
);
// 4. RTL 布局处理
class RTLWrapper extends StatelessWidget {
final Widget child;
@override
Widget build(BuildContext context) {
final isRTL = Localizations.localeOf(context).languageCode == 'ar';
return Directionality(
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
child: child,
);
}
}
// 5. 动态切换语言
class LocaleProvider extends ChangeNotifier {
Locale? _locale;
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!_supportedLocales.contains(locale)) return;
_locale = locale;
notifyListeners();
}
static const _supportedLocales = [
Locale('en'),
Locale('zh'),
Locale('ar'),
];
}
9. 主题和样式管理
问题表现
- 主题切换性能问题
- 暗黑模式实现复杂
- 样式不一致
- 动态主题支持困难
解决方法
dart
php
// 1. 使用 Provider 管理主题
class ThemeProvider extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
void setThemeMode(ThemeMode mode) {
_themeMode = mode;
notifyListeners();
}
}
// 2. 创建自定义主题数据类
class AppTheme {
static const _fontFamily = 'Roboto';
static ThemeData get lightTheme {
return ThemeData(
brightness: Brightness.light,
primaryColor: Colors.blue,
fontFamily: _fontFamily,
textTheme: TextTheme(
headline1: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
bodyText1: TextStyle(fontSize: 16),
),
colorScheme: ColorScheme.light(
primary: Colors.blue,
secondary: Colors.orange,
),
);
}
static ThemeData get darkTheme {
return ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.blueGrey,
fontFamily: _fontFamily,
colorScheme: ColorScheme.dark(
primary: Colors.blueGrey,
secondary: Colors.orange,
),
);
}
}
// 3. 响应系统主题变化
WidgetsBinding.instance.platformDispatcher.onPlatformBrightnessChanged = () {
final brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
// 处理主题变化
};
// 4. 使用 Extension 简化样式访问
extension ThemeExtension on BuildContext {
Color get primaryColor => Theme.of(this).primaryColor;
TextTheme get textTheme => Theme.of(this).textTheme;
double get paddingMedium => 16.0;
}
// 使用
Text(
'Hello',
style: context.textTheme.headline1,
color: context.primaryColor,
);
10. 文件存储和缓存
问题表现
- 文件读写权限问题
- 缓存清理困难
- 大文件处理效率低
- 跨平台路径差异
解决方法
dart
dart
// 1. 使用 path_provider 获取路径
import 'package:path_provider/path_provider.dart';
class StorageService {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile(String filename) async {
final path = await _localPath;
return File('$path/$filename');
}
Future<void> writeData(String data, String filename) async {
final file = await _localFile(filename);
await file.writeAsString(data);
}
}
// 2. 使用 shared_preferences 存储简单数据
final prefs = await SharedPreferences.getInstance();
await prefs.setString('token', 'jwt_token');
final token = prefs.getString('token');
// 3. 使用 hive 或 sqflite 存储结构化数据
dependencies:
hive: ^2.2.0
hive_flutter: ^1.1.0
sqflite: ^2.2.0
// 4. 图片缓存管理
CachedNetworkImage(
imageUrl: 'https://example.com/image.jpg',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
cacheManager: DefaultCacheManager(),
maxHeight: 200,
maxWidth: 200,
);
// 5. 自定义缓存策略
class SmartCacheManager {
final CacheManager _cacheManager = CacheManager(
Config(
'custom_cache_key',
maxNrOfCacheObjects: 100,
stalePeriod: Duration(days: 7),
),
);
Future<void> clearOldCache() async {
await _cacheManager.emptyCache();
}
Future<void> clearExpired() async {
await _cacheManager.removeStale();
}
}
11. 权限管理
问题表现
- 权限申请被拒绝
- 动态权限处理复杂
- 不同平台权限差异
- 权限状态管理困难
解决方法
dart
dart
// 1. 使用 permission_handler
dependencies:
permission_handler: ^10.0.0
// 2. 权限服务封装
class PermissionService {
static Future<bool> requestCameraPermission() async {
final status = await Permission.camera.request();
if (status.isGranted) {
return true;
} else if (status.isDenied) {
// 可再次请求
return false;
} else if (status.isPermanentlyDenied) {
// 需要引导用户去设置
await openAppSettings();
return false;
}
return false;
}
// 3. 批量请求权限
static Future<Map<Permission, PermissionStatus>> requestMultiple(
List<Permission> permissions,
) async {
return await permissions.request();
}
// 4. 检查权限状态
static Future<bool> checkPermission(Permission permission) async {
final status = await permission.status;
return status.isGranted;
}
}
// 5. 平台特定的权限处理
Future<void> requestIOSPermissions() async {
if (Platform.isIOS) {
// iOS 特定权限逻辑
final status = await Permission.photos.request();
if (!status.isGranted) {
// 处理拒绝逻辑
}
}
}
// 6. 权限请求 UI 封装
class PermissionRequestDialog extends StatelessWidget {
final String title;
final String message;
final VoidCallback onGranted;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
content: Text(message),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('取消'),
),
ElevatedButton(
onPressed: () {
onGranted();
Navigator.pop(context);
},
child: Text('去设置'),
),
],
);
}
}
12. 混合开发与平台交互
问题表现
- 平台通道调用失败
- 原生与 Flutter 通信延迟
- 插件兼容性问题
- 二进制大小增加
解决方法
dart
dart
// 1. 方法通道封装
class NativeBridge {
static const platform = MethodChannel('com.example/native');
static Future<String?> callNativeMethod(String method, [dynamic args]) async {
try {
final result = await platform.invokeMethod(method, args);
return result.toString();
} on PlatformException catch (e) {
debugPrint('Native call failed: ${e.message}');
return null;
}
}
// 2. 双向通信
static void setupEventChannel() {
const eventChannel = EventChannel('com.example/events');
eventChannel.receiveBroadcastStream().listen(
(event) {
// 处理来自原生的事件
_handleNativeEvent(event);
},
onError: (error) {
debugPrint('Event channel error: $error');
},
);
}
}
// 3. 使用 Pigeon 生成类型安全的代码
// schema.dart
import 'package:pigeon/pigeon.dart';
class SearchRequest {
String? query;
}
class SearchReply {
String? result;
}
@HostApi()
abstract class SearchApi {
SearchReply search(SearchRequest request);
}
// 4. 平台特定代码抽象
abstract class PlatformSpecificFeature {
Future<void> doSomething();
factory PlatformSpecificFeature() {
if (Platform.isAndroid) {
return AndroidImplementation();
} else if (Platform.isIOS) {
return IOSImplementation();
}
throw UnsupportedError('Platform not supported');
}
}
// 5. 插件开发注意事项
class MyPlugin {
static void registerWith(Registrar registrar) {
final channel = MethodChannel(
'my_plugin',
StandardMethodCodec(),
registrar.messenger(),
);
final instance = MyPlugin();
channel.setMethodCallHandler(instance.handleMethodCall);
}
Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case 'getPlatformVersion':
return Platform.version;
default:
throw PlatformException(
code: 'Unimplemented',
message: 'Method not implemented',
);
}
}
}
13. 调试和日志系统
问题表现
- 生产环境日志泄露
- 调试信息不足
- 性能监控缺失
- 错误追踪困难
解决方法
dart
scss
// 1. 分级日志系统
enum LogLevel { debug, info, warning, error }
class Logger {
static final Logger _instance = Logger._internal();
factory Logger() => _instance;
Logger._internal();
void log(LogLevel level, String message, {Object? error, StackTrace? stackTrace}) {
if (kDebugMode) {
// 开发环境:输出到控制台
_printLog(level, message, error, stackTrace);
}
// 生产环境:发送到服务器
if (level.index >= LogLevel.warning.index) {
_sendToServer(level, message, error, stackTrace);
}
}
void _printLog(LogLevel level, String message, Object? error, StackTrace? stackTrace) {
final prefix = '[${level.name.toUpperCase()}]';
debugPrint('$prefix $message');
if (error != null) {
debugPrint('Error: $error');
}
if (stackTrace != null) {
debugPrint('Stack: $stackTrace');
}
}
}
// 2. 使用 logger 包
dependencies:
logger: ^1.1.0
final logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 8,
colors: true,
),
);
// 3. 性能监控
void main() {
// 记录启动时间
final stopwatch = Stopwatch()..start();
runApp(MyApp());
WidgetsBinding.instance.addPostFrameCallback((_) {
stopwatch.stop();
logger.d('App started in ${stopwatch.elapsedMilliseconds}ms');
});
}
// 4. 网络请求拦截日志
dio.interceptors.add(LogInterceptor(
request: true,
requestHeader: true,
requestBody: true,
responseHeader: true,
responseBody: true,
logPrint: (object) {
logger.d(object);
},
));
// 5. 自定义错误页面
class ErrorBoundary extends StatelessWidget {
final Widget child;
@override
Widget build(BuildContext context) {
return ErrorWidget.builder((FlutterErrorDetails details) {
// 记录错误
logger.e(details.exceptionAsString(),
error: details.exception,
stackTrace: details.stack,
);
// 显示用户友好的错误页面
return ErrorScreen(
onRetry: () => Navigator.of(context).pop(),
);
});
}
}
14. 测试相关挑战
问题表现
- 单元测试难以编写
- Widget 测试缓慢
- 集成测试不稳定
- Mock 数据复杂
解决方法
dart
less
// 1. 使用 Mockito 和 Build Runner
dev_dependencies:
mockito: ^5.3.0
build_runner: ^2.3.0
// 生成 Mock 类
@GenerateMocks([HttpClient])
import 'my_test.mocks.dart';
void main() {
late MockHttpClient mockClient;
setUp(() {
mockClient = MockHttpClient();
});
test('测试网络请求', () async {
when(mockClient.get(any)).thenAnswer(
(_) async => HttpResponse(data: 'test', statusCode: 200),
);
final service = MyService(mockClient);
final result = await service.fetchData();
expect(result, 'test');
verify(mockClient.get(any)).called(1);
});
}
// 2. Widget 测试优化
testWidgets('测试登录页面', (WidgetTester tester) async {
// 使用 Key 查找组件
await tester.pumpWidget(MyApp());
// 输入文本
await tester.enterText(find.byKey(Key('email_field')), 'test@example.com');
await tester.enterText(find.byKey(Key('password_field')), 'password');
// 点击按钮
await tester.tap(find.byKey(Key('login_button')));
// 等待异步操作完成
await tester.pumpAndSettle();
// 验证结果
expect(find.text('登录成功'), findsOneWidget);
});
// 3. 集成测试最佳实践
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('完整用户流程测试', (WidgetTester tester) async {
// 启动应用
await tester.pumpWidget(MyApp());
// 执行用户操作序列
await _performLogin(tester);
await _navigateToProfile(tester);
await _updateProfile(tester);
// 验证最终状态
expect(find.text('更新成功'), findsOneWidget);
});
// 4. Golden Tests(视觉回归测试)
testWidgets('验证UI一致性', (WidgetTester tester) async {
await tester.pumpWidget(MyWidget());
await expectLater(
find.byType(MyWidget),
matchesGoldenFile('goldens/my_widget.png'),
);
});
}
15. 持续集成/持续部署 (CI/CD)
问题表现
- 构建配置复杂
- 多环境管理困难
- 自动化测试集成
- 发布流程繁琐
解决方法
yaml
yaml
# .github/workflows/flutter.yml
name: Flutter CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.0.0'
- name: Install dependencies
run: flutter pub get
- name: Analyze code
run: flutter analyze
- name: Run tests
run: flutter test --coverage
- name: Upload coverage
uses: codecov/codecov-action@v2
build-android:
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Flutter
uses: subosito/flutter-action@v2
- name: Build APK
run: |
flutter build apk --release \
--dart-define=APP_ENV=production \
--dart-define=API_URL=https://api.example.com
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: app-release
path: build/app/outputs/flutter-apk/app-release.apk
环境配置管理
dart
dart
// lib/config/environment.dart
abstract class Environment {
static const String apiUrl = String.fromEnvironment('API_URL');
static const String appEnv = String.fromEnvironment('APP_ENV');
static bool get isProduction => appEnv == 'production';
static bool get isDevelopment => appEnv == 'development';
static Map<String, String> get variables {
return {
'API_URL': apiUrl,
'APP_ENV': appEnv,
};
}
}
// 构建命令
flutter run --dart-define=APP_ENV=development --dart-define=API_URL=http://localhost:3000
flutter build apk --release --dart-define=APP_ENV=production --dart-define=API_URL=https://api.example.com
16. 其他实用技巧
调试技巧
dart
scss
// 1. 调试Build次数
class BuildCounter extends StatelessWidget {
@override
Widget build(BuildContext context) {
debugPrint('BuildCounter rebuilt');
return Container();
}
}
// 2. 使用DevTools
// 运行:flutter pub global run devtools
// 然后:flutter run --observatory-port=9200
// 3. 性能监控
void main() {
WidgetsFlutterBinding.ensureInitialized();
// 添加性能监控
FlutterError.onError = (FlutterErrorDetails details) {
Zone.current.handleUncaughtError(details.exception, details.stack!);
};
runZonedGuarded(() {
runApp(MyApp());
}, (error, stackTrace) {
// 记录未捕获异常
FirebaseCrashlytics.instance.recordError(error, stackTrace);
});
}
资源优化
yaml
yaml
# pubspec.yaml
flutter:
assets:
- assets/images/
# 字体优化
fonts:
- family: Roboto
fonts:
- asset: assets/fonts/Roboto-Regular.ttf
weight: 400
- asset: assets/fonts/Roboto-Bold.ttf
weight: 700
# Shader预编译(减少卡顿)
shaders:
- shaders/myshader.frag