GrowthBook Flutter SDK。
概述
GrowthBook 是一个开源功能标志和实验平台,无需部署新代码即可轻松调整向用户显示的功能,并运行 A/B 测试。GrowthBook 分为两个部分:GrowthBook 应用程序和实现此功能的 SDK。此 Flutter SDK 允许您在基于 Flutter 的移动应用程序中使用 GrowthBook。
- 轻巧快速
- 支持
- Android
- iOS
- Mac
- Windows
- 使用您现有的事件跟踪(GA、Segment、Mixpanel、自定义)
- 无需部署新代码即可调整变体权重和定位
安装
- 将 GrowthBook SDK 添加为 pubspec.yaml 文件中的依赖项。
growthbook_sdk_flutter: ^1.0.0
集成
集成非常简单
- 从 GrowthBook 应用程序创建 GrowthBook API 密钥。
- 如下,在应用程序开头初始化 SDK,传入 API 密钥。
现在,您可以在 Growth Book 应用程序中启动/停止测试、调整覆盖率和变体权重,并将获胜变体应用于 100% 的流量,而无需将代码更改部署到您的站点。
final GrowthBookSDK sdkInstance = GBSDKBuilderApp(
apiKey: "<API_KEY>",
attributes: {
/// Specify attributes.
},
growthBookTrackingCallBack: (gbExperiment, gbExperimentResult) {},
hostURL: '<GrowthBook_URL>',
).initialize();
初始化时还有其他属性可以设置
final GrowthBookSDK newSdkInstance = GBSDKBuilderApp(
apiKey: "<API_KEY>",
attributes: {
/// Specify user attributes.
},
growthBookTrackingCallBack: (gbExperiment, gbExperimentResult) {},
hostURL: '<GrowthBook_URL>',
).setNetworkDispatcher(
// set network dispatcher.
)
.setForcedVariations({})
. // Set forced variations
setQAMode(true)// Set qamode
.initialize();
用法
-
初始化返回 SDK 实例 – GrowthBookSDK
使用 sdkInstance 来使用以下功能 –
-
feature 方法接受一个字符串参数,即功能的唯一标识符,并返回一个 FeatureResult 对象。
GBFeatureResult feature(String id)
-
run 方法接受一个 Experiment 对象并返回一个 ExperimentResult
GBExperimentResult run(GBExperiment experiment)
- 获取上下文
GBContext getGBContext()
- 获取功能
GBFeatures getFeatures()
模型
/// Defines the GrowthBook context.
class GBContext {
GBContext({
this.apiKey,
this.hostURL,
this.enabled,
this.attributes,
this.forcedVariation,
this.qaMode,
this.trackingCallBack,
});
/// Registered API key for GrowthBook SDK.
String? apiKey;
/// Host URL for GrowthBook
String? hostURL;
/// Switch to globally disable all experiments. Default true.
bool? enabled;
/// Map of user attributes that are used to assign variations
Map<String, dynamic>? attributes;
/// Force specific experiments to always assign a specific variation (used for QA).
Map<String, dynamic>? forcedVariation;
/// If true, random assignment is disabled and only explicitly forced variations are used.
bool? qaMode;
/// A function that takes experiment and result as arguments.
TrackingCallBack? trackingCallBack;
/// Keys are unique identifiers for the features and the values are Feature objects.
/// Feature definitions - To be pulled from API / Cache
GBFeatures features = <String, GBFeature>{};
}
/// A Feature object consists of possible values plus rules for how to assign values to users.
class GBFeature {
GBFeature({
this.rules,
this.defaultValue,
});
/// The default value (should use null if not specified)
///2 Array of Rule objects that determine when and how the defaultValue gets overridden
List<GBFeatureRule>? rules;
/// The default value (should use null if not specified)
dynamic defaultValue;
factory GBFeature.fromMap(Map<String, dynamic> dataMap) {
return GBFeature(
rules: dataMap['rules'] != null
? List<GBFeatureRule>.from(
(dataMap['rules'] as List).map(
(e) => GBFeatureRule.fromMap(e),
),
)
: null,
defaultValue: dataMap["defaultValue"],
);
}
}
/// Rule object consists of various definitions to apply to calculate feature value
class GBFeatureRule {
GBFeatureRule({
this.condition,
this.coverage,
this.force,
this.variations,
this.key,
this.weights,
this.nameSpace,
this.hashAttribute,
});
/// Optional targeting condition
GBCondition? condition;
/// What percent of users should be included in the experiment (between 0 and 1, inclusive)
double? coverage;
/// Immediately force a specific value (ignore every other option besides condition and coverage)
dynamic force;
/// Run an experiment (A/B test) and randomly choose between these variations
List<dynamic>? variations;
/// The globally unique tracking key for the experiment (default to the feature key)
String? key;
/// How to weight traffic between variations. Must add to 1.
List<double>? weights;
/// A tuple that contains the namespace identifier, plus a range of coverage for the experiment.
List? nameSpace;
/// What user attribute should be used to assign variations (defaults to id)
String? hashAttribute;
factory GBFeatureRule.fromMap(Map<String, dynamic> mappedData) {
return GBFeatureRule(
nameSpace: mappedData['namespace'],
condition: mappedData['condition'],
coverage: (mappedData['coverage'] as num?)?.toDouble(),
variations: mappedData['variations'] != null
? List<dynamic>.from(mappedData['variations'].map((e) => e))
: null,
key: mappedData['key'],
weights: mappedData['weights'] != null
? List<double>.from(mappedData['weights'])
: null,
force: mappedData['force'],
hashAttribute: mappedData["hashAttribute"],
);
}
}
/// Enum For defining feature value source.
@EnhancedEnum()
enum GBFeatureSource {
/// Queried Feature doesn't exist in GrowthBook.
@EnhancedEnumValue(name: 'unknownFeature')
unknownFeature,
/// Default Value for the Feature is being processed.
@EnhancedEnumValue(name: 'defaultValue')
defaultValue,
/// Forced Value for the Feature is being processed.
@EnhancedEnumValue(name: 'force')
force,
/// Experiment Value for the Feature is being processed.
@EnhancedEnumValue(name: 'experiment')
experiment
}
/// Result for Feature
class GBFeatureResult {
GBFeatureResult({
this.value,
this.on,
this.off,
this.source,
this.experiment,
this.experimentResult,
});
/// The assigned value of the feature
dynamic value;
/// The assigned value cast to a boolean
bool? on = false;
/// The assigned value cast to a boolean and then negated
bool? off = true;
/// One of "unknownFeature", "defaultValue", "force", or "experiment"
GBFeatureSource? source;
/// When source is "experiment", this will be the Experiment object used
GBExperiment? experiment;
///When source is "experiment", this will be an ExperimentResult object
GBExperimentResult? experimentResult;
}
/// Defines a single experiment
class GBExperiment {
GBExperiment({
this.key,
this.variations,
this.namespace,
this.condition,
this.hashAttribute,
this.weights,
this.active = true,
this.coverage,
this.force,
});
factory GBExperiment.fromMap(Map<String, dynamic> map) => GBExperiment(
key: map['key'],
namespace: map['namespace'],
variations: map['variations'],
hashAttribute: map['hashAttribute'],
weights: map['weights'],
active: map['active'] ?? true,
coverage: map['coverage'],
force: map['force'],
condition: map['condition']);
/// The globally unique tracking key for the experiment
String? key;
/// The different variations to choose between
List? variations = [];
/// A tuple that contains the namespace identifier, plus a range of coverage for the experiment
List? namespace;
/// All users included in the experiment will be forced into the specific variation index
String? hashAttribute;
/// How to weight traffic between variations. Must add to 1.
List? weights;
/// If set to false, always return the control (first variation)
bool active;
/// What percent of users should be included in the experiment (between 0 and 1, inclusive)
double? coverage;
/// Optional targeting condition
GBCondition? condition;
/// All users included in the experiment will be forced into the specific variation index
int? force;
///Check if experiment is not active.
bool get deactivated => !active;
}
/// The result of running an Experiment given a specific Context
class GBExperimentResult {
GBExperimentResult({
this.inExperiment,
this.variationID,
this.value,
this.hasAttributes,
this.hashValue,
});
/// Whether or not the user is part of the experiment
bool? inExperiment;
/// The array index of the assigned variation
int? variationID;
/// The array value of the assigned variation
dynamic value;
/// The user attribute used to assign a variation
String? hasAttributes;
/// The value of that attribute
String? hashValue;
}
许可证
该项目使用 MIT 许可证。核心 GrowthBook 应用程序将始终保持开放和免费,尽管我们将来可能会添加一些商业企业插件。
