Flutter应用运行管理插件app_runner的使用
Flutter应用运行管理插件app_runner的使用
AppRunner简介
AppRunner 是一个用于快速且受控启动Flutter应用程序的配置器,它提供了一些runApp
不具备的功能。通过使用AppRunner,你可以更优雅地处理应用启动过程中的各种问题,如自定义启动画面、错误处理等。
特性
- 快速启动你的应用程序。
- 不会阻塞应用程序启动时执行代码。
- 显示独立的启动屏幕,几乎看不到原生的启动屏。
- 可以根据需要重新加载小部件树。
- 为Dart和Flutter代码创建安全的运行环境,捕获并处理错误,防止应用程序在运行时崩溃。
- 更容易配置应用程序区域(Zone)。
- 在调试和发布模式下轻松覆盖
ErrorWidget
。 - 允许使用自己的
WidgetsBinding
实现。 - 最重要的是,集成到项目中非常简单,配置所需时间短。
安装
从2.2.0版本开始,默认使用Flutter 3.10.0+。如果你需要使用低于3.10.0版本的Flutter,请使用包版本2.1.2及以下。
将以下内容添加到你的项目的pubspec.yaml
文件中:
dependencies:
app_runner: <last version>
使用方法
下面是使用AppRunner的一个完整示例,该示例展示了如何初始化第三方库(例如Firebase),显示启动画面,并处理不同状态下的界面展示。
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 {
// 初始化第三方库,比如Firebase
await Firebase.initializeApp();
// 这里可以进行其他初始化操作
return 'Mad Brains'; // 返回的数据可以在builder中使用
},
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(); // 启动时显示Splash页面
break;
case ConnectionState.done:
final String? data = snapshot.data;
debugPrint(data); // 打印preInitialize返回的数据
_child = const MyApp(); // 加载完成显示主页面
break;
default:
return AnimatedSwitcher(
duration: const Duration(milliseconds: 150),
child: _child,
);
}
return _child;
},
),
errorBuilder: (BuildContext context, FlutterErrorDetails errorDetails) => MyErrorScreen(errorDetails), // 调试模式下的错误页面
releaseErrorBuilder: (BuildContext context) => MyReleaseErrorScreen(), // 发布模式下的错误页面
onFlutterError: (FlutterErrorDetails errorDetails) {
// 处理Flutter错误
debugPrint(
errorDetails.toStringShort(),
stackTrace: errorDetails.stack,
error: errorDetails.exception,
);
},
initializeBinding: () => CustomWidgetsFlutterBinding(), // 自定义WidgetsFlutterBinding
);
final ZoneConfiguration zoneConfiguration = ZoneConfiguration(
onZoneError: (Object error, StackTrace stackTrace) {
// 处理Dart错误
debugPrint(
error.runtimeType.toString(),
stackTrace: stackTrace,
error: error,
);
},
);
appRunner(
kIsWeb
? RunnerConfiguration(
widgetConfig: widgetConfiguration,
onPlatformError: (Object exception, StackTrace stackTrace) {
debugPrint(
exception.runtimeType.toString(),
stackTrace: stackTrace,
error: exception,
);
return false;
},
)
: RunnerConfiguration.guarded(
widgetConfig: widgetConfiguration,
zoneConfig: zoneConfiguration,
),
);
}
// 如果需要重新加载小部件,可以调用如下方法:
// reloadWidget(context);
// 或者
// context.reloadWidget();
示例说明
- 预初始化 (
preInitialize
):在这个函数中,你可以执行所有需要在应用启动之前完成的任务,比如初始化数据库或网络连接。这个函数返回的数据可以通过builder
中的snapshop.data
访问。 - 构建UI (
builder
):根据preInitialize
的状态来决定显示什么内容。当preInitialize
还在进行时,可以显示一个简单的启动画面;当preInitialize
完成后,则显示应用程序的主要界面。 - 错误处理:提供了两种类型的错误处理机制,一种是针对Flutter框架内部抛出的错误(
onFlutterError
),另一种是针对Dart语言级别的异常(onZoneError
)。此外还支持平台特定的错误处理(onPlatformError
)。 - 自定义绑定 (
initializeBinding
):允许你创建自己的WidgetsFlutterBinding
实例,以便更好地控制渲染管道和其他底层行为。
以上就是关于app_runner
的基本介绍及其使用方式,希望对大家有所帮助!如果有任何问题或者建议,欢迎随时交流讨论。
更多关于Flutter应用运行管理插件app_runner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter应用运行管理插件app_runner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,app_runner
是一个在 Flutter 应用中用于运行和管理其他应用的插件。尽管 app_runner
并不是一个广泛认知的官方 Flutter 插件,但基于你的要求,我将提供一个假设性的示例代码,展示如何在 Flutter 应用中使用一个类似功能的插件来启动和管理其他应用。
在实际开发中,Flutter 本身并不直接提供运行其他应用的 API,但可以通过调用原生代码(Android 的 Intent 和 iOS 的 URL Scheme)来实现这一功能。以下是一个基于 platform_channel
的示例,它展示了如何在 Flutter 中与原生代码交互来启动另一个应用。
Flutter 端代码
首先,创建一个 Flutter 插件接口,用于与原生代码通信。
import 'package:flutter/services.dart';
class AppRunner {
static const MethodChannel _channel = MethodChannel('com.example.app_runner');
static Future<void> launchApp(String packageName) async {
try {
await _channel.invokeMethod('launchApp', packageName);
} on PlatformException catch (e) {
print("Failed to launch app: '${e.message}'.");
}
}
}
Android 端代码
在 MainActivity.kt
或 MainActivity.java
中处理来自 Flutter 的方法调用。
Kotlin 版本
package com.example.myapp
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.app_runner"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "launchApp") {
val packageName = call.argument<String>("packageName") ?: return@setMethodCallHandler result.error("INVALID_ARGUMENT", "Package name is required", null)
try {
launchApp(packageName)
result.success(null)
} catch (e: Exception) {
result.error("FAILED", e.message, null)
}
} else {
result.notImplemented()
}
}
}
private fun launchApp(packageName: String) {
val pm = packageManager
val launchIntent = pm.getLaunchIntentForPackage(packageName) ?: return
startActivity(launchIntent)
}
}
Java 版本
package com.example.myapp;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.app_runner";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("launchApp")) {
String packageName = call.argument("packageName");
if (packageName == null) {
result.error("INVALID_ARGUMENT", "Package name is required", null);
return;
}
try {
launchApp(packageName);
result.success(null);
} catch (Exception e) {
result.error("FAILED", e.getMessage(), null);
}
} else {
result.notImplemented();
}
}
);
}
private void launchApp(String packageName) throws Exception {
PackageManager pm = getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage(packageName);
if (launchIntent == null) {
throw new ActivityNotFoundException();
}
startActivity(launchIntent);
}
}
iOS 端代码
在 iOS 中,你可以使用 URL Scheme 来启动其他应用。首先,在 Info.plist
中声明你的应用可以查询其他应用的 URL Scheme。然后,在 AppDelegate.swift
或 AppDelegate.m
中处理 Flutter 的方法调用。
Swift 版本
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "com.example.app_runner", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) in
if call.method == "launchApp" {
guard let urlScheme = call.arguments as? String else {
result(FlutterError(code: "INVALID_ARGUMENT", message: "URL Scheme is required", details: nil))
return
}
if let url = URL(string: "\(urlScheme)://") {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
result(success: nil)
} else {
result(FlutterError(code: "FAILED", message: "App not installed", details: nil))
}
} else {
result(FlutterError(code: "INVALID_ARGUMENT", message: "Invalid URL Scheme", details: nil))
}
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Objective-C 版本
#import "AppDelegate.h"
#import <Flutter/Flutter.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
FlutterViewController *controller = (FlutterViewController *)self.window.rootViewController;
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"com.example.app_runner" binaryMessenger:controller.binaryMessenger];
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([call.method isEqualToString:@"launchApp"]) {
NSString *urlScheme = call.arguments;
if (!urlScheme) {
result([FlutterError errorWithCode:@"INVALID_ARGUMENT"
message:@"URL Scheme is required"
details:nil]);
return;
}
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@://", urlScheme]];
if (url && [[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
result(nil);
} else {
result([FlutterError errorWithCode:@"FAILED"
message:@"App not installed"
details:nil]);
}
} else {
result(FlutterMethodNotImplemented);
}
}];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
使用插件
在你的 Flutter 应用中,你可以这样使用 AppRunner
插件:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('App Runner Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
AppRunner.launchApp('com.example.targetapp'); // 替换为目标应用的包名或 URL Scheme
},
child: Text('Launch