Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Protobuf from the ABT SDK #5890

Merged
merged 42 commits into from Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d51514a
Remove Protobuf dependency, add struct-ish class that mimics ABTExper…
christibbs Jun 4, 2020
098e417
Remove a lot of the compiler errors, but not all of them. We need to …
christibbs Jun 4, 2020
912bb9c
Add ABTExperimentPayload class that replaces generated proto, refacto…
christibbs Jun 17, 2020
d505e03
Add unit testing class for ABTExperimentPayload
christibbs Jun 19, 2020
33d84c8
Updates to ABTExperimentPayload API, tests for ABTConditionalUserProp…
christibbs Jun 23, 2020
c952d0f
Update podspec to pull in testing resources
christibbs Jun 23, 2020
bb2ce4c
Add utility class for parsing test files. Use it in ABTExperimentPayl…
christibbs Jun 23, 2020
7c3e642
Fix FIRExperimentController tests
christibbs Jun 24, 2020
220b383
Merge in master
christibbs Jun 24, 2020
5af4ccd
Better documentation
christibbs Jun 24, 2020
360a659
Run scripts/styles.sh
christibbs Jun 24, 2020
fd1009a
Fix whitespace
christibbs Jun 24, 2020
dade3e0
Remove protobuf imports
christibbs Jun 24, 2020
b73cb00
Bump pod spec version for ABT SDK, depend on new ABT SDK in RC. Fix u…
christibbs Jun 24, 2020
35d1ec9
scripts/style.sh
christibbs Jun 24, 2020
c2b6de3
Update In-app messaging to use new ABTExperimentPayload class, which …
christibbs Jun 24, 2020
12b9edb
Delete test payload
christibbs Jun 24, 2020
f6bc47d
Revert scripts/check_imports.swift
christibbs Jun 24, 2020
9d9798b
Better initialization tags for ABTExperimentLite
christibbs Jun 24, 2020
71f9f63
Update CHANGELOGs
christibbs Jun 24, 2020
e793817
Remove private headers in podspec, use integerValue to parse integers
christibbs Jun 24, 2020
3542804
Refactor ABTExperimentPayload header into Private headers. Fix intege…
christibbs Jun 24, 2020
2e2feb0
scripts/styles.sh
christibbs Jun 24, 2020
a7a03bc
Fix integer parsing
christibbs Jun 24, 2020
0491e3b
Merge branch 'master' into abt-remove-protobuf
christibbs Jun 24, 2020
511e0b3
Fix copyrights
christibbs Jun 25, 2020
c75c41b
Fix CHANGELOG typo:
christibbs Jun 25, 2020
8e836ca
Add private_header_files to public_header_files
christibbs Jun 25, 2020
49c6f99
Merge branch 'abt-remove-protobuf' of github.com:firebase/firebase-io…
christibbs Jun 25, 2020
8088d0b
Merge branch 'master' into abt-remove-protobuf
christibbs Jun 25, 2020
0ccb66c
Try just using NSInteger for experimentStartTimeMillis
christibbs Jun 25, 2020
06831d2
Merge branch 'abt-remove-protobuf' of github.com:firebase/firebase-io…
christibbs Jun 25, 2020
cec1309
Bump FIAM dependency on ABTesting
christibbs Jun 25, 2020
de42dd0
Use long long for milli parameters (32-bit apps)
christibbs Jun 26, 2020
4b97861
Merge branch 'master' into abt-remove-protobuf
christibbs Jun 26, 2020
2fb019e
Use longlong in test timestamps
christibbs Jun 26, 2020
7f7c1c4
Merge branch 'abt-remove-protobuf' of github.com:firebase/firebase-io…
christibbs Jun 26, 2020
aba7f30
Don't cast to nsnumber in tests
christibbs Jun 26, 2020
bd89501
Use in64_t
christibbs Jun 26, 2020
f5ef534
Fix Test Overflow
paulb777 Jun 26, 2020
84d865f
Bump major version on ABT SDK
christibbs Jun 29, 2020
8e68e3e
Bump ABTesting version in Firebase.podspec
christibbs Jul 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Firebase.podspec
Expand Up @@ -61,7 +61,7 @@ Simplify your app development, grow your user base, and monetize more effectivel

s.subspec 'ABTesting' do |ss|
ss.dependency 'Firebase/CoreOnly'
ss.dependency 'FirebaseABTesting', '~> 3.3.0'
ss.dependency 'FirebaseABTesting', '~> 4.0.0'
end

s.subspec 'AdMob' do |ss|
Expand Down
11 changes: 5 additions & 6 deletions FirebaseABTesting.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FirebaseABTesting'
s.version = '3.3.0'
s.version = '4.0.0'
s.summary = 'Firebase ABTesting'

s.description = <<-DESC
Expand Down Expand Up @@ -35,20 +35,19 @@ Firebase Cloud Messaging and Firebase Remote Config in your app.
'FirebaseCore/Sources/Private/*.h',
]
s.requires_arc = base_dir + '*.m'
s.public_header_files = base_dir + 'Public/*.h', base_dir + 'Protos/developers/mobile/abt/proto/*.h'
s.private_header_files = base_dir + 'Protos/developers/mobile/abt/proto/*.h'
s.public_header_files = base_dir + 'Public/*.h', base_dir + 'Private/*.h'
s.private_header_files = base_dir + 'Private/*.h'
s.pod_target_xcconfig = {
'GCC_C_LANGUAGE_STANDARD' => 'c99',
'GCC_PREPROCESSOR_DEFINITIONS' =>
'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 ' +
'FIRABTesting_VERSION=' + String(s.version),
'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"'
}
s.dependency 'FirebaseCore', '~> 6.8'
christibbs marked this conversation as resolved.
Show resolved Hide resolved
s.dependency 'Protobuf', '~> 3.9', '>= 3.9.2'

s.test_spec 'unit' do |unit_tests|
unit_tests.source_files = 'FirebaseABTesting/Tests/Unit/*.[mh]'
unit_tests.source_files = 'FirebaseABTesting/Tests/Unit/**/*.[mh]'
unit_tests.resources = 'FirebaseABTesting/Tests/Unit/Resources/*.txt'
unit_tests.requires_app_host = true
unit_tests.dependency 'OCMock'
end
Expand Down
3 changes: 3 additions & 0 deletions FirebaseABTesting/CHANGELOG.md
@@ -1,3 +1,6 @@
# v4.0.0
- [changed] Removed Protobuf dependency (#5890).

# v3.2.0
- [added] Added completion handler for FIRExperimentController's updateExperimentsWithServiceOrigin method.
- [deprecated] Deprecated `FIRExperimentController.updateExperiments(serviceOrigin:events:policy:lastStartTime:payloads:)`.
Expand Down
Expand Up @@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#import <FirebaseABTesting/ABTExperimentPayload.h>
#import <Foundation/Foundation.h>

#import "FirebaseABTesting/Sources/Protos/developers/mobile/abt/proto/ExperimentPayload.pbobjc.h"

#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -69,7 +68,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)setExperimentWithOrigin:(NSString *)origin
payload:(ABTExperimentPayload *)payload
events:(FIRLifecycleEvents *)events
policy:(ABTExperimentPayload_ExperimentOverflowPolicy)policy;
policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy;

/**
* Unavailable. Use sharedInstanceWithAnalytics: instead.
Expand Down
18 changes: 9 additions & 9 deletions FirebaseABTesting/Sources/ABTConditionalUserPropertyController.m
Expand Up @@ -73,7 +73,7 @@ - (void)clearExperiment:(NSString *)experimentID
- (void)setExperimentWithOrigin:(NSString *)origin
payload:(ABTExperimentPayload *)payload
events:(FIRLifecycleEvents *)events
policy:(ABTExperimentPayload_ExperimentOverflowPolicy)policy {
policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy {
NSInteger maxNumOfExperiments = [self maxNumberOfExperimentsOfOrigin:origin];
if (maxNumOfExperiments < 0) {
return;
Expand All @@ -88,10 +88,10 @@ - (void)setExperimentWithOrigin:(NSString *)origin
}

if (maxNumOfExperiments <= experiments.count) {
ABTExperimentPayload_ExperimentOverflowPolicy overflowPolicy =
ABTExperimentPayloadExperimentOverflowPolicy overflowPolicy =
[self overflowPolicyWithPayload:payload originalPolicy:policy];
id experimentToClear = experiments.firstObject;
if (overflowPolicy == ABTExperimentPayload_ExperimentOverflowPolicy_DiscardOldest &&
if (overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest &&
experimentToClear) {
NSString *expID = [self experimentIDOfExperiment:experimentToClear];
NSString *varID = [self variantIDOfExperiment:experimentToClear];
Expand Down Expand Up @@ -265,17 +265,17 @@ - (BOOL)isExperiment:(id)experiment theSameAsPayload:(ABTExperimentPayload *)pay
[variantID isEqualToString:payload.variantId];
}

- (ABTExperimentPayload_ExperimentOverflowPolicy)
- (ABTExperimentPayloadExperimentOverflowPolicy)
overflowPolicyWithPayload:(ABTExperimentPayload *)payload
originalPolicy:(ABTExperimentPayload_ExperimentOverflowPolicy)originalPolicy {
if (payload.overflowPolicy != ABTExperimentPayload_ExperimentOverflowPolicy_PolicyUnspecified) {
originalPolicy:(ABTExperimentPayloadExperimentOverflowPolicy)originalPolicy {
if ([payload overflowPolicyIsValid]) {
return payload.overflowPolicy;
}
if (originalPolicy != ABTExperimentPayload_ExperimentOverflowPolicy_PolicyUnspecified &&
ABTExperimentPayload_ExperimentOverflowPolicy_IsValidValue(originalPolicy)) {
if (originalPolicy == ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest ||
originalPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest) {
return originalPolicy;
}
return ABTExperimentPayload_ExperimentOverflowPolicy_DiscardOldest;
return ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest;
}

@end
151 changes: 151 additions & 0 deletions FirebaseABTesting/Sources/ABTExperimentPayload.m
@@ -0,0 +1,151 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "ABTExperimentPayload.h"

static NSString *const kExperimentPayloadKeyExperimentID = @"experimentId";
static NSString *const kExperimentPayloadKeyVariantID = @"variantId";

// Start time can either be a date string or integer (milliseconds since 1970).
static NSString *const kExperimentPayloadKeyExperimentStartTime = @"experimentStartTime";
static NSString *const kExperimentPayloadKeyExperimentStartTimeMillis =
@"experimentStartTimeMillis";
static NSString *const kExperimentPayloadKeyTriggerEvent = @"triggerEvent";
static NSString *const kExperimentPayloadKeyTriggerTimeoutMillis = @"triggerTimeoutMillis";
static NSString *const kExperimentPayloadKeyTimeToLiveMillis = @"timeToLiveMillis";
static NSString *const kExperimentPayloadKeySetEventToLog = @"setEventToLog";
static NSString *const kExperimentPayloadKeyActivateEventToLog = @"activateEventToLog";
static NSString *const kExperimentPayloadKeyClearEventToLog = @"clearEventToLog";
static NSString *const kExperimentPayloadKeyTimeoutEventToLog = @"timeoutEventToLog";
static NSString *const kExperimentPayloadKeyTTLExpiryEventToLog = @"ttlExpiryEventToLog";

static NSString *const kExperimentPayloadKeyOverflowPolicy = @"overflowPolicy";
static NSString *const kExperimentPayloadValueDiscardOldestOverflowPolicy = @"DISCARD_OLDEST";
static NSString *const kExperimentPayloadValueIgnoreNewestOverflowPolicy = @"IGNORE_NEWEST";

static NSString *const kExperimentPayloadKeyOngoingExperiments = @"ongoingExperiments";

@implementation ABTExperimentLite

- (instancetype)initWithExperimentId:(NSString *)experimentId {
if (self = [super init]) {
_experimentId = experimentId;
}
return self;
}

@end

@implementation ABTExperimentPayload

+ (NSDateFormatter *)experimentStartTimeFormatter {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
// Locale needs to be hardcoded. See
// https://developer.apple.com/library/ios/#qa/qa1480/_index.html for more details.
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
return dateFormatter;
}

+ (instancetype)parseFromData:(NSData *)data {
NSError *error;
NSDictionary *experimentDictionary =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
if (error != nil) {
return nil;
} else {
return [[ABTExperimentPayload alloc] initWithDictionary:experimentDictionary];
}
}

- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionary {
if (self = [super init]) {
_experimentId = dictionary[kExperimentPayloadKeyExperimentID];
_variantId = dictionary[kExperimentPayloadKeyVariantID];
_triggerEvent = dictionary[kExperimentPayloadKeyTriggerEvent];
_setEventToLog = dictionary[kExperimentPayloadKeySetEventToLog];
_activateEventToLog = dictionary[kExperimentPayloadKeyActivateEventToLog];
_clearEventToLog = dictionary[kExperimentPayloadKeyClearEventToLog];
_timeoutEventToLog = dictionary[kExperimentPayloadKeyTimeoutEventToLog];
_ttlExpiryEventToLog = dictionary[kExperimentPayloadKeyTTLExpiryEventToLog];

// Experiment start time can either be in the form of a date string or milliseconds since 1970.
if (dictionary[kExperimentPayloadKeyExperimentStartTime]) {
// Convert from date string.
NSDate *experimentStartTime = [[[self class] experimentStartTimeFormatter]
dateFromString:dictionary[kExperimentPayloadKeyExperimentStartTime]];
_experimentStartTimeMillis =
[@([experimentStartTime timeIntervalSince1970] * 1000) longLongValue];
} else if (dictionary[kExperimentPayloadKeyExperimentStartTimeMillis]) {
// Simply store milliseconds.
_experimentStartTimeMillis =
[dictionary[kExperimentPayloadKeyExperimentStartTimeMillis] longLongValue];
;
}

_triggerTimeoutMillis = [dictionary[kExperimentPayloadKeyTriggerTimeoutMillis] longLongValue];
_timeToLiveMillis = [dictionary[kExperimentPayloadKeyTimeToLiveMillis] longLongValue];

// Overflow policy can be an integer, or string e.g. "DISCARD_OLDEST" or "IGNORE_NEWEST".
if ([dictionary[kExperimentPayloadKeyOverflowPolicy] isKindOfClass:[NSString class]]) {
// If it's a string, pick against the preset string values.
NSString *policy = dictionary[kExperimentPayloadKeyOverflowPolicy];
if ([policy isEqualToString:kExperimentPayloadValueDiscardOldestOverflowPolicy]) {
_overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest;
} else if ([policy isEqualToString:kExperimentPayloadValueIgnoreNewestOverflowPolicy]) {
_overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest;
} else {
_overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyUnrecognizedValue;
}
} else {
_overflowPolicy = [dictionary[kExperimentPayloadKeyOverflowPolicy] intValue];
}

NSMutableArray<ABTExperimentLite *> *ongoingExperiments = [[NSMutableArray alloc] init];

NSArray<NSDictionary<NSString *, NSString *> *> *ongoingExperimentsArray =
dictionary[kExperimentPayloadKeyOngoingExperiments];

for (NSDictionary<NSString *, NSString *> *experimentDictionary in ongoingExperimentsArray) {
NSString *experimentId = experimentDictionary[kExperimentPayloadKeyExperimentID];
if (experimentId) {
ABTExperimentLite *liteExperiment =
[[ABTExperimentLite alloc] initWithExperimentId:experimentId];
[ongoingExperiments addObject:liteExperiment];
}
}

_ongoingExperiments = [ongoingExperiments copy];
}
return self;
}

- (void)clearTriggerEvent {
_triggerEvent = nil;
}

- (BOOL)overflowPolicyIsValid {
return self.overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest ||
self.overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest;
}

- (void)setOverflowPolicy:(ABTExperimentPayloadExperimentOverflowPolicy)overflowPolicy {
_overflowPolicy = overflowPolicy;
}

@end
21 changes: 11 additions & 10 deletions FirebaseABTesting/Sources/FIRExperimentController.m
Expand Up @@ -14,6 +14,7 @@

#import <FirebaseABTesting/FIRExperimentController.h>

#import <FirebaseABTesting/ABTExperimentPayload.h>
#import <FirebaseABTesting/FIRLifecycleEvents.h>
#import "FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h"
#import "FirebaseABTesting/Sources/ABTConstants.h"
Expand All @@ -34,19 +35,19 @@
#define STR_EXPAND(x) #x

/// Default experiment overflow policy.
const ABTExperimentPayload_ExperimentOverflowPolicy FIRDefaultExperimentOverflowPolicy =
ABTExperimentPayload_ExperimentOverflowPolicy_DiscardOldest;
const ABTExperimentPayloadExperimentOverflowPolicy FIRDefaultExperimentOverflowPolicy =
ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest;

/// Deserialize the experiment payloads.
ABTExperimentPayload *ABTDeserializeExperimentPayload(NSData *payload) {
// Verify that we have a JSON object.
NSError *error;
ABTExperimentPayload *experimentPayload = [ABTExperimentPayload parseFromData:payload
error:&error];
if (error) {
id JSONObject = [NSJSONSerialization JSONObjectWithData:payload options:kNilOptions error:&error];
if (JSONObject == nil) {
christibbs marked this conversation as resolved.
Show resolved Hide resolved
FIRLogError(kFIRLoggerABTesting, @"I-ABT000001", @"Failed to parse experiment payload: %@",
error.debugDescription);
}
return experimentPayload;
return [ABTExperimentPayload parseFromData:payload];
}

/// Returns a list of experiments to be set given the payloads and current list of experiments from
Expand Down Expand Up @@ -173,7 +174,7 @@ + (FIRExperimentController *)sharedInstance {

- (void)updateExperimentsWithServiceOrigin:(NSString *)origin
events:(FIRLifecycleEvents *)events
policy:(ABTExperimentPayload_ExperimentOverflowPolicy)policy
policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy
lastStartTime:(NSTimeInterval)lastStartTime
payloads:(NSArray<NSData *> *)payloads
completionHandler:
Expand All @@ -192,7 +193,7 @@ - (void)updateExperimentsWithServiceOrigin:(NSString *)origin

- (void)updateExperimentsWithServiceOrigin:(NSString *)origin
events:(FIRLifecycleEvents *)events
policy:(ABTExperimentPayload_ExperimentOverflowPolicy)policy
policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy
lastStartTime:(NSTimeInterval)lastStartTime
payloads:(NSArray<NSData *> *)payloads {
[self updateExperimentsWithServiceOrigin:origin
Expand All @@ -207,7 +208,7 @@ - (void)updateExperimentsWithServiceOrigin:(NSString *)origin
updateExperimentConditionalUserPropertiesWithServiceOrigin:(NSString *)origin
events:(FIRLifecycleEvents *)events
policy:
(ABTExperimentPayload_ExperimentOverflowPolicy)
(ABTExperimentPayloadExperimentOverflowPolicy)
policy
lastStartTime:(NSTimeInterval)lastStartTime
payloads:(NSArray<NSData *> *)payloads
Expand Down Expand Up @@ -325,7 +326,7 @@ - (void)activateExperiment:(ABTExperimentPayload *)experimentPayload
FIRLifecycleEvents *lifecycleEvents = [[FIRLifecycleEvents alloc] init];

// Ensure that trigger event is nil, which will immediately set the experiment to active.
experimentPayload.triggerEvent = nil;
[experimentPayload clearTriggerEvent];

[controller setExperimentWithOrigin:origin
payload:experimentPayload
Expand Down