Flutter神秘框架插件arcane_framework的使用
Flutter神秘框架插件arcane_framework的使用
Arcane Framework 是一个强大的 Dart 包,旨在为管理应用程序的关键服务(如日志记录、身份验证、安全存储、功能标志、主题等)提供一个健壮的架构。此框架非常适合构建需要动态配置和服务管理的可扩展应用。
功能
- 服务管理:集中访问多个服务(日志记录、身份验证、主题等)。
- 功能标志:使用
ArcaneFeatureFlags
动态启用或禁用功能。 - 日志记录:通过
ArcaneLogger
轻松记录带有元数据、堆栈跟踪和不同日志级别的消息。 - 身份验证:内置支持处理用户身份验证工作流。
- 动态主题:使用
ArcaneReactiveTheme
切换浅色和深色主题。
开始使用
安装
- 将依赖项添加到您的
pubspec.yaml
文件:
dependencies:
arcane_framework: <latest>
- 使用
ArcaneApp
小部件包装您的MaterialApp
或CupertinoApp
,并提供必要的服务和根小部件:
import 'package:arcane_framework/arcane_framework.dart';
void main() {
runApp(
ArcaneApp(
services: [
MyArcaneService.I,
],
child: MyApp(...),
),
);
}
使用
服务
Arcane Framework 提供了一种集中的方式来管理应用程序中的服务。这使得您可以轻松地访问和配置应用程序中的所有服务,而无需将它们传递给多个小部件。
以下是一个服务类的示例:
class FavoriteColorService extends ArcaneService {
static final FavoriteColorService _instance = FavoriteColorService._internal();
static FavoriteColorService get I => _instance;
FavoriteColorService._internal();
Color? get myFavoriteColor => _notifier.value;
final ValueNotifier<Color?> _notifier = ValueNotifier<Color?>(null);
ValueNotifier<Color?> get notifier => _notifier;
void setMyFavoriteColor(Color? newValue) {
if (_notifier.value != newValue) {
_notifier.value = newValue;
}
notifyListeners();
}
}
要注册服务,请将其实例添加到 ArcaneApp
的服务列表中:
ArcaneApp(
services: [
FavoriteColorService.I,
],
child: MyApp(...),
),
可以通过直接引用(例如 FavoriteColorService.I.myFavoriteColor
)或通过 BuildContext
(例如 context.serviceOfType<FavoriteColorService>()?.myFavoriteColor
)访问服务属性。如果服务包含 notifyListeners()
方法,任何引用服务属性的小部件将自动接收到更改通知。此外,可以添加监听器以观察值的变化。
FavoriteColorService.I.notifier.addListener(() {
final Color? color = FavoriteColorService.I.myFavoriteColor;
// 对值执行某些操作
});
功能标志
您可以使用内置的服务 ArcaneFeatureFlags
轻松管理功能标志。功能标志可用于在不同情况下启用或禁用应用程序的不同部分。例如,您可能希望仅在新功能完成开发和测试后启用它,同时仍然能够发布未完成的代码。您还可以利用功能标志启用应用程序中的不同模式(例如,“免费”与“付费”)。此外,它们可用于 A/B 测试。选项几乎是无限的。
首先,创建一个 enum
来定义您的功能:
enum Feature {
awesomeFeature(true),
prettyOkFeature(false),
;
/// 确定在应用程序启动时是否默认启用给定的功能。功能可以在运行时启用或禁用,无论此值为何。
final bool enabledAtStartup;
const Feature(this.enabledAtStartup);
}
接下来,确保功能在启动时启用,通过在功能标志服务中注册它们:
void main() {
WidgetsFlutterBinding.ensureInitialized();
// 注册您将用于启用和禁用功能的枚举。
for (final Feature feature in Feature.values) {
if (feature.enabledAtStartup) Arcane.features.enableFeature(feature);
}
runApp(const ArcaneApp());
}
当您想要确定某个功能是否启用时,可以使用其中一个助手扩展:
// 通过枚举扩展
final bool isMyAwesomeFeatureEnabled = Feature.awesomeFeature.enabled;
// 通过 Arcane 功能标志服务
final bool isMyPrettyOkFeatureDisabled = Arcane.features.isDisabled(Feature.prettyOkFeature);
您也可以在运行时启用和禁用功能:
// 通过枚举扩展
Feature.awesomeFeature.disable();
Feature.prettyOkFeature.enable();
// 通过 Arcane 特性服务
Arcane.features.disableFeature(Feature.awesomeFeature);
Arcane.features.enableFeature(Feature.prettyOkFeature);
要获取当前启用的功能列表,请简单询问 Arcane 功能标志服务:
final List<Enum> enabledFeatures = Arcane.features.enabledFeatures;
还可以添加监听器以观察启用功能的变化。
Arcane.features.notifier.addListener(() {
print("Features changed: ${Arcane.features.enabledFeatures}");
});
注意,可以在功能标志服务中注册多个不同的 Enum
类型,如有必要。
日志记录
Arcane Framework 提供了一个强大的日志系统,允许您轻松记录带有元数据、堆栈跟踪和不同日志级别的消息。框架还提供了轻松配置日志记录行为的方法(例如,是否显示堆栈跟踪)。
首先,创建一个或多个日志接口,扩展 LoggingInterface
基类:
class DebugConsole implements LoggingInterface {
static final DebugConsole _instance = DebugConsole._internal();
static DebugConsole get I => _instance;
DebugConsole._internal();
final bool _initialized = true;
[@override](/user/override)
bool get initialized => I._initialized;
[@override](/user/override)
void log(
String message, {
Map<String, dynamic>? metadata,
Level? level,
StackTrace? stackTrace,
}) {
debugPrint(
"$message\n"
"$metadata\n",
);
}
[@override](/user/override)
Future<LoggingInterface?> init() async => I;
}
接下来,将您的日志接口注册到 Arcane 日志服务:
// 注册您的日志接口
await Arcane.logger.registerInterfaces([
DebugConsole.I,
]);
// 初始化已注册的日志接口
// 注意:此步骤可能延迟到用户已同意应用程序跟踪。
await Arcane.logger.initializeInterfaces();
最后,向日志消息添加任何其他持久的元数据(可选),然后记录一条消息:
// 向日志器添加持久元数据
Arcane.logger.addPersistentMetadata({
"app_name": "My App",
"environment": "production",
});
// 记录一条消息!
Arcane.log(
"This is a debug message",
level: Level.debug,
module: "ModuleName",
method: "MethodName",
metadata: {"key": "value"},
stackTrace: StackTrace.current,
);
可以同时注册多个日志接口。
重要提示:日志接口通常应在与日志服务注册之后进行初始化。这确保了在记录任何消息之前所有日志接口都已正确初始化。这通常应手动执行,以便适当地向用户提供即将被提示授予跟踪权限的消息(在 iOS 上)。
身份验证
Arcane Framework 提供了一个有用的接口,用于执行常见的身份验证任务,如注册、密码重置、登录、登出和启用调试模式。
首先,创建一个身份验证接口提供者并将其注册到 Arcane 身份验证模块:
import "package:arcane_framework/arcane_framework.dart";
typedef Credentials = ({String email, String password});
class DebugAuthInterface
with ArcaneAuthAccountRegistration, ArcaneAuthPasswordManagement
implements ArcaneAuthInterface {
DebugAuthInterface._internal();
static final ArcaneAuthInterface _instance = DebugAuthInterface._internal();
static ArcaneAuthInterface get I => _instance;
[@override](/user/override)
Future<bool> get isSignedIn => Future.value(_isSignedIn);
bool _isSignedIn = false;
[@override](/user/override)
Future<String?> get accessToken => isSignedIn.then(
(loggedIn) => loggedIn ? "access_token" : null,
);
[@override](/user/override)
Future<String?> get refreshToken => isSignedIn.then(
(loggedIn) => loggedIn ? "refresh_token" : null,
);
[@override](/user/override)
Future<Result<void, String>> logout() async {
Arcane.log("Logging out");
_isSignedIn = false;
return Result.ok(null);
}
[@override](/user/override)
Future<Result<void, String>> login<Credentials>({
Credentials? input,
Future<void> Function()? onLoggedIn,
}) async {
final bool alreadyLoggedIn = await isSignedIn;
if (alreadyLoggedIn) return Result.ok(null);
final credentials = input as ({String email, String password});
final String email = credentials.email;
final String password = credentials.password;
Arcane.log("Logging in as $email using password $password");
_isSignedIn = true;
return Result.ok(null);
}
// 由 ArcaneAuthAccountRegistration 混入提供
[@override](/user/override)
Future<Result<String, String>> resendVerificationCode<T>({
T? input,
}) async {
Arcane.log("Re-sending verification code to $input");
return Result.ok("Code sent");
}
// 由 ArcaneAuthAccountRegistration 混入提供
[@override](/user/override)
Future<Result<SignUpStep, String>> register<Credentials>({
Credentials? input,
}) async {
if (input != null) {
final credentials = input as ({String email, String password});
final String email = credentials.email;
final String password = credentials.password;
Arcane.log("Creating account for $email with password $password");
}
return Result.ok(SignUpStep.confirmSignUp);
}
// 由 ArcaneAuthAccountRegistration 混入提供
[@override](/user/override)
Future<Result<bool, String>> confirmSignup({
String? username,
String? confirmationCode,
}) async {
Arcane.log(
"Confirming registration for $username with code $confirmationCode",
);
return Result.ok(true);
}
// 由 ArcaneAuthPasswordManagement 混入提供
[@override](/user/override)
Future<Result<bool, String>> resetPassword({
String? email,
String? newPassword,
String? code,
}) async {
Arcane.log("Resetting password for $email");
return Result.ok(true);
}
[@override](/user/override)
Future<void> init() async {
Arcane.log("Debug auth interface initialized.");
return;
}
}
// 注册一个接口以处理用户身份验证
await Arcane.auth.registerInterface(DebugAuthInterface.I);
一旦您的接口已创建并注册,您可以使用它来执行许多常见的身份验证任务:
// 使用 ArcaneAuthAccountRegistration 混入注册帐户
final nextStep = await Arcane.auth.register<Credentials>(
input: ("email": "user@example.com", "password": "password123"),
);
// 使用 ArcaneAuthAccountRegistration 混入确认新注册的帐户
final accountConfirmed = await Arcane.auth.confirmSignup(
email: "user@example.com",
confirmationCode: "123456",
);
// 使用 ArcaneAuthAccountRegistration 混入重新发送验证代码
final response = await Arcane.auth.resendVerificationCode("user@example.com");
// 使用 ArcaneAuthPasswordManagement 混入发起密码重置流程
final passwordResetStarted = await Arcane.auth.resetPassword(
email: "user@example.com",
newPassword: "password456",
);
// 使用 ArcaneAuthPasswordManagement 混入确认密码重置
final passwordResetFinished = await Arcane.auth.resetPassword(
email: "user@example.com",
newPassword: "password456",
confirmationCode: "123456",
);
// 使用电子邮件和密码登录
final result = await Arcane.auth.login(
input: ("email": "user@example.com", "password": "password123"),
onLoggedIn: () => Arcane.log("User logged in"),
);
// 登出
await Arcane.auth.logout();
动态主题
Arcane Framework 提供了一个简单的界面来管理应用程序中的主题,根据用户的系统设置动态切换浅色和深色主题,或者手动切换主题。
首先,在 Arcane 主题模块中注册您的 ThemeData
对象:
void main() {
// 设置您的主题
Arcane.theme
..setDarkTheme(darkTheme)
..setLightTheme(lightTheme);
runApp(
ArcaneApp(
child: MainApp(),
),
);
}
从这里开始,您可以遵循系统的主题:
// 遵循系统的主题模式
class MainApp extends StatefulWidget {
const MainApp({super.key});
[@override](/user/override)
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
[@override](/user/override)
Widget build(BuildContext context) {
return ArcaneApp(
child: MaterialApp(
theme: Arcane.theme.light,
darkTheme: Arcane.theme.dark,
themeMode: Arcane.theme.systemTheme.value,
),
);
}
[@override](/user/override)
void didChangeDependencies() {
Arcane.theme.followSystemTheme(context);
super.didChangeDependencies();
}
}
或者手动控制主题模式:
// 手动控制主题模式
class MainApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return ArcaneApp(
child: MaterialApp(
theme: Arcane.theme.light,
darkTheme: Arcane.theme.dark,
themeMode: Arcane.theme.currentMode,
),
);
}
}
然后,您可以随时切换模式:
// 在浅色和深色主题之间切换
Arcane.theme.switchTheme();
// 获取当前主题数据
final ThemeData currentTheme = Arcane.theme.currentMode == ThemeMode.dark
? Arcane.theme.dark
: Arcane.theme.light;
if (context.isDarkMode) {
// 当暗模式激活时执行某些操作
}
// 设置自定义暗主题
Arcane.theme.setDarkTheme(customDarkTheme);
// 设置自定义浅主题
Arcane.theme.setLightTheme(customLightTheme);
示例代码
以下是完整的示例代码:
import "package:arcane_framework/arcane_framework.dart";
import "package:example/config.dart";
import "package:example/interfaces/debug_auth_interface.dart";
import "package:example/interfaces/debug_print_interface.dart";
import "package:example/services/demo_service.dart";
import "package:example/theme/theme.dart";
import "package:flutter/material.dart";
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
for (final Feature feature in Feature.values) {
if (feature.enabledAtStartup) Arcane.features.enableFeature(feature);
}
await Future.wait([
Arcane.logger.registerInterfaces([
DebugPrint.I,
]),
IdService.I.init(),
]);
Arcane.logger.addPersistentMetadata({
"session_id": IdService.I.sessionId.value,
});
await Arcane.auth.registerInterface(DebugAuthInterface.I);
Arcane.theme
..setDarkTheme(darkTheme)
..setLightTheme(lightTheme);
Arcane.log(
"Initialization complete.",
level: Level.info,
module: "main",
method: "main",
metadata: {
"ready": "true",
},
);
runApp(const MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
[@override](/user/override)
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
[@override](/user/override)
Widget build(BuildContext context) {
return ArcaneApp(
services: [
IdService.I,
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: Arcane.theme.light,
darkTheme: Arcane.theme.dark,
themeMode: Arcane.theme.currentMode,
home: Scaffold(
appBar: AppBar(
title: const Text("Arcane Framework Example"),
actions: [
IconButton(
icon: const Icon(Icons.contrast),
onPressed: () {
Arcane.theme.switchTheme();
setState(() {});
},
),
],
),
body: const HomeScreen(),
),
),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
[@override](/user/override)
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
[@override](/user/override)
Widget build(BuildContext context) {
final bool isSignedIn = Arcane.auth.isSignedIn.value;
return Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Authentication status: ${Arcane.auth.status.name}",
),
if (isSignedIn)
ElevatedButton(
child: const Text("Sign out"),
onPressed: () async {
await Arcane.auth.logOut(
onLoggedOut: () async {
setState(() {});
},
);
},
),
if (!isSignedIn)
ElevatedButton(
child: const Text("Sign in"),
onPressed: () async {
await Arcane.auth.login<Map<String, String>>(
input: {
"email": "email",
"password": "password",
},
onLoggedIn: () async {
setState(() {});
},
);
},
),
],
),
),
);
}
}
更多关于Flutter神秘框架插件arcane_framework的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html