From f8a08e5292b6bc663a604a678e4a27626bc061f2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:57:22 +0000 Subject: [PATCH 1/8] Implement setDefaultEventParameters method in C++ Analytics API This commit adds the method to the C++ Analytics API. This method allows setting default event parameters, mirroring functionality in the iOS and Android SDKs. The implementation covers: - iOS: Using Objective-C++ to call the - Android: Using JNI to call the - Desktop: A stub implementation for other platforms. Unit tests and integration tests were added to ensure the change works as intended. A release note was added for the next release (v12.7.0) in - Analytics: Added support for default parameters to be sent with each event. This change lets you use to set default parameters to be sent with each event. - General (iOS): Update to Firebase Cocoapods version 11.9.0. - General (Android): Update to Firebase Android BoM version 33.10.0. All the references to in the test files were corrected to have the namespace added. --- .../integration_test/src/integration_test.cc | 93 +++++++++++-------- analytics/src/analytics_android.cc | 60 ++++++++++++ analytics/src/analytics_ios.mm | 17 ++++ analytics/src/analytics_stub.cc | 5 + analytics/src/include/firebase/analytics.h | 5 + analytics/tests/analytics_test.cc | 18 ++++ release_build_files/readme.md | 8 ++ 7 files changed, 165 insertions(+), 41 deletions(-) diff --git a/analytics/integration_test/src/integration_test.cc b/analytics/integration_test/src/integration_test.cc index bedccee516..330115d522 100644 --- a/analytics/integration_test/src/integration_test.cc +++ b/analytics/integration_test/src/integration_test.cc @@ -298,47 +298,58 @@ TEST_F(FirebaseAnalyticsTest, TestLogEventWithComplexParameters) { } TEST_F(FirebaseAnalyticsTest, TestSetConsent) { - // On Android, this test must be performed at the end, after all the tests for - // session ID and instance ID. This is because once you call SetConsent to - // deny consent on Android, calling it again to grant consent may not take - // effect until the app restarts, thus breaking any of those tests that are - // run after this one. - // - // If this test does happen to run earlier (due to randomizing test order, for - // example), the tests that could fail will be skipped (on Android). - - // Can't confirm that these do anything but just run them all to ensure the - // app doesn't crash. - std::map - consent_settings_allow = { - {firebase::analytics::kConsentTypeAnalyticsStorage, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdStorage, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdUserData, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdPersonalization, - firebase::analytics::kConsentStatusGranted}}; - std::map - consent_settings_deny = { - {firebase::analytics::kConsentTypeAnalyticsStorage, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdStorage, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdUserData, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdPersonalization, - firebase::analytics::kConsentStatusDenied}}; - std::map - consent_settings_empty; - firebase::analytics::SetConsent(consent_settings_empty); - ProcessEvents(1000); - firebase::analytics::SetConsent(consent_settings_deny); - ProcessEvents(1000); - firebase::analytics::SetConsent(consent_settings_allow); - ProcessEvents(1000); - - did_test_setconsent_ = true; + // On Android, this test must be performed at the end, after all the tests for + // session ID and instance ID. This is because once you call SetConsent to + // deny consent on Android, calling it again to grant consent may not take + // effect until the app restarts, thus breaking any of those tests that are + // run after this one. + // + // If this test does happen to run earlier (due to randomizing test order, for + // example), the tests that could fail will be skipped (on Android). + + // Can't confirm that these do anything but just run them all to ensure the + // app doesn't crash. + std::map + consent_settings_allow = { + {firebase::analytics::kConsentTypeAnalyticsStorage, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdStorage, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdUserData, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdPersonalization, + firebase::analytics::kConsentStatusGranted}}; + std::map + consent_settings_deny = { + {firebase::analytics::kConsentTypeAnalyticsStorage, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdStorage, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdUserData, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdPersonalization, + firebase::analytics::kConsentStatusDenied}}; + std::map + consent_settings_empty; + firebase::analytics::SetConsent(consent_settings_empty); + ProcessEvents(1000); + firebase::analytics::SetConsent(consent_settings_deny); + ProcessEvents(1000); + firebase::analytics::SetConsent(consent_settings_allow); + ProcessEvents(1000); + + did_test_setconsent_ = true; } +TEST_F(FirebaseAnalyticsTest, TestSetDefaultEventParameters) { + std::map default_params = { + {"key1", firebase::Variant("value1")}, + {"key2", firebase::Variant(12345)}, + {"key3", firebase::Variant(1.01)}, + {"key4", firebase::Variant("my_value")}, + {"key5", firebase::Variant(true)}, + {"key6", firebase::Variant::EmptyMap()}, + }; + firebase::analytics::SetDefaultEventParameters(default_params); +} } // namespace firebase_testapp_automated diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index d1279c6ba7..62ba39e029 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -736,5 +736,65 @@ Future GetSessionIdLastResult() { internal::kAnalyticsFnGetSessionId)); } +// Sets the default parameters to be sent with each event. +void SetDefaultEventParameters(const std::map& parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + JNIEnv* env = g_app->GetJNIEnv(); + + jobject map = + env->NewObject(util::hash_map::GetClass(), + util::hash_map::GetMethodId(util::hash_map::kConstructor)); + util::CheckAndClearJniExceptions(env); + + jmethodID put_method_id = util::map::GetMethodId(util::map::kPut); + + for (const auto& pair : parameters) { + jstring key_string = env->NewStringUTF(pair.first.c_str()); + jobject jni_value; + if (pair.second.is_int64()) { + jni_value = env->NewObject(util::integer_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + } + else if (pair.second.is_double()){ + jni_value = env->NewObject(util::double_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + }else if (pair.second.is_string()) { + jni_value = env->NewObject(util::string_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + } + else if(pair.second.is_map()){ + jobject jni_bundle = MapToBundle(env,pair.second.map()); + jobject previous_value = env->CallObjectMethod( + bundle, put_method_id, env->NewStringUTF(key_string.c_str()), jni_bundle); + util::CheckAndClearJniExceptions(env); + if (previous_value) { + env->DeleteLocalRef(previous_value); + } + + }else { + // A Variant type that couldn't be handled was passed in. + LogError( + "LogEvent(%s): %s is not a valid parameter value type. " + "No event was logged.", + pair.first.c_str(), Variant::TypeName(pair.second.type())); + continue; + } + jobject previous_value = env->CallObjectMethod( + map, put_method_id, key_string, jni_value); + util::CheckAndClearJniExceptions(env); + env->DeleteLocalRef(jni_value); + env->DeleteLocalRef(key_string); + + } + + env->CallVoidMethod(g_analytics_class_instance, + analytics::GetMethodId(analytics::kSetDefaultEventParameters), + map); + + util::CheckAndClearJniExceptions(env); + env->DeleteLocalRef(map); + +} + } // namespace analytics } // namespace firebase diff --git a/analytics/src/analytics_ios.mm b/analytics/src/analytics_ios.mm index d56fd61356..a66764223b 100644 --- a/analytics/src/analytics_ios.mm +++ b/analytics/src/analytics_ios.mm @@ -438,5 +438,22 @@ Thread get_id_thread( internal::FutureData::Get()->api()->LastResult(internal::kAnalyticsFnGetSessionId)); } +/// @brief Sets the default parameters to be sent with each event. +/// +/// @param[in] parameters The parameters to send with each event. +void SetDefaultEventParameters(const std::map& parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + NSMutableDictionary* parameters_dict = + [[NSMutableDictionary alloc] initWithCapacity:parameters.size()]; + for (const auto& pair : parameters) { + NSString* key = SafeString(pair.first.c_str()); + if (!AddVariantToDictionary(parameters_dict, key, pair.second)) { + LogError("SetDefaultEventParameters: Unsupported type (%s) within map with key %s.", + Variant::TypeName(pair.second.type()), key); + } + } + [FIRAnalytics setDefaultEventParameters:parameters_dict]; +} + } // namespace analytics } // namespace firebase diff --git a/analytics/src/analytics_stub.cc b/analytics/src/analytics_stub.cc index 37c4b3520b..cbb670b4f9 100644 --- a/analytics/src/analytics_stub.cc +++ b/analytics/src/analytics_stub.cc @@ -186,5 +186,10 @@ Future GetSessionIdLastResult() { internal::kAnalyticsFnGetSessionId)); } +// Sets the default parameters to be sent with each event. +void SetDefaultEventParameters(const std::map& parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); +} + } // namespace analytics } // namespace firebase diff --git a/analytics/src/include/firebase/analytics.h b/analytics/src/include/firebase/analytics.h index 746df99894..dd1da71919 100644 --- a/analytics/src/include/firebase/analytics.h +++ b/analytics/src/include/firebase/analytics.h @@ -591,6 +591,11 @@ Future GetSessionId(); /// app session. Future GetSessionIdLastResult(); +/// @brief Sets the default parameters to be sent with each event. +/// +/// @param[in] parameters The parameters to send with each event. +void SetDefaultEventParameters(const std::map& parameters); + } // namespace analytics } // namespace firebase diff --git a/analytics/tests/analytics_test.cc b/analytics/tests/analytics_test.cc index 8235c69e25..db658aa30a 100644 --- a/analytics/tests/analytics_test.cc +++ b/analytics/tests/analytics_test.cc @@ -296,5 +296,23 @@ TEST_F(AnalyticsTest, TestGetAnalyticsInstanceId) { EXPECT_EQ(std::string("FakeAnalyticsInstanceId0"), *result.result()); } +TEST_F(AnalyticsTest, TestSetDefaultEventParameters) { + std::map parameters = { + {"key1", firebase::Variant("value1")}, + {"key2", firebase::Variant(12345)}, + {"key3", firebase::Variant(1.01)}, + {"key4", firebase::Variant("my_value")}, + {"key5", firebase::Variant(true)}, + {"key6", firebase::Variant::EmptyMap()}, + }; + + AddExpectationAndroid("FirebaseAnalytics.setDefaultEventParameters", + {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); + AddExpectationApple("+[FIRAnalytics setDefaultEventParameters:]", + {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); + + SetDefaultEventParameters(parameters); +} + } // namespace analytics } // namespace firebase diff --git a/release_build_files/readme.md b/release_build_files/readme.md index c659c7f452..d69bd71959 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -631,6 +631,14 @@ workflow use only during the development of your app, not for publicly shipping code. ## Release Notes +### Next Release (12.7.0) +- Changes + - Analytics: Added support for default parameters to be sent with each event. + This change lets you use `SetDefaultEventParameters` to set default + parameters to be sent with each event. + - General (iOS): Update to Firebase Cocoapods version 11.9.0. + - General (Android): Update to Firebase Android BoM version 33.10.0. + ### 12.6.0 - Changes - General (iOS): Update to Firebase Cocoapods version 11.8.1. From 5dbbfda62d5bb7e5c268639b15d8238cb53a09f8 Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 14:06:48 -0800 Subject: [PATCH 2/8] Format code and update readme. --- .../integration_test/src/integration_test.cc | 86 +++++++-------- analytics/src/analytics_android.cc | 103 +++++++++--------- analytics/src/analytics_ios.mm | 14 +-- analytics/src/analytics_stub.cc | 3 +- analytics/src/include/firebase/analytics.h | 3 +- analytics/tests/analytics_test.cc | 10 +- release_build_files/readme.md | 7 +- 7 files changed, 115 insertions(+), 111 deletions(-) diff --git a/analytics/integration_test/src/integration_test.cc b/analytics/integration_test/src/integration_test.cc index 330115d522..7b398cf43e 100644 --- a/analytics/integration_test/src/integration_test.cc +++ b/analytics/integration_test/src/integration_test.cc @@ -298,51 +298,51 @@ TEST_F(FirebaseAnalyticsTest, TestLogEventWithComplexParameters) { } TEST_F(FirebaseAnalyticsTest, TestSetConsent) { - // On Android, this test must be performed at the end, after all the tests for - // session ID and instance ID. This is because once you call SetConsent to - // deny consent on Android, calling it again to grant consent may not take - // effect until the app restarts, thus breaking any of those tests that are - // run after this one. - // - // If this test does happen to run earlier (due to randomizing test order, for - // example), the tests that could fail will be skipped (on Android). - - // Can't confirm that these do anything but just run them all to ensure the - // app doesn't crash. - std::map - consent_settings_allow = { - {firebase::analytics::kConsentTypeAnalyticsStorage, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdStorage, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdUserData, - firebase::analytics::kConsentStatusGranted}, - {firebase::analytics::kConsentTypeAdPersonalization, - firebase::analytics::kConsentStatusGranted}}; - std::map - consent_settings_deny = { - {firebase::analytics::kConsentTypeAnalyticsStorage, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdStorage, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdUserData, - firebase::analytics::kConsentStatusDenied}, - {firebase::analytics::kConsentTypeAdPersonalization, - firebase::analytics::kConsentStatusDenied}}; - std::map - consent_settings_empty; - firebase::analytics::SetConsent(consent_settings_empty); - ProcessEvents(1000); - firebase::analytics::SetConsent(consent_settings_deny); - ProcessEvents(1000); - firebase::analytics::SetConsent(consent_settings_allow); - ProcessEvents(1000); - - did_test_setconsent_ = true; + // On Android, this test must be performed at the end, after all the tests for + // session ID and instance ID. This is because once you call SetConsent to + // deny consent on Android, calling it again to grant consent may not take + // effect until the app restarts, thus breaking any of those tests that are + // run after this one. + // + // If this test does happen to run earlier (due to randomizing test order, for + // example), the tests that could fail will be skipped (on Android). + + // Can't confirm that these do anything but just run them all to ensure the + // app doesn't crash. + std::map + consent_settings_allow = { + {firebase::analytics::kConsentTypeAnalyticsStorage, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdStorage, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdUserData, + firebase::analytics::kConsentStatusGranted}, + {firebase::analytics::kConsentTypeAdPersonalization, + firebase::analytics::kConsentStatusGranted}}; + std::map + consent_settings_deny = { + {firebase::analytics::kConsentTypeAnalyticsStorage, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdStorage, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdUserData, + firebase::analytics::kConsentStatusDenied}, + {firebase::analytics::kConsentTypeAdPersonalization, + firebase::analytics::kConsentStatusDenied}}; + std::map + consent_settings_empty; + firebase::analytics::SetConsent(consent_settings_empty); + ProcessEvents(1000); + firebase::analytics::SetConsent(consent_settings_deny); + ProcessEvents(1000); + firebase::analytics::SetConsent(consent_settings_allow); + ProcessEvents(1000); + + did_test_setconsent_ = true; } TEST_F(FirebaseAnalyticsTest, TestSetDefaultEventParameters) { - std::map default_params = { + std::map default_params = { {"key1", firebase::Variant("value1")}, {"key2", firebase::Variant(12345)}, {"key3", firebase::Variant(1.01)}, @@ -350,6 +350,6 @@ TEST_F(FirebaseAnalyticsTest, TestSetDefaultEventParameters) { {"key5", firebase::Variant(true)}, {"key6", firebase::Variant::EmptyMap()}, }; - firebase::analytics::SetDefaultEventParameters(default_params); + firebase::analytics::SetDefaultEventParameters(default_params); } } // namespace firebase_testapp_automated diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index 62ba39e029..b379ae9761 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -737,63 +737,64 @@ Future GetSessionIdLastResult() { } // Sets the default parameters to be sent with each event. -void SetDefaultEventParameters(const std::map& parameters) { - FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); - JNIEnv* env = g_app->GetJNIEnv(); - - jobject map = - env->NewObject(util::hash_map::GetClass(), - util::hash_map::GetMethodId(util::hash_map::kConstructor)); - util::CheckAndClearJniExceptions(env); - - jmethodID put_method_id = util::map::GetMethodId(util::map::kPut); +void SetDefaultEventParameters( + const std::map& parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + JNIEnv* env = g_app->GetJNIEnv(); - for (const auto& pair : parameters) { - jstring key_string = env->NewStringUTF(pair.first.c_str()); - jobject jni_value; - if (pair.second.is_int64()) { - jni_value = env->NewObject(util::integer_java_class_type::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); - } - else if (pair.second.is_double()){ - jni_value = env->NewObject(util::double_java_class_type::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); - }else if (pair.second.is_string()) { - jni_value = env->NewObject(util::string_java_class_type::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); - } - else if(pair.second.is_map()){ - jobject jni_bundle = MapToBundle(env,pair.second.map()); - jobject previous_value = env->CallObjectMethod( - bundle, put_method_id, env->NewStringUTF(key_string.c_str()), jni_bundle); - util::CheckAndClearJniExceptions(env); - if (previous_value) { - env->DeleteLocalRef(previous_value); - } + jobject map = + env->NewObject(util::hash_map::GetClass(), + util::hash_map::GetMethodId(util::hash_map::kConstructor)); + util::CheckAndClearJniExceptions(env); - }else { - // A Variant type that couldn't be handled was passed in. - LogError( - "LogEvent(%s): %s is not a valid parameter value type. " - "No event was logged.", - pair.first.c_str(), Variant::TypeName(pair.second.type())); - continue; - } - jobject previous_value = env->CallObjectMethod( - map, put_method_id, key_string, jni_value); - util::CheckAndClearJniExceptions(env); - env->DeleteLocalRef(jni_value); - env->DeleteLocalRef(key_string); + jmethodID put_method_id = util::map::GetMethodId(util::map::kPut); + + for (const auto& pair : parameters) { + jstring key_string = env->NewStringUTF(pair.first.c_str()); + jobject jni_value; + if (pair.second.is_int64()) { + jni_value = + env->NewObject(util::integer_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + } else if (pair.second.is_double()) { + jni_value = + env->NewObject(util::double_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + } else if (pair.second.is_string()) { + jni_value = + env->NewObject(util::string_java_class_type::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + } else if (pair.second.is_map()) { + jobject jni_bundle = MapToBundle(env, pair.second.map()); + jobject previous_value = env->CallObjectMethod( + bundle, put_method_id, env->NewStringUTF(key_string.c_str()), + jni_bundle); + util::CheckAndClearJniExceptions(env); + if (previous_value) { + env->DeleteLocalRef(previous_value); + } + } else { + // A Variant type that couldn't be handled was passed in. + LogError( + "LogEvent(%s): %s is not a valid parameter value type. " + "No event was logged.", + pair.first.c_str(), Variant::TypeName(pair.second.type())); + continue; } - - env->CallVoidMethod(g_analytics_class_instance, - analytics::GetMethodId(analytics::kSetDefaultEventParameters), - map); - + jobject previous_value = + env->CallObjectMethod(map, put_method_id, key_string, jni_value); util::CheckAndClearJniExceptions(env); - env->DeleteLocalRef(map); + env->DeleteLocalRef(jni_value); + env->DeleteLocalRef(key_string); + } + env->CallVoidMethod( + g_analytics_class_instance, + analytics::GetMethodId(analytics::kSetDefaultEventParameters), map); + + util::CheckAndClearJniExceptions(env); + env->DeleteLocalRef(map); } } // namespace analytics diff --git a/analytics/src/analytics_ios.mm b/analytics/src/analytics_ios.mm index a66764223b..922ebbaa15 100644 --- a/analytics/src/analytics_ios.mm +++ b/analytics/src/analytics_ios.mm @@ -445,14 +445,14 @@ void SetDefaultEventParameters(const std::map& parameters) FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); NSMutableDictionary* parameters_dict = [[NSMutableDictionary alloc] initWithCapacity:parameters.size()]; - for (const auto& pair : parameters) { - NSString* key = SafeString(pair.first.c_str()); - if (!AddVariantToDictionary(parameters_dict, key, pair.second)) { - LogError("SetDefaultEventParameters: Unsupported type (%s) within map with key %s.", - Variant::TypeName(pair.second.type()), key); - } + for (const auto& pair : parameters) { + NSString* key = SafeString(pair.first.c_str()); + if (!AddVariantToDictionary(parameters_dict, key, pair.second)) { + LogError("SetDefaultEventParameters: Unsupported type (%s) within map with key %s.", + Variant::TypeName(pair.second.type()), key); } - [FIRAnalytics setDefaultEventParameters:parameters_dict]; + } + [FIRAnalytics setDefaultEventParameters:parameters_dict]; } } // namespace analytics diff --git a/analytics/src/analytics_stub.cc b/analytics/src/analytics_stub.cc index cbb670b4f9..3f51ffbdab 100644 --- a/analytics/src/analytics_stub.cc +++ b/analytics/src/analytics_stub.cc @@ -187,7 +187,8 @@ Future GetSessionIdLastResult() { } // Sets the default parameters to be sent with each event. -void SetDefaultEventParameters(const std::map& parameters) { +void SetDefaultEventParameters( + const std::map& parameters) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); } diff --git a/analytics/src/include/firebase/analytics.h b/analytics/src/include/firebase/analytics.h index dd1da71919..6efc60048c 100644 --- a/analytics/src/include/firebase/analytics.h +++ b/analytics/src/include/firebase/analytics.h @@ -594,7 +594,8 @@ Future GetSessionIdLastResult(); /// @brief Sets the default parameters to be sent with each event. /// /// @param[in] parameters The parameters to send with each event. -void SetDefaultEventParameters(const std::map& parameters); +void SetDefaultEventParameters( + const std::map& parameters); } // namespace analytics } // namespace firebase diff --git a/analytics/tests/analytics_test.cc b/analytics/tests/analytics_test.cc index db658aa30a..2d80b4c8f6 100644 --- a/analytics/tests/analytics_test.cc +++ b/analytics/tests/analytics_test.cc @@ -306,10 +306,12 @@ TEST_F(AnalyticsTest, TestSetDefaultEventParameters) { {"key6", firebase::Variant::EmptyMap()}, }; - AddExpectationAndroid("FirebaseAnalytics.setDefaultEventParameters", - {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); - AddExpectationApple("+[FIRAnalytics setDefaultEventParameters:]", - {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); + AddExpectationAndroid( + "FirebaseAnalytics.setDefaultEventParameters", + {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); + AddExpectationApple( + "+[FIRAnalytics setDefaultEventParameters:]", + {"key1=value1,key2=12345,key3=1.01,key4=my_value,key5=1"}); SetDefaultEventParameters(parameters); } diff --git a/release_build_files/readme.md b/release_build_files/readme.md index d69bd71959..6f026792af 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -631,13 +631,12 @@ workflow use only during the development of your app, not for publicly shipping code. ## Release Notes -### Next Release (12.7.0) +### 12.7.0 - Changes - - Analytics: Added support for default parameters to be sent with each event. - This change lets you use `SetDefaultEventParameters` to set default - parameters to be sent with each event. - General (iOS): Update to Firebase Cocoapods version 11.9.0. - General (Android): Update to Firebase Android BoM version 33.10.0. + - Analytics: Added support for setting default parameters to be sent + with each event, using `SetDefaultEventParameters`. ### 12.6.0 - Changes From fff19cac6f1894a63e4c7b820ce77db4de3a7b9f Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 15:04:33 -0800 Subject: [PATCH 3/8] Update Android implementation. --- analytics/src/analytics_android.cc | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index b379ae9761..b00518a281 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -750,30 +750,23 @@ void SetDefaultEventParameters( jmethodID put_method_id = util::map::GetMethodId(util::map::kPut); for (const auto& pair : parameters) { - jstring key_string = env->NewStringUTF(pair.first.c_str()); jobject jni_value; if (pair.second.is_int64()) { jni_value = - env->NewObject(util::integer_java_class_type::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); + env->NewObject(util::integer_class::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor), + pair.second.int64_value()); } else if (pair.second.is_double()) { jni_value = - env->NewObject(util::double_java_class_type::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); + env->NewObject(util::double_class::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor), + pair.second.double_value()); } else if (pair.second.is_string()) { jni_value = - env->NewObject(util::string_java_class_type::GetClass(), + env->NewObject(util::string::GetClass(), util::bundle::GetMethodId(util::bundle::kConstructor)); } else if (pair.second.is_map()) { - jobject jni_bundle = MapToBundle(env, pair.second.map()); - jobject previous_value = env->CallObjectMethod( - bundle, put_method_id, env->NewStringUTF(key_string.c_str()), - jni_bundle); - util::CheckAndClearJniExceptions(env); - if (previous_value) { - env->DeleteLocalRef(previous_value); - } - + jni_value = env->NewStringUTF(pair.second.c_str()); } else { // A Variant type that couldn't be handled was passed in. LogError( @@ -782,11 +775,13 @@ void SetDefaultEventParameters( pair.first.c_str(), Variant::TypeName(pair.second.type())); continue; } + jstring key_string = env->NewStringUTF(pair.first.c_str()); jobject previous_value = env->CallObjectMethod(map, put_method_id, key_string, jni_value); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(jni_value); env->DeleteLocalRef(key_string); + env->DeleteLocalRef(previous_value); } env->CallVoidMethod( From 8d6d7d63e7924990180b60d462c701c843328931 Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 15:23:17 -0800 Subject: [PATCH 4/8] Update JNI usage and add method definition. --- analytics/src/analytics_android.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index b00518a281..b91218e914 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -58,6 +58,8 @@ static const ::firebase::App* g_app = nullptr; "()Lcom/google/android/gms/tasks/Task;"), \ X(GetSessionId, "getSessionId", \ "()Lcom/google/android/gms/tasks/Task;"), \ + X(SetDefaultEventParameters, "setDefaultEventParameters", \ + "(Landroid/os/Bundle;)V"), \ X(GetInstance, "getInstance", "(Landroid/content/Context;)" \ "Lcom/google/firebase/analytics/FirebaseAnalytics;", \ firebase::util::kMethodTypeStatic) @@ -755,27 +757,27 @@ void SetDefaultEventParameters( jni_value = env->NewObject(util::integer_class::GetClass(), util::bundle::GetMethodId(util::bundle::kConstructor), - pair.second.int64_value()); + pair.second.int64_value()); } else if (pair.second.is_double()) { jni_value = env->NewObject(util::double_class::GetClass(), util::bundle::GetMethodId(util::bundle::kConstructor), - pair.second.double_value()); + pair.second.double_value()); } else if (pair.second.is_string()) { jni_value = env->NewObject(util::string::GetClass(), util::bundle::GetMethodId(util::bundle::kConstructor)); } else if (pair.second.is_map()) { - jni_value = env->NewStringUTF(pair.second.c_str()); + jni_value = env->NewStringUTF(pair.second.string_value()); } else { // A Variant type that couldn't be handled was passed in. LogError( "LogEvent(%s): %s is not a valid parameter value type. " "No event was logged.", - pair.first.c_str(), Variant::TypeName(pair.second.type())); + pair.first.string_value(), Variant::TypeName(pair.second.type())); continue; } - jstring key_string = env->NewStringUTF(pair.first.c_str()); + jstring key_string = env->NewStringUTF(pair.first.string_value()); jobject previous_value = env->CallObjectMethod(map, put_method_id, key_string, jni_value); util::CheckAndClearJniExceptions(env); From d6ca0478cb12b49bff2090a8f37e3f66984781b5 Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 15:31:07 -0800 Subject: [PATCH 5/8] Fix map access to use strings. --- analytics/src/analytics_android.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index b91218e914..68800e249d 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -774,10 +774,10 @@ void SetDefaultEventParameters( LogError( "LogEvent(%s): %s is not a valid parameter value type. " "No event was logged.", - pair.first.string_value(), Variant::TypeName(pair.second.type())); + pair.first.c_str(), Variant::TypeName(pair.second.type())); continue; } - jstring key_string = env->NewStringUTF(pair.first.string_value()); + jstring key_string = env->NewStringUTF(pair.first.c_str()); jobject previous_value = env->CallObjectMethod(map, put_method_id, key_string, jni_value); util::CheckAndClearJniExceptions(env); From 3cc444719b75d9aadb06e82c1e6622204462adef Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 15:40:04 -0800 Subject: [PATCH 6/8] Add write permission for integration test, so it can do labeling. --- .github/workflows/integration_tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 634a93f6df..bbb5b5d309 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -42,6 +42,8 @@ on: firestore_dep_source: description: 'Optional: Where to get firestore iOS SDK from: "RELEASED", "TIP" or " from firestore-ios-sdk"' +permissions: write-all + env: triggerLabelPrefix: "tests-requested: " triggerLabelFull: "tests-requested: full" From 908f624a3f4d698c0ffcb5988e7bf213a326f75e Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 15:57:54 -0800 Subject: [PATCH 7/8] Fix usage of MapToBundle. --- analytics/src/analytics_android.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index 68800e249d..082b902aba 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -756,19 +756,17 @@ void SetDefaultEventParameters( if (pair.second.is_int64()) { jni_value = env->NewObject(util::integer_class::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor), + util::integer_class::GetMethodId(util::integer_class::kConstructor), pair.second.int64_value()); } else if (pair.second.is_double()) { jni_value = env->NewObject(util::double_class::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor), + util::double_class::GetMethodId(util::double_class::kConstructor), pair.second.double_value()); } else if (pair.second.is_string()) { - jni_value = - env->NewObject(util::string::GetClass(), - util::bundle::GetMethodId(util::bundle::kConstructor)); - } else if (pair.second.is_map()) { jni_value = env->NewStringUTF(pair.second.string_value()); + } else if (pair.second.is_map()) { + jni_value = MapToBundle(env, pair.second.map()); } else { // A Variant type that couldn't be handled was passed in. LogError( From 5b5571162d6f5884327e3cb31ae3521ee26130b3 Mon Sep 17 00:00:00 2001 From: Jon Simantov Date: Wed, 5 Mar 2025 16:06:24 -0800 Subject: [PATCH 8/8] Format code. --- analytics/src/analytics_android.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index 082b902aba..af4610dd77 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -754,15 +754,15 @@ void SetDefaultEventParameters( for (const auto& pair : parameters) { jobject jni_value; if (pair.second.is_int64()) { - jni_value = - env->NewObject(util::integer_class::GetClass(), - util::integer_class::GetMethodId(util::integer_class::kConstructor), - pair.second.int64_value()); + jni_value = env->NewObject( + util::integer_class::GetClass(), + util::integer_class::GetMethodId(util::integer_class::kConstructor), + pair.second.int64_value()); } else if (pair.second.is_double()) { - jni_value = - env->NewObject(util::double_class::GetClass(), - util::double_class::GetMethodId(util::double_class::kConstructor), - pair.second.double_value()); + jni_value = env->NewObject( + util::double_class::GetClass(), + util::double_class::GetMethodId(util::double_class::kConstructor), + pair.second.double_value()); } else if (pair.second.is_string()) { jni_value = env->NewStringUTF(pair.second.string_value()); } else if (pair.second.is_map()) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy