You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter修复Web刷新丢数据后,移动端编译失败(Web端正常)

问题:移除image_picker_web后iOS/Android编译失败,Web端正常运行

修复Web端刷新数据丢失问题时,曾添加image_picker_web依赖,后续移除该依赖后,iOS和Android平台出现编译错误,Web端运行正常。错误出现在final parsed = css.parse(text);处,提示可空类型String?无法赋值给非可空类型Object,导致Gradle的:app:compileFlutterBuildDebug任务执行失败。


错误日志

Launching lib\main.dart on Infinix X6831 in debug mode...
main.dart:1
: Error: The argument type 'String?' can't be assigned to the parameter type 'Object' because 'String?' is nullable and 'Object' isn't.
element_subclasses.dart:2752

'Object' is from 'dart:core'.
final parsed = css.parse(text);
^
Target kernel_snapshot failed: Exception
2

FAILURE: Build failed with an exception.

Where:
Script 'C:\scr\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 1157

What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.

Process 'command 'C:\scr\flutter\bin\flutter.bat'' finished with non-zero exit value 1

Try:
Run with --stacktrace option to get the stack trace.
Run with --info or --debug option to get more log output.
Run with --scan to get full insights.

Get more help at https://help.gradle.org
BUILD FAILED in 13s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

main.dart代码片段

import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:kleely/services/exam_service.dart';
import 'package:kleely/services/question_service.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:provider/provider.dart';

import 'firebase_options.dart';
import 'router/garde.dart';
import 'router/router.gr.dart';
import 'services/chapter_service.dart';
import 'services/class_service.dart';
import 'services/grade.service.dart';
import 'services/sub_chapter_service.dart';
import 'services/subject_service.dart';
import 'services/user_authentication.dart';
import 'translations/codegen_loader.g.dart';
import 'utils/injection/injection_container.dart';
import 'utils/network/internet_checker.dart';
import 'utils/network/no_internet.dart';
import 'utils/theme/app_theme.dart';
import 'utils/theme/presentation/theme_cubit.dart';


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);

  await init();
  if (kIsWeb) {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );

    runApp(
      OverlaySupport.global(
        child: EasyLocalization(
          path: 'assets/translations',
          supportedLocales: const [Locale('ar')],
          useFallbackTranslations: true,
          fallbackLocale: const Locale('ar'),
          assetLoader: const CodegenLoader(),
          startLocale: const Locale('ar'),
          child: MainApp(),
        ),
      ),
    );
  } else {
    bool isConnected = await sl<InternetChecker>().checkInternet();
    if (isConnected) {
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );

      runApp(
        OverlaySupport.global(
          child: EasyLocalization(
            path: 'assets/translations',
            supportedLocales: const [Locale('ar')],
            useFallbackTranslations: true,
            fallbackLocale: const Locale('ar'),
            assetLoader: const CodegenLoader(),
            startLocale: const Locale('ar'),
            child: MainApp(),
          ),
        ),
      );
    } else {
      runApp(const NoInternet());
    }
  }
}

class MainApp extends StatelessWidget {
  MainApp({super.key});

  final _appRouter = AppRouter(authGuard: AuthGuard());

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => UserAuthentication()),
        Provider(create: (_) => GradeService()),
        Provider(create: (_) => SubjectService()),
        Provider(create: (_) => ChapterService()),
        Provider(create: (_) => SubChapterService()),
        Provider(create: (_) => ClassService()),
        Provider(create: (_) => ExamService()),
        Provider(create: (_) => QuestionService()),
        BlocProvider<ThemeCubit>(create: (_) {
          // Initialize ThemeCubit and load the saved theme mode
          final themeCubit = sl<ThemeCubit>();
          themeCubit.loadThemeMode();
          return themeCubit;
        })
      ],
      child: BlocBuilder<ThemeCubit, ThemeMode>(
        builder: (context, themeMode) {
          return MaterialApp.router(
            // easy localization
            localizationsDelegates: context.localizationDelegates,
            supportedLocales: context.supportedLocales,
            locale: context.locale,

            title: 'Kleely',
            debugShowCheckedModeBanner: false,

            // app theme
            theme: themeMode == ThemeMode.light
                ? AppTheme.themeData
                : AppTheme.darkTheme,
            darkTheme: AppTheme.darkTheme,
            themeMode: themeMode,

            routerDelegate: AutoRouterDelegate(
              _appRouter,
              navigatorObservers: () => [AutoRouteObserver()],
            ),
            routeInformationParser: _appRouter.defaultRouteParser(),
            builder: (context, router) {
              ScreenUtil.init(
                context,
                designSize: const Size(360, 690),
              );

              return router!;
            },
          );
        },
      ),
    );
  }
}

环境信息

Flutter版本: 3.7.12
Dart版本: 2.19.6
操作系统: Windows 10
Android Studio版本: 2021.3
Visual Studio Code版本: 1.81.1

依赖配置

name: kleely
description: A new Flutter project.
publish_to: "none"
version: 0.1.0

environment:
  sdk: ">=2.19.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  # firebase
  firebase_core: ^2.15.0
  firebase_auth: ^4.7.1
  cloud_firestore: ^4.8.3
  firebase_storage: ^11.2.5

  # other
  http: ^0.13.6
  intl: ^0.17.0
  permission_handler: ^10.4.3
  dartz:

  # route
  path_provider: ^2.1.0
  auto_route: ^5.0.2

  # Generators
  username_generator: ^1.3.0
  uuid: ^3.0.7

  # style
  flex_color_scheme: ^7.0.5
  flutter_carousel_widget: ^2.0.4
  flutter_screenutil: ^5.7.0
  flutter_spinkit: ^5.2.0
  google_fonts: ^4.0.4
  shimmer: ^3.0.0
  curved_navigation_bar: ^1.0.3
  percent_indicator: ^4.2.3
  infinite_carousel: ^1.0.2
  intl_phone_number_input: ^0.7.3+1
  loading_animation_widget: ^1.2.0+4
  widget_and_text_animator: ^1.0.0

  # localization
  easy_localization: ^3.0.2

  # network and overlay
  connectivity_plus: ^4.0.2
  overlay_support: ^2.1.0

  # video and image
  appinio_video_player: ^1.2.1
  image_picker: ^1.0.1
  # image_picker_web: ^3.0.0+1
  image_cropper: ^1.4.1

  # storage
  hive: ^2.2.3
  hive_flutter: ^1.1.0

  # state management & dependency injection
  get: ^4.6.5
  get_it: ^7.6.0
  bloc: ^8.1.2
  flutter_bloc: ^8.1.3
  provider: ^6.0.5
  image_picker_for_web: ^3.0.0
  cached_network_image: ^3.2.3
  blurry_modal_progress_hud: ^1.1.1
  firebase_performance: ^0.9.2+5
  universal_html: ^2.2.2

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0
  auto_route_generator: ^5.0.2
  build_runner: ^2.3.3
  flutter_launcher_icons: ^0.13.1

flutter_icons:
  android: true
  ios: true
  image_path: "assets/logos/icon.png"

flutter:
  uses-material-design: true

  assets:
    - assets/logos/KleeliLogo.png
    - assets/logos/KleeliIcon.ico
    - assets/icons/1.png
    - assets/icons/2.png
    - assets/icons/3.png
    - assets/icons/4.png
    - assets/icons/biology.png
    - assets/icons/chemistry.png
    - assets/icons/physics.png
    - assets/icons/math.png
    - assets/translations/
    - assets/images/c.jpg
    - assets/audio/loading.mp3

近期修改内容

学生数据存储逻辑调整

Future<Either<Failure, Student>> fetchStudent(String studentId) async {
    DocumentSnapshot docSnapshot =
        await _firestore.collection('students').doc(studentId).get();
    if (docSnapshot.exists) {
      final studentData = docSnapshot.data() as Map<String, dynamic>;
      final student = Student.fromMap(studentData);
      notifyListeners();

      if (kIsWeb) {
        // Web端将学生数据存入Cookie
        CookieManager.setObjectAsCookie('student', student.toMap());
      } else {
        // 移动端将学生数据存入Hive
        await HiveManager.addObjectAsBox('student', student.toMap());
      }

      return right(student);
    } else {
      _student = null;
      notifyListeners();
      return left(Failure('No student found with this ID'));
    }
  }

图片选择逻辑调整

GestureDetector(
                onTap: () async {
                  if (kIsWeb) {
                    final ImagePicker _picker = ImagePicker();
                    XFile? image =
                        await _picker.pickImage(source: ImageSource.gallery);
                    if (image != null) {
                      File file = File(image.path);
                      // ignore: use_build_context_synchronously
                      await Provider.of<UserAuthentication>(context,
                              listen: false)
                          .setProfilePicture(file);
                    }
                  } else {
                    PermissionStatus permissionStatus =
                        await Permission.photos.status;

                    if (permissionStatus.isDenied ||
                        permissionStatus.isPermanentlyDenied) {
                      // 可弹出提示告知用户应用需要权限
                      permissionStatus = await Permission.photos.request();
                    }

                    if (permissionStatus.isGranted) {
                      final XFile? image = await ImagePicker()
                          .pickImage(source: ImageSource.gallery);

                      if (image != null) {
                        File? croppedFile = await ImageCropper().cropImage(
                          sourcePath: image.path,
                          compressFormat: ImageCompressFormat.jpg,
                          aspectRatioPresets: [
                            CropAspectRatioPreset.square,
                            CropAspectRatioPreset.ratio3x2,
                            CropAspectRatioPreset.original,
                            CropAspectRatioPreset.ratio4x3,
                            CropAspectRatioPreset.ratio16x9
                          ],
                          androidUiSettings: AndroidUiSettings(
                              toolbarTitle: 'Cropper',
                              toolbarColor: Colors.white,
                              // ignore: use_build_context_synchronously
                              toolbarWidgetColor:
                                  Theme.of(context).primaryColor,
                              initAspectRatio: CropAspectRatioPreset.original,
                              lockAspectRatio: false),
                          iosUiSettings: const IOSUiSettings(
                            title: 'Cropper',
                          ),
                        );

                        if (croppedFile != null) {
                          // ignore: use_build_context_synchronously
                          await Provider.of<UserAuthentication>(context,
                                  listen: false)
                              .setProfilePicture(croppedFile);
                        }
                      }
                    } else {
                      // 处理用户拒绝权限的情况
                      log("Permission to access gallery is denied");
                    }
                  }
                },
                child: Consumer<UserAuthentication>(
                  builder: (context, value, child) {
                    return SizedBox(
                      width: 100.w, // 使用screenutil扩展
                      child: CircleAvatar(
                        radius: 50.r, // 使用screenutil扩展
                        backgroundImage: NetworkImage(
                          value.user == null
                              ? 'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?r=pg'
                              : value.user!.photoURL ??
                                  'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?r=pg',
                        ),
                      ),
                    );
                  },
                ),
              ),

解决方案建议

  1. 清理项目缓存与依赖

    • 执行flutter clean清理Flutter项目缓存
    • 执行flutter pub get重新拉取所有依赖
    • Android平台额外执行gradlew clean清理Gradle缓存
  2. 修复css.parse的可空类型问题
    错误来自css解析逻辑,检查传入css.parse的text变量是否为可空值,添加非空处理:

    // 方式1:非空断言(确保text不会为空)
    final parsed = css.parse(text!);
    // 方式2:空值判断
    if (text != null) {
      final parsed = css.parse(text);
    }
    

    同时检查引入css解析的依赖(如universal_html)版本是否与当前Flutter/Dart版本兼容,尝试更新到最新兼容版本。

  3. 排查图片选择依赖冲突
    当前依赖中保留了image_picker_for_web,而image_picker本身已支持Web端,可尝试移除image_picker_for_web后重新执行flutter pub get,避免依赖冲突。

  4. 重新生成自动代码
    执行flutter pub run build_runner clean和flutter pub run build_runner build,重新生成路由等自动生成的代码,避免旧代码残留导致的编译问题。


内容的提问来源于stack exchange,提问作者Arevan Shamal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:30:53