Flutter宏定义参数传递插件args_macro的使用
Flutter宏定义参数传递插件args_macro的使用
简介
args_macro
插件用于生成命令行参数解析器,基于你的数据类。它封装了标准的 args
包。
使用
import 'package:args_macro/args_macro.dart';
@Args()
class MyArgs {
final String requiredString;
final String? optionalString;
String stringWithDefault = 'My default string.';
final int requiredInt;
final int? optionalInt;
int intWithDefault = 7;
final double requiredDouble;
final double? optionalDouble;
double doubleWithDefault = 7.77;
bool boolWithDefaultFalse = false;
bool boolWithDefaultTrue = true;
final Fruit requiredEnum;
final Fruit? optionalEnum;
Fruit enumWithDefault = Fruit.mango;
final List<String> stringList;
List<String> stringListWithDefault = ['Huey', 'Dewey', 'Louie'];
final List<int> intList;
List<int> intListWithDefault = [1, 2];
final List<double> doubleList;
List<double> doubleListWithDefault = [1, 2.0];
final List<Fruit> enumList;
List<Fruit> enumListWithDefault = [Fruit.apple, Fruit.banana];
}
enum Fruit { apple, banana, mango, orange }
void main(List<String> argv) {
final parser = MyArgsParser(); // 生成的类。
final MyArgs args = parser.parse(argv);
// ...
}
这将创建一个包含解析数据的 MyArgs
类实例。
参数类型配置
- 非空字段:无初始值的非空字段会创建一个必填选项。
- 可空字段:无初始值的可空字段会创建一个默认为
null
的可选选项。 - 有初始值的字段:有初始值的字段会创建一个具有默认值的可选选项。此类字段不能为
final
或nullable
。
支持的类型
字符串(String)
字符串选项不会被解释。
@Args()
class MyArgs {
final String requiredString;
final String? optionalString;
String stringWithDefault = 'My default string.';
}
整数(int)
整数通过 int.parse(String)
进行解析。如果无法解析,调用 MyArgsParser.parse()
会显示消息并终止程序。
@Args()
class MyArgs {
final int requiredInt;
final int? optionalInt;
int intWithDefault = 7;
}
双精度浮点数(double)
双精度浮点数通过 double.parse(String)
进行解析。如果无法解析,调用 MyArgsParser.parse()
会显示消息并终止程序。
@Args()
class MyArgs {
final double requiredDouble;
final double? optionalDouble;
double doubleWithDefault = 7.77;
}
布尔值(bool)
布尔字段生成一个标志。布尔字段必须有初始值,因为它们不能被要求,缺少一个标志意味着其不存在。因此,布尔字段也不能为 nullable
。
通常你希望默认为 false
的布尔值,添加标志会将其更改为 true
。对于默认为 true
的字段,会产生一个标志来否定它,并在标志名称前加上 no-
。
@Args()
class MyArgs {
bool boolWithDefaultFalse = false; // 使用 --bool-with-default-false 来使其为 true。
bool boolWithDefaultTrue = true; // 使用 --no-bool-with-default-true 来使其为 false。
}
枚举(enum)
枚举通过 MyEnum.values.byName(String)
进行解析。如果值与任何枚举常量不匹配,调用 MyArgsParser.parse()
会显示消息并终止程序。
@Args()
class MyArgs {
final Fruit requiredEnum;
final Fruit? optionalEnum;
Fruit enumWithDefault = Fruit.mango;
}
enum Fruit { apple, banana, mango, orange }
列表和集合(List, Set)
List
和 Set
字段生成的选项可以在命令行中多次传递。每次传递都会向集合添加一个项目。
可以使用默认值,如果选项未传递零次。
如果不在乎值的顺序且希望去重,请使用 Set
。否则,使用 List
。
这些集合支持 String
、int
、double
和 enum
。
@Args()
class MyArgs {
final List<String> stringList;
List<String> stringListWithDefault = ['Huey', 'Dewey', 'Louie'];
final List<int> intList;
List<int> intListWithDefault = [1, 2];
final List<double> doubleList;
List<double> doubleListWithDefault = [1, 2.0];
final List<Fruit> enumList;
List<Fruit> enumListWithDefault = [Fruit.apple, Fruit.banana];
final Set<String> stringSet;
Set<String> stringSetWithDefault = {'Huey', 'Dewey', 'Louie'};
final Set<int> intSet;
Set<int> intSetWithDefault = {3, 4};
final Set<double> doubleSet;
Set<double> doubleSetWithDefault = {3, 4.0};
final Set<Fruit> enumSet;
Set<Fruit> enumSetWithDefault = {Fruit.orange, Fruit.banana};
}
enum Fruit { apple, banana, mango, orange }
帮助信息
解析器自动添加 --help
选项。它打印使用信息并终止程序 (parse()
方法永远不会返回)。
添加帮助信息
要为选项添加帮助信息,请定义一个静态变量,前面加上下划线并追加 Help
:
@Args()
class MyArgs {
final String requiredString;
static const _requiredStringHelp = 'Help for the required string.';
// ...
}
可执行文件名和描述
要将帮助文本前缀为描述和命令示例,请将以下参数传递给宏:
@Args(
description: 'The command description.',
executableName: 'executable_name',
)
class MyArgs { /* ... */ }
示例帮助输出
这是完整的示例文件的输出:
The command description.
Usage: executable_name [arguments]
--required-string (mandatory) Help for the required string.
--optional-string
--string-with-default (defaults to "My default string.")
--required-int (mandatory)
--optional-int Help for the optional int.
--int-with-default (defaults to "7")
--required-double (mandatory) Help for the required double.
--optional-double
--double-with-default (defaults to "7.77")
--bool-with-default-false Help for the flag.
--no-bool-with-default-true
--required-enum (mandatory) [apple, banana, mango, orange]
--optional-enum Help for the optional Enum.
[apple, banana, mango, orange]
--enum-with-default [apple, banana, mango (default), orange]
--string-list
--string-list-with-default Help for String[] with default.
(defaults to "Huey", "Dewey", "Louie")
--int-list Help for int[].
--int-list-with-default (defaults to "1", "2")
--double-list Help for double[].
--double-list-with-default (defaults to "1.0", "2.0")
--enum-list Help for Enum[].
[apple, banana, mango, orange]
--enum-list-with-default [apple (default), banana (default), mango, orange]
--string-set Help for String{}.
--string-set-with-default (defaults to "Huey", "Dewey", "Louie")
--int-set Help for int{}.
--int-set-with-default (defaults to "3", "4")
--double-set Help for double{}.
--double-set-with-default (defaults to "3.0", "4.0")
--enum-set Help for Enum{}.
[apple, banana, mango, orange]
--enum-set-with-default [apple, banana, mango (default), orange]
-h, --help Print this usage information.
错误处理
除非传递了 --help
,所有数据都会根据你的数据类结构进行验证。发生任何错误时,parse()
方法会将第一个错误和使用信息打印到 stderr
并终止程序,退出代码为 64。
要忽略所有错误但仍然让解析器填充由你的数据类派生的选项(并跳过 --help
的自动处理),请使用标准的 ArgParser
实例,该解析器包装了此生成的解析器。它将返回普通的 ArgResults
而没有任何错误处理:
void main(List<String> argv) {
final result = MyArgsParser().parser.parse(argv);
print(result.option('required-string'));
}
更多关于Flutter宏定义参数传递插件args_macro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter宏定义参数传递插件args_macro的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中,如果你需要利用宏定义参数传递插件(如args_macro
,尽管这不是一个官方的Flutter插件,但假设它提供类似功能),你可以通过创建和使用Flutter平台通道(Platform Channel)结合Dart宏定义来实现参数的传递。不过,由于Dart本身并不支持C/C++风格的宏定义,我们通常通过常量或配置来实现类似效果。
以下是一个简化的示例,展示了如何通过平台通道在Flutter和原生代码之间传递参数,并结合Dart中的常量定义来模拟宏定义的效果。
1. 设置Flutter项目
首先,确保你的Flutter项目已经创建。如果还没有,可以使用以下命令创建:
flutter create my_flutter_app
cd my_flutter_app
2. 定义Dart常量(模拟宏定义)
在lib
目录下创建一个新的Dart文件,比如config.dart
,用于定义常量:
// lib/config.dart
class Config {
static const String apiEndpoint = "https://api.example.com";
static const bool enableLogging = true;
}
3. 创建Flutter平台通道
在lib/main.dart
中,设置平台通道以从原生代码接收参数(虽然这个例子没有直接传递宏定义,但展示了参数传递的过程):
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'config.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const platform = MethodChannel('com.example.flutterapp/channel');
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Macro Args Example'),
),
body: Center(
child: FutureBuilder<String?>(
future: _getPlatformVersion(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Text('Failed to get platform version: ${snapshot.error!}');
} else {
// 这里可以处理从原生代码传递过来的参数
// 例如,假设原生代码传递了一个名为"nativeParam"的参数
String? nativeParam = snapshot.data;
return Text('Received from native: $nativeParam\nConfig API Endpoint: ${Config.apiEndpoint}');
}
} else {
return CircularProgressIndicator();
}
},
),
),
),
);
}
Future<String?> _getPlatformVersion() async {
try {
final String? version = await platform.invokeMethod('getPlatformVersion');
return version;
} on PlatformException catch (e) {
return "Failed to get platform version: '${e.message}'".trim();
}
}
}
4. 在原生代码中实现平台通道
iOS (Swift)
在ios/Runner/AppDelegate.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.flutterapp/channel", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler {
(call: FlutterMethodCall, result: @escaping FlutterResult) in
if call.method == "getPlatformVersion" {
let version = UIDevice.current.systemVersion
result(version)
} else {
result(FlutterMethodNotImplemented)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Android (Kotlin)
在android/app/src/main/kotlin/.../MainActivity.kt
中,添加平台通道的实现:
package com.example.flutterapp
import android.os.Bundle
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.flutterapp/channel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getPlatformVersion") {
result.success(android.os.Build.VERSION.RELEASE)
} else {
result.notImplemented()
}
}
}
}
总结
虽然Dart不支持传统意义上的宏定义,但你可以通过常量配置和平台通道在Flutter和原生代码之间传递参数。上述示例展示了如何在Flutter应用中设置平台通道,并从原生代码中获取参数,同时利用Dart常量来模拟一些配置参数。根据你的需求,你可以进一步扩展这些代码来处理更复杂的参数传递逻辑。