Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions FirebaseRemoteConfig/Sources/FIRRemoteConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
#import "FirebaseRemoteConfig/Sources/RCNConfigRealtime.h"
#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h"

#import "FirebaseRemoteConfig/FirebaseRemoteConfig-Swift.h"

Expand Down Expand Up @@ -180,9 +179,9 @@
if (analytics) {
_listeners = [[NSMutableArray alloc] init];
RCNPersonalization *personalization =
[[RCNPersonalization alloc] initWithAnalytics:analytics];

Check warning on line 182 in FirebaseRemoteConfig/Sources/FIRRemoteConfig.m

View workflow job for this annotation

GitHub Actions / remoteconfig (iOS)

sending 'id<FIRAnalyticsInterop> _Nullable __strong' to parameter of incompatible type 'id<AnalyticsInterop> _Nullable'

Check warning on line 182 in FirebaseRemoteConfig/Sources/FIRRemoteConfig.m

View workflow job for this annotation

GitHub Actions / sample-build-test

sending 'id<FIRAnalyticsInterop> _Nullable __strong' to parameter of incompatible type 'id<AnalyticsInterop> _Nullable'
[self addListener:^(NSString *key, NSDictionary *config) {
[personalization logArmActive:key config:config];
[personalization logArmActiveWithRcParameter:key config:config];
}];
}
}
Expand Down
56 changes: 0 additions & 56 deletions FirebaseRemoteConfig/Sources/RCNPersonalization.h

This file was deleted.

72 changes: 0 additions & 72 deletions FirebaseRemoteConfig/Sources/RCNPersonalization.m

This file was deleted.

88 changes: 88 additions & 0 deletions FirebaseRemoteConfig/SwiftNew/Personalization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2024 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 Foundation

// TODO: AnalyticInterop refactor
// import FirebaseAnalyticsInterop

private let kAnalyticsOriginPersonalization = "fp"
private let kExternalEvent = "personalization_assignment"
private let kExternalRcParameterParam = "arm_key"
private let kExternalArmValueParam = "arm_value"
private let kPersonalizationId = "personalizationId"
private let kExternalPersonalizationIdParam = "personalization_id"
private let kArmIndex = "armIndex"
private let kExternalArmIndexParam = "arm_index"
private let kGroup = "group"
private let kExternalGroupParam = "group"

private let kInternalEvent = "_fpc"
private let kChoiceId = "choiceId"
private let kInternalChoiceIdParam = "_fpid"

@objc(RCNPersonalization)
public class Personalization: NSObject {
/// Analytics connector.
weak var analytics: FIRAnalyticsInterop?

private var loggedChoiceIds = [String: String]()

/// Designated initializer.
@objc public init(analytics: FIRAnalyticsInterop?) {
self.analytics = analytics
super.init()
}

/// Called when an arm is pulled from Remote Config. If the arm is personalized, log information
/// to
/// Google Analytics in another thread.
@objc public func logArmActive(rcParameter: String, config: [String: Any]) {
guard let ids =
config[ConfigConstants.fetchResponseKeyPersonalizationMetadata] as? [String: Any],
let values = config[ConfigConstants.fetchResponseKeyEntries] as? [String: RemoteConfigValue],
let value = values[rcParameter] else {
return
}

guard let metadata = ids[rcParameter] as? [String: AnyHashable],
let choiceId = metadata[kChoiceId] as? String else {
return
}

// Listeners like logArmActive() are dispatched to a serial queue, so loggedChoiceIds should
// contain any previously logged RC parameter / choice ID pairs.
if loggedChoiceIds[rcParameter] == choiceId {
return
}
loggedChoiceIds[rcParameter] = choiceId

analytics?.logEvent(
withOrigin: kAnalyticsOriginPersonalization,
name: kExternalEvent,
parameters: [
kExternalRcParameterParam: rcParameter,
kExternalArmValueParam: value.stringValue,
kExternalPersonalizationIdParam: metadata[kPersonalizationId] ?? "",
// Provide default value if nil
kExternalArmIndexParam: metadata[kArmIndex] ?? "", // Provide default value if nil
kExternalGroupParam: metadata[kGroup] ?? "", // Provide default value if nil
]
)

analytics?.logEvent(withOrigin: kAnalyticsOriginPersonalization,
name: kInternalEvent,
parameters: [kInternalChoiceIdParam: choiceId])
}
}
3 changes: 3 additions & 0 deletions FirebaseRemoteConfig/SwiftNew/RemoteConfigComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import FirebaseRemoteConfigInterop
// TODO(ncooke3): Move to another pod.
@objc(AnalyticsInterop) public protocol FIRAnalyticsInterop {
func getUserProperties(callback: @escaping ([String: Any]) -> Void)
func logEvent(withOrigin origin: String,
name: String,
parameters: [String: Any])
}

/// Provides and creates instances of Remote Config based on the namespace provided. Used in the
Expand Down
30 changes: 22 additions & 8 deletions FirebaseRemoteConfig/Tests/Unit/RCNPersonalizationTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,26 @@
// #import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h"
#import "FirebaseRemoteConfig/Tests/Unit/RCNTestUtilities.h"
#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"

#import "FirebaseRemoteConfig/FirebaseRemoteConfig-Swift.h"
@import FirebaseRemoteConfig;

static NSString *const kAnalyticsOriginPersonalization = @"fp";

static NSString *const kExternalEvent = @"personalization_assignment";
static NSString *const kExternalRcParameterParam = @"arm_key";
static NSString *const kExternalArmValueParam = @"arm_value";
static NSString *const kPersonalizationId = @"personalizationId";
static NSString *const kExternalPersonalizationIdParam = @"personalization_id";
static NSString *const kArmIndex = @"armIndex";
static NSString *const kExternalArmIndexParam = @"arm_index";
static NSString *const kGroup = @"group";
static NSString *const kExternalGroupParam = @"group";

static NSString *const kInternalEvent = @"_fpc";
static NSString *const kChoiceId = @"choiceId";
static NSString *const kInternalChoiceIdParam = @"_fpid";

@interface RCNConfigFetch (ForTest)
- (NSURLSessionDataTask *)URLSessionDataTaskWithContent:(NSData *)content
Expand Down Expand Up @@ -118,8 +133,7 @@ - (void)tearDown {

- (void)testNonPersonalizationKey {
[_fakeLogs removeAllObjects];

[_personalization logArmActive:@"key3" config:_configContainer];
[_personalization logArmActiveWithRcParameter:@"key3" config:_configContainer];

OCMVerify(never(),
[_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
Expand All @@ -134,7 +148,7 @@ - (void)testNonPersonalizationKey {
- (void)testSinglePersonalizationKey {
[_fakeLogs removeAllObjects];

[_personalization logArmActive:@"key1" config:_configContainer];
[_personalization logArmActiveWithRcParameter:@"key1" config:_configContainer];

OCMVerify(times(2),
[_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
Expand All @@ -161,9 +175,9 @@ - (void)testSinglePersonalizationKey {
- (void)testMultiplePersonalizationKeys {
[_fakeLogs removeAllObjects];

[_personalization logArmActive:@"key1" config:_configContainer];
[_personalization logArmActive:@"key2" config:_configContainer];
[_personalization logArmActive:@"key1" config:_configContainer];
[_personalization logArmActiveWithRcParameter:@"key1" config:_configContainer];
[_personalization logArmActiveWithRcParameter:@"key2" config:_configContainer];
[_personalization logArmActiveWithRcParameter:@"key1" config:_configContainer];

OCMVerify(times(4),
[_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
Expand Down
Loading