Skip to content

Add support for on-device conversions using hashed email address and phone number. #1603

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

Merged
merged 12 commits into from
Jun 7, 2024
Merged
20 changes: 20 additions & 0 deletions analytics/integration_test/src/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,26 @@ TEST_F(FirebaseAnalyticsTest, TestSetProperties) {
"[email protected]");
firebase::analytics::InitiateOnDeviceConversionMeasurementWithPhoneNumber(
"+15551234567");

std::vector<unsigned char> hashed_email = {
// SHA256-encoded "[email protected]"
0x31, 0xc5, 0x54, 0x3c, 0x17, 0x34, 0xd2, 0x5c, 0x72, 0x06, 0xf5,
0xfd, 0x59, 0x15, 0x25, 0xd0, 0x29, 0x5b, 0xec, 0x6f, 0xe8, 0x4f,
0xf8, 0x2f, 0x94, 0x6a, 0x34, 0xfe, 0x97, 0x0a, 0x1e, 0x66,
};

firebase::analytics::
InitiateOnDeviceConversionMeasurementWithHashedEmailAddress(hashed_email);

std::vector<unsigned char> hashed_phone = {
// SHA256-encoded "+12345556789"
0x12, 0x8c, 0x64, 0xfe, 0x24, 0x0f, 0x08, 0x75, 0xf5, 0x98, 0xc3,
0x48, 0x0e, 0xb0, 0x38, 0xd2, 0xe6, 0xb0, 0x05, 0xd1, 0xa0, 0x57,
0xb6, 0x21, 0x4a, 0xc2, 0x09, 0xf6, 0xe5, 0xc0, 0x68, 0x41,
};

firebase::analytics::
InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber(hashed_phone);
}

TEST_F(FirebaseAnalyticsTest, TestLogEvents) {
Expand Down
20 changes: 20 additions & 0 deletions analytics/src/analytics_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,26 @@ void InitiateOnDeviceConversionMeasurementWithPhoneNumber(
// No-op on Android
}

/// Initiates on-device conversion measurement given a hashed user email address
/// on iOS (no-op on Android). On iOS, requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
/// no-op.
void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress(
std::vector<unsigned char> hashed_email) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
// No-op on Android
}

/// Initiates on-device conversion measurement given a hashed phone number on
/// iOS (no-op on Android). On iOS, requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
/// no-op.
void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
std::vector<unsigned char> hashed_phone) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
// No-op on Android
}

// Set a user property to the given value.
void SetUserProperty(const char* name, const char* value) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
Expand Down
24 changes: 24 additions & 0 deletions analytics/src/analytics_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,30 @@ void InitiateOnDeviceConversionMeasurementWithPhoneNumber(const char* phone_numb
[FIRAnalytics initiateOnDeviceConversionMeasurementWithPhoneNumber:@(phone_number)];
}

/// Initiates on-device conversion measurement given a hashed user email address
/// on iOS (no-op on Android). On iOS, requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
/// no-op.
void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress(
std::vector<unsigned char> hashed_email) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
NSData* hashed_email_data =
firebase::util::BytesToNSData(hashed_email.data(), hashed_email.size());
[FIRAnalytics initiateOnDeviceConversionMeasurementWithHashedEmailAddress:hashed_email_data];
}

/// Initiates on-device conversion measurement given a hashed phone number on
/// iOS (no-op on Android). On iOS, requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
/// no-op.
void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
std::vector<unsigned char> hashed_phone) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
NSData* hashed_phone_data =
firebase::util::BytesToNSData(hashed_phone.data(), hashed_phone.size());
[FIRAnalytics initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:hashed_phone_data];
}

// Set a user property to the given value.
void SetUserProperty(const char* name, const char* value) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
Expand Down
10 changes: 10 additions & 0 deletions analytics/src/analytics_stub.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ void InitiateOnDeviceConversionMeasurementWithEmailAddress(
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
}

void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress(
std::vector<unsigned char> email_address) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
}

/// Initiates on-device conversion measurement given a phone number on iOS
/// (no-op on Android). On iOS, requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
Expand All @@ -115,6 +120,11 @@ void InitiateOnDeviceConversionMeasurementWithPhoneNumber(
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
}

void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
std::vector<unsigned char> phone_number_hash) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
}

// Set a user property to the given value.
void SetUserProperty(const char* /*name*/, const char* /*value*/) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
Expand Down
20 changes: 20 additions & 0 deletions analytics/src/include/firebase/analytics.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <cstdint>
#include <map>
#include <string>
#include <vector>

#include "firebase/app.h"
#include "firebase/future.h"
Expand Down Expand Up @@ -503,6 +504,25 @@ void InitiateOnDeviceConversionMeasurementWithEmailAddress(
void InitiateOnDeviceConversionMeasurementWithPhoneNumber(
const char* phone_number);

/// Initiates on-device conversion measurement given a SHA256-hashed user email
/// address. Requires dependency GoogleAppMeasurementOnDeviceConversion to be
/// linked in, otherwise it is a no-op.
/// @param hashed_email_address User email address as a UTF8-encoded string
/// normalized and hashed according to the instructions at
/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3.
void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress(
std::vector<unsigned char> hashed_email_address);

/// Initiates on-device conversion measurement given a SHA256-hashed phone
/// number in E.164 format. Requires dependency
/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a
/// no-op.
/// @param hashed_phone_number UTF8-encoded user phone number in E.164 format
/// and then hashed according to the instructions at
/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3.
void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber(
std::vector<unsigned char> hashed_phone_number);

/// @brief Set a user property to the given value.
///
/// Properties associated with a user allow a developer to segment users
Expand Down
3 changes: 3 additions & 0 deletions app/src/util_ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ NSData *StringToNSData(const std::string &str);
// Convert bytes to NSData.
NSData *BytesToNSData(const char *bytes, const int len);

// Convert bytes to NSData.
NSData *BytesToNSData(const unsigned char *bytes, const int len);

// Convert an NSData to std::string.
std::string NSDataToString(NSData *data);

Expand Down
4 changes: 4 additions & 0 deletions app/src/util_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ void ForEachAppDelegateClass(void (^block)(Class)) {
return [NSData dataWithBytes:bytes length:len];
}

NSData *BytesToNSData(const unsigned char *bytes, const int len) {
return [NSData dataWithBytes:bytes length:len];
}

std::string NSDataToString(NSData *data) {
return std::string(static_cast<const char *>(data.bytes), data.length);
}
Expand Down
6 changes: 6 additions & 0 deletions release_build_files/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,12 @@ workflow use only during the development of your app, not for publicly shipping
code.

## Release Notes
### Upcoming Release
- Changes
- Analytics (iOS): Add support for
`InitiateOnDeviceConversionMeasurementWithHashedEmailAddress` and
`InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber`.

### 12.0.0
- Changes
- General (Android): Update to Firebase Android BoM version 33.0.0.
Expand Down
Loading