diff --git a/analytics/integration_test/src/integration_test.cc b/analytics/integration_test/src/integration_test.cc index bedccee516..81ad49466b 100644 --- a/analytics/integration_test/src/integration_test.cc +++ b/analytics/integration_test/src/integration_test.cc @@ -297,6 +297,18 @@ TEST_F(FirebaseAnalyticsTest, TestLogEventWithComplexParameters) { sizeof(kViewCartParameters) / sizeof(kViewCartParameters[0])); } +TEST_F(FirebaseAnalyticsTest, TestSetDefaultEventParameters) { + const std::vector kDefaultParameters = { + firebase::analytics::Parameter("default_parameter_double", 123.456), + firebase::analytics::Parameter("default_parameter_int", 4), + firebase::analytics::Parameter("default_parameter_str", "Hello World"), + }; + + firebase::analytics::SetDefaultEventParameters(kDefaultParameters); + firebase::analytics::LogEvent("default_parameter_event"); + firebase::analytics::SetDefaultEventParameters(nullptr, 0); +} + 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 diff --git a/analytics/src/analytics_android.cc b/analytics/src/analytics_android.cc index d1279c6ba7..e170f91beb 100644 --- a/analytics/src/analytics_android.cc +++ b/analytics/src/analytics_android.cc @@ -19,6 +19,7 @@ #include #include +#include #include "analytics/src/analytics_common.h" #include "analytics/src/include/firebase/analytics.h" @@ -60,7 +61,9 @@ static const ::firebase::App* g_app = nullptr; "()Lcom/google/android/gms/tasks/Task;"), \ X(GetInstance, "getInstance", "(Landroid/content/Context;)" \ "Lcom/google/firebase/analytics/FirebaseAnalytics;", \ - firebase::util::kMethodTypeStatic) + firebase::util::kMethodTypeStatic), \ + X(SetDefaultEventParameters, "setDefaultEventParameters", \ + "(Landroid/os/Bundle;)V") // clang-format on // clang-format off @@ -340,8 +343,8 @@ void AddToBundle(JNIEnv* env, jobject bundle, const char* key, void AddToBundle(JNIEnv* env, jobject bundle, const char* key, double value) { jstring key_string = env->NewStringUTF(key); env->CallVoidMethod(bundle, - util::bundle::GetMethodId(util::bundle::kPutFloat), - key_string, static_cast(value)); + util::bundle::GetMethodId(util::bundle::kPutDouble), + key_string, static_cast(value)); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(key_string); } @@ -518,6 +521,60 @@ void LogEvent(const char* name, const Parameter* parameters, }); } +// log an event and the associated parameters via a vector. +void LogEvent(const char* name, const std::vector& parameters) { + LogEvent(name, parameters.data(), parameters.size()); +} + +// Set the default event parameters. +void SetDefaultEventParameters(const Parameter* parameters, + size_t number_of_parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + JNIEnv* env = g_app->GetJNIEnv(); + + if (!parameters || number_of_parameters == 0) { + env->CallVoidMethod( + g_analytics_class_instance, + analytics::GetMethodId(analytics::kSetDefaultEventParameters), nullptr); + if (util::CheckAndClearJniExceptions(env)) { + LogError("Failed to set default event parameters"); + } + return; + } + + jobject bundle = + env->NewObject(util::bundle::GetClass(), + util::bundle::GetMethodId(util::bundle::kConstructor)); + if (util::CheckAndClearJniExceptions(env) || !bundle) { + LogError("Failed to create bundle for SetDefaultEventParameters."); + if (bundle) env->DeleteLocalRef(bundle); + return; + } + + for (size_t i = 0; i < number_of_parameters; ++i) { + const Parameter& parameter = parameters[i]; + if (!AddVariantToBundle(env, bundle, parameter.name, parameter.value)) { + // A Variant type that couldn't be handled was passed in. + LogError( + "SetDefaultEventParameters(%s): %s is not a valid parameter value" + " type. Excluded from default parameters.", + parameter.name, Variant::TypeName(parameter.value.type())); + } + } + env->CallVoidMethod( + g_analytics_class_instance, + analytics::GetMethodId(analytics::kSetDefaultEventParameters), bundle); + if (util::CheckAndClearJniExceptions(env)) { + LogError("Failed to set default event parameters"); + } + env->DeleteLocalRef(bundle); +} + +// Set the default event parameters +void SetDefaultEventParameters(const std::vector& parameters) { + SetDefaultEventParameters(parameters.data(), parameters.size()); +} + /// Initiates on-device conversion measurement given a user email address on iOS /// (no-op on Android). On iOS, requires dependency /// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a diff --git a/analytics/src/analytics_desktop.cc b/analytics/src/analytics_desktop.cc index 24f7effb79..08b2b090cb 100644 --- a/analytics/src/analytics_desktop.cc +++ b/analytics/src/analytics_desktop.cc @@ -310,6 +310,11 @@ void LogEvent(const char* name, const Parameter* parameters, // c_event_params if non-null. } +// log an event and the associated parameters via a vector. +void LogEvent(const char* name, const std::vector& parameters) { + LogEvent(name, parameters.data(), parameters.size()); +} + // Sets a user property to the given value. // // Up to 25 user property names are supported. Once set, user property values @@ -429,6 +434,15 @@ void LogEvent(const char* name, const char* parameter_name, // --- Stub Implementations for Unsupported Features --- +void SetDefaultEventParameters(const Parameter* parameters, + size_t number_of_parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); +} + +void SetDefaultEventParameters(const std::vector& parameters) { + SetDefaultEventParameters(parameters.data(), parameters.size()); +} + void SetConsent(const std::map& consent_settings) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); diff --git a/analytics/src/analytics_desktop_dynamic.c b/analytics/src/analytics_desktop_dynamic.c index dec496ba40..fe096076a6 100644 --- a/analytics/src/analytics_desktop_dynamic.c +++ b/analytics/src/analytics_desktop_dynamic.c @@ -139,6 +139,10 @@ static void Stub_GoogleAnalytics_LogEvent(const char* name, GoogleAnalytics_Even // No return value. } +static void Stub_GoogleAnalytics_SetDefaultEventParameters(GoogleAnalytics_EventParameters* parameters, size_t number_of_parameters) { + // No return value. +} + // Stub for GoogleAnalytics_SetUserProperty static void Stub_GoogleAnalytics_SetUserProperty(const char* name, const char* value) { @@ -180,6 +184,7 @@ void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalytics_Eve void (*ptr_GoogleAnalytics_EventParameters_Destroy)(GoogleAnalytics_EventParameters* event_parameter_map) = &Stub_GoogleAnalytics_EventParameters_Destroy; bool (*ptr_GoogleAnalytics_Initialize)(const GoogleAnalytics_Options* options) = &Stub_GoogleAnalytics_Initialize; void (*ptr_GoogleAnalytics_LogEvent)(const char* name, GoogleAnalytics_EventParameters* parameters) = &Stub_GoogleAnalytics_LogEvent; +void (*ptr_GoogleAnalytics_SetDefaultEventParameters)(GoogleAnalytics_EventParameters* parameters, size_t number_of_parameters) = &Stub_GoogleAnalytics_SetDefaultEventParameters; void (*ptr_GoogleAnalytics_SetUserProperty)(const char* name, const char* value) = &Stub_GoogleAnalytics_SetUserProperty; void (*ptr_GoogleAnalytics_SetUserId)(const char* user_id) = &Stub_GoogleAnalytics_SetUserId; void (*ptr_GoogleAnalytics_ResetAnalyticsData)() = &Stub_GoogleAnalytics_ResetAnalyticsData; diff --git a/analytics/src/analytics_desktop_dynamic.h b/analytics/src/analytics_desktop_dynamic.h index 55567bd1ba..b9c06b3deb 100644 --- a/analytics/src/analytics_desktop_dynamic.h +++ b/analytics/src/analytics_desktop_dynamic.h @@ -164,6 +164,7 @@ extern void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalyt extern void (*ptr_GoogleAnalytics_EventParameters_Destroy)(GoogleAnalytics_EventParameters* event_parameter_map); extern bool (*ptr_GoogleAnalytics_Initialize)(const GoogleAnalytics_Options* options); extern void (*ptr_GoogleAnalytics_LogEvent)(const char* name, GoogleAnalytics_EventParameters* parameters); +extern void (*ptr_GoogleAnalytics_SetDefaultEventParameters)(GoogleAnalytics_EventParameters* parameters, size_t number_of_parameters); extern void (*ptr_GoogleAnalytics_SetUserProperty)(const char* name, const char* value); extern void (*ptr_GoogleAnalytics_SetUserId)(const char* user_id); extern void (*ptr_GoogleAnalytics_ResetAnalyticsData)(); diff --git a/analytics/src/analytics_ios.mm b/analytics/src/analytics_ios.mm index d56fd61356..3ca93d9326 100644 --- a/analytics/src/analytics_ios.mm +++ b/analytics/src/analytics_ios.mm @@ -312,6 +312,40 @@ void LogEvent(const char* name, const Parameter* parameters, size_t number_of_pa [FIRAnalytics logEventWithName:@(name) parameters:parameters_dict]; } +// log an event and the associated parameters via a vector. +void LogEvent(const char* name, const std::vector& parameters) { + LogEvent(name, parameters.data(), parameters.size()); +} + +// Sets the default event parameter +void SetDefaultEventParameters(const Parameter* parameters, size_t number_of_parameters) { + FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + + if (!parameters || number_of_parameters == 0) { + [FIRAnalytics setDefaultEventParameters:nil]; + return; + } + + NSMutableDictionary* parameters_dict = + [NSMutableDictionary dictionaryWithCapacity:number_of_parameters]; + for (size_t i = 0; i < number_of_parameters; ++i) { + const Parameter& parameter = parameters[i]; + NSString* parameter_name = SafeString(parameter.name); + if (!AddVariantToDictionary(parameters_dict, parameter_name, parameter.value)) { + // A Variant type that couldn't be handled was passed in. + LogError("SetDefaultEventParameters(%s): %s is not a valid parameter value type. " + "The parameter was not added.", + parameter.name, Variant::TypeName(parameter.value.type())); + } + } + [FIRAnalytics setDefaultEventParameters:parameters_dict]; +} + +// Sets the default event parameters via a vector +void SetDefaultEventParameters(const std::vector& parameters) { + SetDefaultEventParameters(parameters.data(), parameters.size()); +} + /// Initiates on-device conversion measurement given a user email address on iOS (no-op on /// Android). On iOS, requires dependency GoogleAppMeasurementOnDeviceConversion to be linked /// in, otherwise it is a no-op. diff --git a/analytics/src/include/firebase/analytics.h b/analytics/src/include/firebase/analytics.h index 746df99894..2ee77fd9e7 100644 --- a/analytics/src/include/firebase/analytics.h +++ b/analytics/src/include/firebase/analytics.h @@ -476,6 +476,55 @@ void LogEvent(const char* name); void LogEvent(const char* name, const Parameter* parameters, size_t number_of_parameters); +/// @brief Log an event with associated parameters. +/// +/// An Event is an important occurrence in your app that you want to +/// measure. You can report up to 500 different types of events per app and +/// you can associate up to 25 unique parameters with each Event type. +/// +/// Some common events are documented in @ref event_names (%event_names.h), +/// but you may also choose to specify custom event types that are associated +/// with your specific app. +/// +/// @param[in] name Name of the event to log. Should contain 1 to 40 +/// alphanumeric characters or underscores. The name must start with an +/// alphabetic character. Some event names are reserved. See @ref event_names +/// (%event_names.h) for the list of reserved event names. The "firebase_" +/// prefix is reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in +/// case will result in two distinct events. +/// @param[in] parameters Vector of Parameter structures. +void LogEvent(const char* name, const std::vector& parameters); + +/// @brief Adds parameters that will be set on every event logged from the SDK. +/// +/// Adds parameters that will be set on every event logged from the SDK, +/// including automatic ones. The values passed in the parameters bundle will +/// be added to the map of default event parameters. These parameters persist +/// across app runs. They are of lower precedence than event parameters, so if +/// an event parameter and a parameter set using this API have the same name, +/// the value of the event parameter will be used. The same limitations on event +/// parameters apply to default event parameters. +/// +/// @param[in] parameters Array of Parameter structures. +/// @param[in] number_of_parameters Number of elements in the parameters +/// array. +void SetDefaultEventParameters(const Parameter* parameters, + size_t number_of_parameters); + +/// @brief Adds parameters that will be set on every event logged from the SDK. +/// +/// Adds parameters that will be set on every event logged from the SDK, +/// including automatic ones. The values passed in the parameters bundle will +/// be added to the map of default event parameters. These parameters persist +/// across app runs. They are of lower precedence than event parameters, so if +/// an event parameter and a parameter set using this API have the same name, +/// the value of the event parameter will be used. The same limitations on event +/// parameters apply to default event parameters. +/// +/// @param[in] parameters reference to vector of Parameter structures. +void SetDefaultEventParameters(const std::vector& parameters); + /// Initiates on-device conversion measurement given a user email address on iOS /// and tvOS (no-op on Android). On iOS and tvOS, this method requires the /// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, diff --git a/app/src/util_android.h b/app/src/util_android.h index 3467c53b22..222144533f 100644 --- a/app/src/util_android.h +++ b/app/src/util_android.h @@ -496,6 +496,7 @@ METHOD_LOOKUP_DECLARATION(activity, ACTIVITY_METHODS) X(GetString, "getString", "(Ljava/lang/String;)Ljava/lang/String;"), \ X(KeySet, "keySet", "()Ljava/util/Set;"), \ X(PutFloat, "putFloat", "(Ljava/lang/String;F)V"), \ + X(PutDouble, "putDouble", "(Ljava/lang/String;D)V"), \ X(PutLong, "putLong", "(Ljava/lang/String;J)V"), \ X(PutString, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"), \ X(PutBundle, "putBundle", "(Ljava/lang/String;Landroid/os/Bundle;)V"), \ diff --git a/release_build_files/readme.md b/release_build_files/readme.md index d8452c5f24..21504b6c10 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -618,6 +618,10 @@ code. - Storage: Add support for Firebase Storage emulator via `UseEmulator`. The `UseEmulator` method should be called before invoking any other methods on a new instance of Storage. Default port is 9199. + - Analytics: Add support for SetDefaultEventParameters in Android and iOS. + Adds parameters that will be set on every event logged from the SDK, + including automatic ones. + - Analytics: Enables LogEvent to take in a vector of parameters. ### 13.2.0 - Changes