搜索插件、代码仓与 APP 分类

app_runner 封面
插件详情v2.2.2

app_runner

像专业人士一样启动您的 Flutter 应用!AppRunner 是一个用于快速且可控启动应用程序的配置工具。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
166
喜欢数
61
Pub 分数
160

安装插件

flutter pub add app_runner

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

AppRunner 是一个 Flutter 工具包,可让开发者使用可自定义的配置启动其应用程序,确保应用启动过程受控且高效。它简化了在多个平台之间管理启动参数、环境设置和初始化工作流程的过程。适用于开发、测试和预发布环境,AppRunner 能够增强工作流程的一致性并减少设置时间。支持 Android、iOS、Web、macOS、Windows 和 Linux,为现代 Flutter 项目提供跨平台灵活性。

适合场景

  • 使用自定义配置快速启动应用
  • 开发和测试环境设置
  • 预发布环境配置
  • 跨平台应用程序初始化
  • 自动化构建和运行工作流

主要特点

  • 可配置的启动设置
  • 多平台支持
  • 环境感知的启动
  • 简化初始化
  • 与 CI/CD 流水线集成

适合对象

  • Flutter 开发者
  • 测试自动化工程师
  • DevOps 团队
  • 跨平台应用维护者
  • 快速原型设计

使用建议

  • 每个环境都需要手动配置
  • 仅限启动时自定义
  • 无运行时配置更改
  • 最适合发布前的设置
  • 依赖于正确的项目结构

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

AppRunner

pub package License

Launch your Flutter app like a pro! AppRunner is a configurator for quick and controlled launch of your application, with features that runApp does not have.

We solve problems of brand presence on mobile devices, specializing in development of mobile applications and services in the b2c segment.

Subscribe for the latest updates:


Features

  • Get your application up and running quickly.
  • Allows you to run code without blocking your application from launching.
  • Show your independent splash screen while loading the app. AppRunner does not block the first call of the widget, do you practically won't see the native splash screen.
  • Allows you to reload the widget tree if you need it.
  • Your code will run in a safe environment for both Dart code and Flutter code. AppRunner catches and handles errors, preventing your application from breaking at runtime.
  • Configuring the zone of your application is much easier.
  • With AppRunner you can easily override ErrorWidget for debug and release mode.
  • Lets you just use your WidgetsBinding implementation.
  • And the very last and most important argument to use AppRunner in your application, it is very easy to integrate into your application, and its configuration does not take much time.
Splash Screen Debug Error Screen Release Error Screen
run debug-error release-error

Installing

BREAKING: Note, starting with version 2.2.0, Flutter 3.10.0+ is used by default. If you need to use a Flutter version lower than 3.10.0, then use package version 2.1.2 and below.

Add this to your package's pubspec.yaml file:

dependencies:
  app_runner: <last version>

Usage

This is how your application launch looked like before:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

It is simply by attaching your widget to the root. But in order to catch errors, it was necessary to use runZonedGuarded, then our code will become like this:

import 'dart:async';

import 'package:flutter/material.dart';

void main() {
  runZonedGuarded<void>(
    () {
      runApp(MyApp());
    },
    (Object error, StackTrace stackTrace) {...},
    zoneValues: ...,
    zoneSpecification: ...,
  );
}

But we also need to initialize some code to launch the application, for example Firebase:

import 'dart:async';

import 'package:flutter/material.dart';
void main() {
  runZonedGuarded<void>(
    () async {
      WidgetsFlutterBinding.ensureInitialized();

      await Firebase.initializeApp();

      HydratedBloc.storage = await HydratedStorage.build(
        storageDirectory: await getApplicationDocumentsDirectory(),
      );

      Bloc.observer = MyBlocObserver();

      runApp(MyApp());
    },
    (Object error, StackTrace stackTrace) {},
    zoneValues: ...,
    zoneSpecification: ...,
  );
}

And what do we have:

  • The launch of the widget is blocked by the third-party code.
  • The splash screen is implemented in MyApp, that is, it will be present in the tree when it is no longer needed.
  • Not the most beautiful and understandable code.

Let's fix this with AppRunner (all possible parameters are shown here, it is not necessary to use all of them):

import 'package:app_runner/app_runner.dart';
import 'package:flutter/material.dart';

void main() {
  final WidgetConfiguration widgetConfiguration = WidgetConfiguration(
    child: AppBuilder<String>(
      preInitialize: (WidgetsBinding binding) async {
        // Custom code initialization.
        // You don't need to call WidgetsFlutterBinding.ensureInitialized();
        // WidgetsBinding is also available here if you need it.

        await Firebase.initializeApp();

        HydratedBloc.storage = await HydratedStorage.build(
          storageDirectory: await getApplicationDocumentsDirectory(),
        );

        Bloc.observer = MyBlocObserver();
        
        return 'Mad Brains';
      },
      // Our application
      builder: (
        BuildContext context,
        AsyncSnapshot<String?> snapshot,
        Widget? child,
      ) {
        late final Widget _child;
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.active:
          case ConnectionState.waiting:
            _child = const Splash(); // show Splash
            continue display;
          case ConnectionState.done:
            final String? data = snapshot.data; // data from preInitialize
            log(data);
            _child = const MyApp(); // show App
            continue display;
          display:
          default:
            return AnimatedSwitcher(
              duration: const Duration(milliseconds: 150),
              child: _child,
            );
        }
      },
    ),
    errorBuilder: (BuildContext context, FlutterErrorDetails errorDetails) => MyErrorScreen(errorDetails), // Our flutter error screen during debugging
    releaseErrorBuilder: (BuildContext context) => MyReleaseErrorScreen(), // Our flutter error screen during release
    onFlutterError: (FlutterErrorDetails errorDetails) {
      // Flutter error handling
      log(
        errorDetails.toStringShort(),
        name: 'onFlutterError',
        stackTrace: errorDetails.stack,
        error: errorDetails.exception,
      );
    },
    initializeBinding: () => CustomWidgetsFlutterBinding(), // Creating your WidgetsFlutterBinding
  );

  final ZoneConfiguration zoneConfiguration = ZoneConfiguration(
    onZoneError: (Object error, StackTrace stackTrace) {
      // Dart error handling
      log(
        error.runtimeType.toString(),
        name: 'onZoneError',
        stackTrace: stackTrace,
        error: error,
      );
    },
    zoneValues: ..., // Your zone parameters
    zoneSpecification: ..., // Your zone specifications
  );

  appRunner(
    kIsWeb
        ? RunnerConfiguration(
            widgetConfig: widgetConfiguration,
            // optional, isolate error handling
            onPlatformError: (Object exception, StackTrace stackTrace) {
              log(
                exception.runtimeType.toString(),
                name: 'onPlatformError',
                stackTrace: stackTrace,
                error: exception,
              );

              return false;
            },
          )
        : RunnerConfiguration.guarded(
            widgetConfig: widgetConfiguration,
            zoneConfig: zoneConfiguration,
          ),
  );
}

If you need to reload the widgets, you can do:

reloadWidget(context);

// or

context.reloadWidget();

Example

The Example is in the corresponding folder

所属分类

源码仓库

使用此插件的项目

暂无相关数据。