Flutter性能监控插件bucketeer_flutter_client_sdk的使用
Flutter性能监控插件bucketeer_flutter_client_sdk的使用
bucketeer_flutter_client_sdk
是一个用于在 Flutter 应用中集成 Bucketeer 功能的 SDK。Bucketeer 是一个开源平台,由 CyberAgent 创建,旨在帮助团队通过功能标志做出更好的决策,减少部署前置时间并降低发布风险。
安装
要将 bucketeer_flutter_client_sdk
添加到你的 Flutter 项目中,请在 pubspec.yaml
文件中添加以下依赖项:
dependencies:
bucketeer_flutter_client_sdk: ^版本号
然后运行 flutter pub get
来安装依赖项。
使用示例
下面是一个完整的示例,展示了如何在 Flutter 应用中初始化 bucketeer_flutter_client_sdk
并获取特征标志(Feature Flags)的值。
import 'package:bucketeer_example/snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:bucketeer_flutter_client_sdk/bucketeer_flutter_client_sdk.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ua_client_hints/ua_client_hints.dart';
import 'constant.dart';
const keyUserId = 'key_user_id';
Future<Map<String, String>> userMap() async {
final uaData = await userAgentData();
return {
'platform': uaData.platform, // e.g.. 'Android'
'platformVersion': uaData.platformVersion, // e.g.. '10'
'device': uaData.device, // e.g.. 'coral'
'appName': uaData.package.appName, // e.g.. 'SampleApp'
'appVersion': uaData.package.appVersion, // e.g.. '1.0.0'
'packageName': uaData.package.packageName, // e.g.. 'jp.wasabeef.ua'
'buildNumber': uaData.package.buildNumber, // e.g.. '1'
};
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
State<MyApp> createState() => _AppState();
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class _AppState extends State<MyApp>
with WidgetsBindingObserver
implements BKTEvaluationUpdateListener {
late final String _listenToken;
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(title: 'Bucketeer Demo'),
);
}
[@override](/user/override)
void initState() {
super.initState();
Future(() async {
// Generate UserId for Demo
final prefs = await SharedPreferences.getInstance();
var userId = prefs.getString(keyUserId);
if (userId == null) {
userId = 'demo-userId-${DateTime.now().millisecondsSinceEpoch}';
await prefs.setString(keyUserId, userId);
}
final config = BKTConfigBuilder()
.apiKey(Constants.apiKey)
.apiEndpoint(Constants.apiEndpoint)
.featureTag(Constants.exampleFeatureTag)
.debugging(true)
.eventsMaxQueueSize(Constants.exampleEventMaxQueueSize)
.eventsFlushInterval(Constants.exampleEventsFlushInterval)
.pollingInterval(Constants.examplePollingInterval)
.backgroundPollingInterval(Constants.exampleBackgroundPollingInterval)
.appVersion("1.0.0")
.build();
final user = BKTUserBuilder()
.id(userId)
.customAttributes({'app_version': "1.2.3"}).build();
final result = await BKTClient.initialize(config: config, user: user);
if (result.isSuccess) {
_listenToken =
await BKTClient.instance.addEvaluationUpdateListener(this);
} else if (result.isFailure) {
final errorMessage = result.asFailure.message;
debugPrint(errorMessage);
}
});
WidgetsBinding.instance.addObserver(this);
}
[@override](/user/override)
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
BKTClient.instance.removeEvaluationUpdateListener(_listenToken);
}
[@override](/user/override)
void onUpdate() {
// EvaluationUpdateListener onUpdate()
debugPrint("EvaluationUpdateListener.onUpdate() called");
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final flagController =
TextEditingController(text: Constants.exampleFeatureId);
final goalController = TextEditingController(text: 'bucketeer-goal-id');
final userIdController = TextEditingController(text: Constants.exampleUserId);
Future<void> _getStringVariation(String featureId) async {
final result = await BKTClient.instance
.stringVariation(featureId, defaultValue: 'default value');
debugPrint('getStringVariation: $result');
showSnackbar(title: 'getStringVariation', message: result);
}
Future<void> _getIntVariation(String featureId) async {
final result =
await BKTClient.instance.intVariation(featureId, defaultValue: 0);
debugPrint('getIntVariation: $result');
showSnackbar(title: 'getIntVariation', message: '$result');
}
Future<void> _getDoubleVariation(String featureId) async {
final result =
await BKTClient.instance.doubleVariation(featureId, defaultValue: 0.0);
debugPrint('getDoubleVariation: $result');
showSnackbar(title: 'getDoubleVariation', message: '$result');
}
Future<void> _getBoolVariation(String featureId) async {
final result =
await BKTClient.instance.boolVariation(featureId, defaultValue: false);
debugPrint('getBoolVariation: $result');
showSnackbar(title: 'getBoolVariation', message: '$result');
}
Future<void> _getObjectVariation(String featureId) async {
final result =
await BKTClient.instance.objectVariation(featureId, defaultValue: const BKTNumber(1.0));
debugPrint('objectVariation: $result');
showSnackbar(title: 'objectVariation', message: '${result.toJson()}');
}
Future<void> _getEvaluation(String featureId) async {
// ignore: deprecated_member_use
final result = await BKTClient.instance.evaluationDetails(featureId);
debugPrint('Successful get evaluation details');
if (result != null) {
showSnackbar(
title: 'getEvaluation(${result.toString()})',
message: 'Successful the evaluation.');
}
}
Future<void> _getJSONVariation(String featureId) async {
final result =
// ignore: deprecated_member_use
await BKTClient.instance.jsonVariation(featureId, defaultValue: {});
debugPrint('getJSONVariation: $result');
showSnackbar(title: 'getJSONVariation', message: '$result');
}
Future<void> _sendGoal(String goalId) async {
await BKTClient.instance.track(goalId, value: 3.1412);
showSnackbar(title: 'sendGoal', message: 'Successful the send goal.');
}
Future<void> _switchUser(String userId) async {
// Note: Please initialize the Bucketeer again when switching the user
final config = BKTConfigBuilder()
.apiKey(Constants.apiKey)
.apiEndpoint(Constants.apiEndpoint)
.featureTag(Constants.exampleFeatureTag)
.debugging(true)
.eventsMaxQueueSize(Constants.exampleEventMaxQueueSize)
.eventsFlushInterval(Constants.exampleEventsFlushInterval)
.pollingInterval(Constants.examplePollingInterval)
.backgroundPollingInterval(Constants.exampleBackgroundPollingInterval)
.appVersion("1.0.0")
.build();
final user = BKTUserBuilder()
.id(userId)
.customAttributes({'app_version': "1.2.3"}).build();
await BKTClient.instance.destroy();
final result = await BKTClient.initialize(
config: config,
user: user,
);
if (result.isSuccess || result.asFailure.exception is BKTTimeoutException) {
/// BKTClient.initialize success
const client = BKTClient.instance;
await client.updateUserAttributes(
{'app_version': "1.2.4"},
);
showSnackbar(title: 'setUser', message: 'Successful the switchUser.');
} else {
/// Print the error
showSnackbar(
title: 'initialize',
message: 'Failed with error ${result.asFailure.message}');
}
}
Future<void> _getCurrentUser() async {
final userRs = await BKTClient.instance.currentUser();
userRs.ifSuccess((user) {
showSnackbar(
title: 'getUser(${user.id})', message: user.attributes.toString());
});
userRs.ifFailure((message, exception) {
showSnackbar(title: 'currentUser', message: 'Failed with error $message');
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 36.0),
const Text(
'Feature Flag Id',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextFormField(
controller: flagController,
decoration: const InputDecoration(
hintText: 'bucketeer-feature-flag'),
),
const SizedBox(height: 12),
const Text('GET VARIATION',
style: TextStyle(fontWeight: FontWeight.bold)),
Wrap(
spacing: 8,
children: [
TextButton(
child: const Text('GET String param'),
onPressed: () async {
return _getStringVariation(flagController.text);
}),
TextButton(
child: const Text('GET int param'),
onPressed: () async {
return _getIntVariation(flagController.text);
}),
TextButton(
child: const Text('GET double params'),
onPressed: () async {
return _getDoubleVariation(flagController.text);
}),
TextButton(
child: const Text('GET bool params'),
onPressed: () async {
return _getBoolVariation(flagController.text);
}),
TextButton(
child: const Text('GET object params'),
onPressed: () async {
return _getObjectVariation(flagController.text);
}),
TextButton(
child: const Text('GET json params'),
onPressed: () async {
return _getJSONVariation(flagController.text);
}),
TextButton(
child: const Text('GET evaluation'),
onPressed: () async {
return _getEvaluation(flagController.text);
}),
],
),
const SizedBox(height: 36.0),
const Text(
'Goal Id',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextFormField(
controller: goalController,
decoration: InputDecoration(hintText: goalController.text),
),
TextButton(
child: const Text('SEND GOAL'),
onPressed: () async {
return _sendGoal(goalController.text);
}),
const SizedBox(height: 36.0),
const Text(
'User Id',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextFormField(
controller: userIdController,
decoration:
InputDecoration(hintText: userIdController.text),
),
Row(
children: [
TextButton(
child: const Text('SWITCH USER'),
onPressed: () async {
return _switchUser(userIdController.text);
}),
TextButton(
child: const Text('GET CURRENT USER'),
onPressed: () async {
return _getCurrentUser();
},
)
],
),
],
),
),
),
),
),
);
}
}
更多关于Flutter性能监控插件bucketeer_flutter_client_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter性能监控插件bucketeer_flutter_client_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
Bucketeer Flutter Client SDK
是一个用于在 Flutter 应用中集成 Bucketeer 功能(如 A/B 测试、功能标志等)的插件。虽然它主要用于功能管理和实验,但也可以间接地用于性能监控,通过跟踪功能标志的使用情况和用户行为来评估性能。
安装插件
首先,你需要在 pubspec.yaml
文件中添加 bucketeer_flutter_client_sdk
依赖:
dependencies:
bucketeer_flutter_client_sdk: ^1.0.0
然后运行 flutter pub get
来安装依赖。
初始化 SDK
在使用 Bucketeer Flutter Client SDK
之前,你需要初始化它。通常,你会在 main.dart
文件中进行初始化。
import 'package:bucketeer_flutter_client_sdk/bucketeer_flutter_client_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 Bucketeer SDK
await BucketeerClient.initialize(
apiKey: 'YOUR_API_KEY',
featureTag: 'YOUR_FEATURE_TAG',
user: BucketeerUser(id: 'USER_ID'),
);
runApp(MyApp());
}
使用功能标志
你可以使用 BucketeerClient
来获取功能标志的值,并根据这些值来决定应用的行为。
bool isFeatureEnabled = await BucketeerClient.getBoolVariation('FEATURE_KEY', defaultValue: false);
if (isFeatureEnabled) {
// 执行某些操作
} else {
// 执行其他操作
}
性能监控
虽然 Bucketeer Flutter Client SDK
本身并不是一个专门的性能监控工具,但你可以通过以下方式来间接监控性能:
-
跟踪功能标志的使用:通过记录功能标志的使用情况,你可以分析哪些功能对性能影响较大。
-
用户行为跟踪:通过 Bucketeer 的事件跟踪功能,你可以记录用户的行为,并分析这些行为对性能的影响。
-
A/B 测试:通过 A/B 测试,你可以比较不同功能版本对应用性能的影响,并选择最优的版本。
事件跟踪
你可以使用 BucketeerClient
来跟踪自定义事件:
BucketeerClient.trackEvent('event_name', metadata: {'key': 'value'});