Flutter特性管理插件flutter_bucketeer的使用

Flutter特性管理插件flutter_bucketeer的使用

概述

本文将详细介绍如何在Flutter项目中使用特性管理插件flutter_bucketeer。我们将通过一个完整的示例来展示如何集成该插件并进行基本操作。

安装

首先,确保你的项目已经安装了必要的依赖项。在项目的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter_bucketeer: ^1.x.x

然后运行以下命令来获取这些依赖项:

$ flutter pub get

示例代码

接下来,我们将展示如何在Flutter应用中使用flutter_bucketeer插件。以下是完整的示例代码:

import 'package:bucketeer_example/snack_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bucketeer/bucketeer.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ua_client_hints/ua_client_hints.dart';

const keyUserId = 'key_user_id';

Future<Map<String, String>> userMap() async {
  final uaData = await userAgentData();
  return {
    'platform': uaData.platform, // 例如: 'Android'
    'platformVersion': uaData.platformVersion, // 例如: '10'
    'device': uaData.device, // 例如: 'coral'
    'appName': uaData.package.appName, // 例如: 'SampleApp'
    'appVersion': uaData.package.appVersion, // 例如: '1.0.0'
    'packageName': uaData.package.packageName, // 例如: 'jp.wasabeef.ua'
    'buildNumber': uaData.package.buildNumber, // 例如: '1'
  };
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  State<MyApp> createState() {
    return _AppState();
  }
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Bucketeer.instance
    ..initialize(
      apiKey: 'YOUR_API_KEY',
      endpoint: 'YOUR_ENDPOINT.bucketeer.jp',
      featureTag: 'Flutter',
      debugging: true,
      logSendingIntervalMillis: 3000,
      logSendingMaxBatchQueueCount: 3,
      pollingEvaluationIntervalMillis: 3000,
    );
  runApp(MyApp());
}

class _AppState extends State<MyApp> with WidgetsBindingObserver {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Bucketeer Demo'),
    );
  }

  [@override](/user/override)
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      Bucketeer.instance.start();
    } else if (state == AppLifecycleState.paused) {
      Bucketeer.instance.stop();
    }
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    Future(() async {
      // 生成用户ID用于演示
      final prefs = await SharedPreferences.getInstance();
      final userId = prefs.getString(keyUserId);
      if (userId == null) {
        await prefs.setString(
            keyUserId, 'demo-userId-${DateTime.now().millisecondsSinceEpoch}');
      } else {
        await Bucketeer.instance.setUser(userId, userMap: await userMap());
      }
    });
    WidgetsBinding.instance.addObserver(this);
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final flagController = TextEditingController(text: 'bucketeer-feature-flag');
  final goalController = TextEditingController(text: 'bucketeer-goal-id');
  final userIdController = TextEditingController(text: 'bucketeer-flutter-user-id');

  Future<void> _getStringVariation(String featureId) async {
    final result = await Bucketeer.instance
        .getStringVariation(featureId, defaultValue: 'default value');
    result.ifSuccess((data) {
      print('getStringVariation: ${data}');
      showSnackbar(
          context: context, title: 'getStringVariation', message: data);
    });
  }

  Future<void> _getIntVariation(String featureId) async {
    final result =
        await Bucketeer.instance.getIntVariation(featureId, defaultValue: 0);
    result.ifSuccess((data) {
      print('getIntVariation: $data');
      showSnackbar(
          context: context, title: 'getIntVariation', message: '$data');
    });
  }

  Future<void> _getDoubleVariation(String featureId) async {
    final result = await Bucketeer.instance
        .getDoubleVariation(featureId, defaultValue: 0.0);
    result.ifSuccess((data) {
      print('getDoubleVariation: $data');
      showSnackbar(
          context: context, title: 'getDoubleVariation', message: '$data');
    });
  }

  Future<void> _getBoolVariation(String featureId) async {
    final result = await Bucketeer.instance
        .getBoolVariation(featureId, defaultValue: false);
    result.ifSuccess((data) {
      print('getBoolVariation: $data');
      showSnackbar(
          context: context, title: 'getBoolVariation', message: '$data');
    });
  }

  Future<void> _getEvaluation(String featureId) async {
    final result = await Bucketeer.instance.getEvaluation(featureId);
    result.ifSuccess((evaluation) {
      print('Successful the evaluation');
      showSnackbar(
          context: context,
          title: 'getEvaluation(${evaluation.toString()})',
          message: 'Successful the evaluation.');
    });
  }

  Future<void> _sendGoal(String goalId) async {
    final result = await Bucketeer.instance.track(goalId, value: 3.1412);
    if (result.isSuccess) {
      print('Successful the send goal.');
      showSnackbar(
          context: context,
          title: 'sendGoal',
          message: 'Successful the send goal.');
    } else {
      print('Failed the send goal.');
      showSnackbar(
          context: context,
          title: 'sendGoal',
          message: 'Failed the send goal.');
    }
  }

  Future<void> _switchUser(String userId) async {
    final result =
        await Bucketeer.instance.setUser(userId, userMap: await userMap());
    result.ifSuccess((_) {
      print('Successful the setUser');
      showSnackbar(
          context: context,
          title: 'setUser',
          message: 'Successful the setUser.');
    });
  }

  Future<void> _getCurrentUser() async {
    final result = await Bucketeer.instance.getUser();
    result.ifSuccess((user) {
      print('Successful the getUser');
      showSnackbar(
          context: context,
          title: 'getUser(${user.id})',
          message: 'Successful the getUser.');
    });
  }

  [@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: [
                  SizedBox(height: 36.0),
                  Text(
                    'Feature Flag Id',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  TextFormField(
                    controller: flagController,
                    decoration:
                        InputDecoration(hintText: 'bucketeer-feature-flag'),
                  ),
                  const SizedBox(height: 12),
                  Text('GET VARIATION',
                      style: TextStyle(fontWeight: FontWeight.bold)),
                  Wrap(
                    spacing: 8,
                    children: [
                      TextButton(
                          child: Text('GET String param'),
                          onPressed: () async {
                            return _getStringVariation(flagController.text);
                          }),
                      TextButton(
                          child: Text('GET int param'),
                          onPressed: () async {
                            return _getIntVariation(flagController.text);
                          }),
                      TextButton(
                          child: Text('GET double params'),
                          onPressed: () async {
                            return _getDoubleVariation(flagController.text);
                          }),
                      TextButton(
                          child: Text('GET bool params'),
                          onPressed: () async {
                            return _getBoolVariation(flagController.text);
                          }),
                      TextButton(
                          child: Text('GET evalution'),
                          onPressed: () async {
                            return _getEvaluation(flagController.text);
                          }),
                    ],
                  ),
                  SizedBox(height: 36.0),
                  Text(
                    'Goal Id',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  TextFormField(
                    controller: goalController,
                    decoration: InputDecoration(hintText: goalController.text),
                  ),
                  TextButton(
                      child: Text('SEND GOAL'),
                      onPressed: () async {
                        return _sendGoal(goalController.text);
                      }),
                  SizedBox(height: 36.0),
                  Text(
                    'User Id',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  TextFormField(
                    controller: userIdController,
                    decoration:
                        InputDecoration(hintText: userIdController.text),
                  ),
                  Row(
                    children: [
                      TextButton(
                          child: Text('SWITCH USER'),
                          onPressed: () async {
                            return _switchUser(userIdController.text);
                          }),
                      TextButton(
                        child: Text('GET CURRENT USER'),
                        onPressed: () async {
                          return _getCurrentUser();
                        },
                      )
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

更多关于Flutter特性管理插件flutter_bucketeer的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter特性管理插件flutter_bucketeer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_bucketeer 是一个用于 Flutter 的特性管理插件,它可以帮助你在应用中实现特性标志(Feature Flags)的管理。特性标志允许你在不重新部署应用的情况下,动态地开启或关闭某些功能。这在 A/B 测试、逐步推出新功能或快速回滚问题功能时非常有用。

1. 安装 flutter_bucketeer

首先,你需要在 pubspec.yaml 文件中添加 flutter_bucketeer 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_bucketeer: ^0.1.0  # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 初始化 flutter_bucketeer

在你的 Flutter 应用中初始化 flutter_bucketeer。你可以在应用的 main.dart 文件中进行初始化:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化 Bucketeer
  await Bucketeer.init(
    apiKey: 'YOUR_API_KEY',
    userId: 'USER_ID',  // 可以是用户的唯一标识符
    countryCode: 'US',  // 可选
    appVersion: '1.0.0',  // 可选
  );

  runApp(MyApp());
}

3. 获取特性标志

在初始化之后,你可以通过 Bucketeer 类来获取特性标志的值。特性标志可以是布尔值、字符串、数字等类型。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取特性标志
    bool isFeatureEnabled = Bucketeer.getBool('feature_flag_key', defaultValue: false);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Bucketeer Example'),
        ),
        body: Center(
          child: isFeatureEnabled
              ? Text('Feature is enabled!')
              : Text('Feature is disabled!'),
        ),
      ),
    );
  }
}

4. 更新特性标志

你可以使用 Bucketeerupdate 方法来手动更新特性标志。这对于在特定事件或用户操作后重新获取最新的特性标志非常有用。

void updateFeatureFlags() async {
  await Bucketeer.update();
}

5. 处理特性标志的变化

flutter_bucketeer 还允许你监听特性标志的变化,以便在标志值发生变化时做出相应的处理。

Bucketeer.addListener('feature_flag_key', (value) {
  print('Feature flag changed to: $value');
});
回到顶部