diff --git a/analytics/CMakeLists.txt b/analytics/CMakeLists.txt index 0b5603f871..63d33b125f 100644 --- a/analytics/CMakeLists.txt +++ b/analytics/CMakeLists.txt @@ -104,6 +104,9 @@ set_property(TARGET firebase_analytics PROPERTY FOLDER "Firebase Cpp") # Set up the dependency on Firebase App. target_link_libraries(firebase_analytics PUBLIC firebase_app) +if(WIN32) + target_link_libraries(firebase_analytics PRIVATE Crypt32.lib) +endif() # Public headers all refer to each other relative to the src/include directory, # while private headers are relative to the entire C++ SDK directory. target_include_directories(firebase_analytics diff --git a/analytics/generate_windows_stubs.py b/analytics/generate_windows_stubs.py index cc89422395..0b7f7f0db3 100755 --- a/analytics/generate_windows_stubs.py +++ b/analytics/generate_windows_stubs.py @@ -55,13 +55,34 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o initialized pointers, and a dynamic loading function for Windows. Args: - header_file_path (str): The path to the DLL file. + dll_file_path (str): The path to the DLL file. header_file_path (str): The path to the input C header file. output_h_path (str): The path for the generated C header output file. output_c_path (str): The path for the generated C source output file. """ print(f"Reading DLL file: {dll_file_path}") - dll_hash = hash_file(dll_file_path) + dll_hash = hash_file(dll_file_path) # This is binary + + # --- Manage known hashes --- + hash_file_path = os.path.join(os.path.dirname(dll_file_path), "known_dll_hashes.txt") + known_hex_hashes = [] + try: + with open(hash_file_path, 'r') as f: + for line in f: + known_hex_hashes.append(line.strip()) + except FileNotFoundError: + print(f"Info: '{hash_file_path}' not found, will be created.") + pass # File doesn't exist, list remains empty + + current_dll_hex_hash = dll_hash.hex() + if current_dll_hex_hash not in known_hex_hashes: + known_hex_hashes.append(current_dll_hex_hash) + + with open(hash_file_path, 'w') as f: + for hex_hash in known_hex_hashes: + f.write(hex_hash + '\n') + print(f"Updated known hashes in: {hash_file_path}") + # --- End of manage known hashes --- print(f"Reading header file: {header_file_path}") try: @@ -77,7 +98,7 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o includes = re.findall(r"#include\s+<.*?>", header_content) # Find all typedefs, including their documentation comments - typedefs = re.findall(r"/\*\*(?:[\s\S]*?)\*/\s*typedef[\s\S]*?;\s*", header_content) + typedefs = re.findall(r"(?:/\*\*(?:[\s\S]*?)\*/\s*)?typedef[\s\S]*?;\s*", header_content) # --- Extract function prototypes --- function_pattern = re.compile( @@ -104,7 +125,7 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o if "void" in return_type: return_statement = " // No return value." elif "*" in return_type: - return_statement = f' return ({return_type})(&g_stub_memory);' + return_statement = f' return ({return_type})(&g_stub_memory[0]);' else: # bool, int64_t, etc. return_statement = " return 1;" @@ -136,6 +157,7 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n") f.write(f"#ifndef {header_guard}\n") f.write(f"#define {header_guard}\n\n") + f.write(f"#define ANALYTICS_API // filter out from header copy\n\n") f.write("#include // needed for bool type in pure C\n\n") f.write("// --- Copied from original header ---\n") @@ -157,8 +179,10 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o f.write("\n// --- Dynamic Loader Declaration for Windows ---\n") f.write("#if defined(_WIN32)\n\n") f.write('#include \n') - f.write(f'\n// Google Analytics Windows DLL SHA256 hash, to be verified before loading.') - f.write(f'\nextern const unsigned char FirebaseAnalytics_WindowsDllHash[{len(dll_hash)}];\n\n'); + f.write('\n// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings).\n') + f.write('extern const char* FirebaseAnalytics_KnownWindowsDllHashes[];\n') + f.write('// Count of known Google Analytics Windows DLL SHA256 hashes.\n') + f.write('extern const int FirebaseAnalytics_KnownWindowsDllHashCount;\n\n') f.write('// Load Analytics functions from the given DLL handle into function pointers.\n') f.write(f'// Returns the number of functions successfully loaded.\n') f.write("int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle);\n\n") @@ -178,15 +202,23 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n") f.write(f'#include "{INCLUDE_PREFIX}{os.path.basename(output_h_path)}"\n\n') f.write('#include \n\n') - f.write("static void* g_stub_memory = NULL;\n\n") + f.write("// A nice big chunk of stub memory that can be returned by stubbed Create methods.\n") + f.write("static char g_stub_memory[256] = {0};\n\n") f.write("// clang-format off\n") f.write(f'\n// Number of Google Analytics functions expected to be loaded from the DLL.') f.write(f'\nconst int FirebaseAnalytics_DynamicFunctionCount = {len(function_details_for_loader)};\n\n'); f.write("#if defined(_WIN32)\n") - f.write('// Google Analytics Windows DLL SHA256 hash, to be verified before loading.\n') - f.write('const unsigned char FirebaseAnalytics_WindowsDllHash[] = {\n ') - f.write(', '.join(["0x%02x" % s for s in dll_hash])) - f.write('\n};\n') + f.write('// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings).\n') + f.write('const char* FirebaseAnalytics_KnownWindowsDllHashes[] = {\n') + if known_hex_hashes: + for i, hex_hash in enumerate(known_hex_hashes): + f.write(f' "{hex_hash}"') + if i < len(known_hex_hashes) - 1: + f.write(',') + f.write('\n') + f.write('};\n\n') + f.write('// Count of known Google Analytics Windows DLL SHA256 hashes.\n') + f.write(f'const int FirebaseAnalytics_KnownWindowsDllHashCount = {len(known_hex_hashes)};\n') f.write("#endif // defined(_WIN32)\n") f.write("\n// --- Stub Function Definitions ---\n") f.write("\n\n".join(stub_functions)) @@ -231,25 +263,21 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o parser.add_argument( "--windows_dll", default = os.path.join(os.path.dirname(sys.argv[0]), "windows/analytics_win.dll"), - #required=True, help="Path to the DLL file to calculate a hash." ) parser.add_argument( "--windows_header", default = os.path.join(os.path.dirname(sys.argv[0]), "windows/include/public/c/analytics.h"), - #required=True, help="Path to the input C header file." ) parser.add_argument( "--output_header", default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_desktop_dynamic.h"), - #required=True, help="Path for the generated output header file." ) parser.add_argument( "--output_source", default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_desktop_dynamic.c"), - #required=True, help="Path for the generated output source file." ) args = parser.parse_args() diff --git a/analytics/src/analytics_desktop.cc b/analytics/src/analytics_desktop.cc index 5e9669bf7b..b484beee9a 100644 --- a/analytics/src/analytics_desktop.cc +++ b/analytics/src/analytics_desktop.cc @@ -29,7 +29,7 @@ #if defined(_WIN32) #include -#include "analytics/src/analytics_windows.h" +#include "analytics_windows.h" #endif // defined(_WIN32) namespace firebase { @@ -45,15 +45,11 @@ static HMODULE g_analytics_module = 0; // This is initialized in `Initialize()` and cleaned up in `Terminate()`. static bool g_initialized = false; static int g_fake_instance_id = 0; +static bool g_analytics_collection_enabled = true; // Initializes the Analytics desktop API. // This function must be called before any other Analytics methods. void Initialize(const App& app) { - // The 'app' parameter is not directly used by the underlying Google Analytics - // C API for Windows for global initialization. It's included for API - // consistency with other Firebase platforms. - (void)app; - g_initialized = true; internal::RegisterTerminateOnDefaultAppDestroy(); internal::FutureData::Create(); @@ -61,20 +57,19 @@ void Initialize(const App& app) { #if defined(_WIN32) if (!g_analytics_module) { - std::vector> allowed_hashes; - std::vector current_hash; - current_hash.assign(FirebaseAnalytics_WindowsDllHash, - FirebaseAnalytics_WindowsDllHash + - sizeof(FirebaseAnalytics_WindowsDllHash)); - allowed_hashes.push_back(current_hash); + std::vector allowed_hashes; + for (int i = 0; i < FirebaseAnalytics_KnownWindowsDllHashCount; i++) { + allowed_hashes.push_back( + std::string(FirebaseAnalytics_KnownWindowsDllHashes[i])); + } g_analytics_module = firebase::analytics::internal::VerifyAndLoadAnalyticsLibrary( ANALYTICS_DLL_FILENAME, allowed_hashes); if (g_analytics_module) { - int num_loaded = FirebaseAnalytics_LoadDynamicFunctions( - g_analytics_module); // Ensure g_analytics_module is used + int num_loaded = + FirebaseAnalytics_LoadDynamicFunctions(g_analytics_module); if (num_loaded < FirebaseAnalytics_DynamicFunctionCount) { LogWarning( "Analytics: Failed to load functions from Google Analytics " @@ -83,12 +78,46 @@ void Initialize(const App& app) { FirebaseAnalytics_UnloadDynamicFunctions(); FreeLibrary(g_analytics_module); g_analytics_module = 0; + // Do not proceed with C API initialization if functions didn't load } else { LogInfo("Analytics: Loaded Google Analytics module."); + + // Initialize Google Analytics C API + std::string current_app_id = app.options().app_id(); + std::string current_package_name = app.options().package_name(); + + GoogleAnalytics_Options* c_options = GoogleAnalytics_Options_Create(); + if (!c_options) { + LogError("Analytics: Failed to create GoogleAnalytics_Options."); + } else { + c_options->app_id = current_app_id.c_str(); + c_options->package_name = current_package_name.c_str(); + c_options->analytics_collection_enabled_at_first_launch = + g_analytics_collection_enabled; + + LogInfo( + "Analytics: Initializing Google Analytics C API with App ID: %s, " + "Package Name: %s", + c_options->app_id ? c_options->app_id : "null", + c_options->package_name ? c_options->package_name : "null"); + + if (!GoogleAnalytics_Initialize(c_options)) { + LogError("Analytics: Failed to initialize Google Analytics C API."); + // GoogleAnalytics_Initialize destroys c_options automatically if + // created by _Create + } else { + LogInfo( + "Analytics: Google Analytics C API initialized successfully."); + } + } } + } else { + // LogWarning for g_analytics_module load failure is handled by + // VerifyAndLoadAnalyticsLibrary + g_analytics_module = 0; // Ensure it's null if loading failed } } -#endif +#endif // defined(_WIN32) } namespace internal { @@ -107,7 +136,7 @@ void Terminate() { FreeLibrary(g_analytics_module); g_analytics_module = 0; } -#endif +#endif // defined(_WIN32) internal::FutureData::Destroy(); internal::UnregisterTerminateOnDefaultAppDestroy(); @@ -141,10 +170,16 @@ static void ConvertParametersToGAParams( // Vector types for top-level event parameters are not supported on // Desktop. Only specific complex types (like a map processed into an // ItemVector) are handled. - LogError( - "Analytics: Parameter '%s' has type Vector, which is unsupported for " - "event parameters on Desktop. Skipping.", - param.name); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogError( + "Analytics: Parameter '%s' has type Vector, which is unsupported " + "for " + "event parameters on Desktop. Skipping.", + param.name); + } +#endif // defined(_WIN32) continue; // Skip this parameter } else if (param.value.is_map()) { // This block handles parameters that are maps. @@ -328,9 +363,11 @@ void SetUserId(const char* user_id) { // // @param[in] enabled A flag that enables or disables Analytics collection. void SetAnalyticsCollectionEnabled(bool enabled) { - FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); + g_analytics_collection_enabled = enabled; - GoogleAnalytics_SetAnalyticsCollectionEnabled(enabled); + if (internal::IsInitialized()) { + GoogleAnalytics_SetAnalyticsCollectionEnabled(enabled); + } } // Clears all analytics data for this app from the device and resets the app @@ -395,53 +432,85 @@ void SetConsent(const std::map& consent_settings) { // Not supported by the Windows C API. (void)consent_settings; // Mark as unused - LogWarning( - "Analytics: SetConsent() is not supported and has no effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: SetConsent() is not supported and has no effect on " + "Desktop."); + } +#endif // defined(_WIN32) } void InitiateOnDeviceConversionMeasurementWithEmailAddress( const char* email_address) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); (void)email_address; - LogWarning( - "Analytics: InitiateOnDeviceConversionMeasurementWithEmailAddress() is " - "not supported and has no effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: InitiateOnDeviceConversionMeasurementWithEmailAddress() is " + "not supported and has no effect on Desktop."); + } +#endif // defined(_WIN32) } void InitiateOnDeviceConversionMeasurementWithPhoneNumber( const char* phone_number) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); (void)phone_number; - LogWarning( - "Analytics: InitiateOnDeviceConversionMeasurementWithPhoneNumber() is " - "not supported and has no effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: InitiateOnDeviceConversionMeasurementWithPhoneNumber() is " + "not supported and has no effect on Desktop."); + } +#endif // defined(_WIN32) } void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress( std::vector hashed_email_address) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); (void)hashed_email_address; - LogWarning( - "Analytics: " - "InitiateOnDeviceConversionMeasurementWithHashedEmailAddress() is not " - "supported and has no effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: " + "InitiateOnDeviceConversionMeasurementWithHashedEmailAddress() is not " + "supported and has no effect on Desktop."); + } +#endif // defined(_WIN32) } void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber( std::vector hashed_phone_number) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); (void)hashed_phone_number; - LogWarning( - "Analytics: InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber() " - "is not supported and has no effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: " + "InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber() " + "is not supported and has no effect on Desktop."); + } +#endif // defined(_WIN32) } void SetSessionTimeoutDuration(int64_t milliseconds) { FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized()); (void)milliseconds; - LogWarning( - "Analytics: SetSessionTimeoutDuration() is not supported and has no " - "effect on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: SetSessionTimeoutDuration() is not supported and has no " + "effect on Desktop."); + } +#endif // defined(_WIN32) } Future GetAnalyticsInstanceId() { @@ -456,8 +525,14 @@ Future GetAnalyticsInstanceId() { instance_id += ss.str(); } api->CompleteWithResult(future_handle, 0, "", instance_id); - LogWarning( - "Analytics: GetAnalyticsInstanceId() is not supported on Desktop."); + +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: GetAnalyticsInstanceId() is not supported on Desktop."); + } +#endif // defined(_WIN32) return Future(api, future_handle.get()); } @@ -478,14 +553,24 @@ Future GetSessionId() { api->SafeAlloc(internal::kAnalyticsFnGetSessionId); int64_t session_id = 0x5E5510171D570BL; // "SESSIONIDSTUB", kinda api->CompleteWithResult(future_handle, 0, "", session_id); - LogWarning("Analytics: GetSessionId() is not supported on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning("Analytics: GetSessionId() is not supported on Desktop."); + } +#endif // defined(_WIN32) return Future(api, future_handle.get()); } Future GetSessionIdLastResult() { FIREBASE_ASSERT_RETURN(Future(), internal::IsInitialized()); - LogWarning( - "Analytics: GetSessionIdLastResult() is not supported on Desktop."); +#if defined(_WIN32) + if (g_analytics_module) { + // Only log this if we are not in stub mode. + LogWarning( + "Analytics: GetSessionIdLastResult() is not supported on Desktop."); + } +#endif // defined(_WIN32) return static_cast&>( internal::FutureData::Get()->api()->LastResult( internal::kAnalyticsFnGetSessionId)); diff --git a/analytics/src/analytics_desktop_dynamic.c b/analytics/src/analytics_desktop_dynamic.c index e629e59474..dec496ba40 100644 --- a/analytics/src/analytics_desktop_dynamic.c +++ b/analytics/src/analytics_desktop_dynamic.c @@ -18,24 +18,40 @@ #include -static void* g_stub_memory = NULL; +// A nice big chunk of stub memory that can be returned by stubbed Create +// methods. +static char g_stub_memory[256] = {0}; // clang-format off // Number of Google Analytics functions expected to be loaded from the DLL. -const int FirebaseAnalytics_DynamicFunctionCount = 19; +const int FirebaseAnalytics_DynamicFunctionCount = 22; #if defined(_WIN32) -// Google Analytics Windows DLL SHA256 hash, to be verified on load. -const unsigned char FirebaseAnalytics_WindowsDllHash[] = { - 0xc1, 0xb9, 0xff, 0x6e, 0x91, 0x19, 0xc3, 0x0b, 0xbe, 0xb7, 0x47, 0x23, 0x26, 0xdc, 0xde, 0x41, 0x8f, 0x45, 0x68, 0x2e, 0x6b, 0x82, 0x2e, 0x25, 0xee, 0xd9, 0x22, 0xfe, 0x6e, 0x3c, 0xc6, 0x98 +// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings). +const char* FirebaseAnalytics_KnownWindowsDllHashes[] = { + "c1b9ff6e9119c30bbeb7472326dcde418f45682e6b822e25eed922fe6e3cc698", + "13ae5f9349b24186f1f3667b52832076e8d14ad9656c3546b1b7fca79ac8144b" }; + +// Count of known Google Analytics Windows DLL SHA256 hashes. +const int FirebaseAnalytics_KnownWindowsDllHashCount = 2; #endif // defined(_WIN32) // --- Stub Function Definitions --- +// Stub for GoogleAnalytics_Options_Create +static GoogleAnalytics_Options* Stub_GoogleAnalytics_Options_Create() { + return (GoogleAnalytics_Options*)(&g_stub_memory[0]); +} + +// Stub for GoogleAnalytics_Options_Destroy +static void Stub_GoogleAnalytics_Options_Destroy(GoogleAnalytics_Options* options) { + // No return value. +} + // Stub for GoogleAnalytics_Item_Create static GoogleAnalytics_Item* Stub_GoogleAnalytics_Item_Create() { - return (GoogleAnalytics_Item*)(&g_stub_memory); + return (GoogleAnalytics_Item*)(&g_stub_memory[0]); } // Stub for GoogleAnalytics_Item_InsertInt @@ -66,7 +82,7 @@ static void Stub_GoogleAnalytics_Item_Destroy(GoogleAnalytics_Item* item) { // Stub for GoogleAnalytics_ItemVector_Create static GoogleAnalytics_ItemVector* Stub_GoogleAnalytics_ItemVector_Create() { - return (GoogleAnalytics_ItemVector*)(&g_stub_memory); + return (GoogleAnalytics_ItemVector*)(&g_stub_memory[0]); } // Stub for GoogleAnalytics_ItemVector_InsertItem @@ -81,7 +97,7 @@ static void Stub_GoogleAnalytics_ItemVector_Destroy(GoogleAnalytics_ItemVector* // Stub for GoogleAnalytics_EventParameters_Create static GoogleAnalytics_EventParameters* Stub_GoogleAnalytics_EventParameters_Create() { - return (GoogleAnalytics_EventParameters*)(&g_stub_memory); + return (GoogleAnalytics_EventParameters*)(&g_stub_memory[0]); } // Stub for GoogleAnalytics_EventParameters_InsertInt @@ -113,6 +129,11 @@ static void Stub_GoogleAnalytics_EventParameters_Destroy(GoogleAnalytics_EventPa // No return value. } +// Stub for GoogleAnalytics_Initialize +static bool Stub_GoogleAnalytics_Initialize(const GoogleAnalytics_Options* options) { + return 1; +} + // Stub for GoogleAnalytics_LogEvent static void Stub_GoogleAnalytics_LogEvent(const char* name, GoogleAnalytics_EventParameters* parameters) { // No return value. @@ -141,6 +162,8 @@ static void Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled(bool enabled) { // --- Function Pointer Initializations --- +GoogleAnalytics_Options* (*ptr_GoogleAnalytics_Options_Create)() = &Stub_GoogleAnalytics_Options_Create; +void (*ptr_GoogleAnalytics_Options_Destroy)(GoogleAnalytics_Options* options) = &Stub_GoogleAnalytics_Options_Destroy; GoogleAnalytics_Item* (*ptr_GoogleAnalytics_Item_Create)() = &Stub_GoogleAnalytics_Item_Create; void (*ptr_GoogleAnalytics_Item_InsertInt)(GoogleAnalytics_Item* item, const char* key, int64_t value) = &Stub_GoogleAnalytics_Item_InsertInt; void (*ptr_GoogleAnalytics_Item_InsertDouble)(GoogleAnalytics_Item* item, const char* key, double value) = &Stub_GoogleAnalytics_Item_InsertDouble; @@ -155,6 +178,7 @@ void (*ptr_GoogleAnalytics_EventParameters_InsertDouble)(GoogleAnalytics_EventPa void (*ptr_GoogleAnalytics_EventParameters_InsertString)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, const char* value) = &Stub_GoogleAnalytics_EventParameters_InsertString; void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, GoogleAnalytics_ItemVector* value) = &Stub_GoogleAnalytics_EventParameters_InsertItemVector; 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_SetUserProperty)(const char* name, const char* value) = &Stub_GoogleAnalytics_SetUserProperty; void (*ptr_GoogleAnalytics_SetUserId)(const char* user_id) = &Stub_GoogleAnalytics_SetUserId; @@ -170,6 +194,16 @@ int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) { return count; } + FARPROC proc_GoogleAnalytics_Options_Create = GetProcAddress(dll_handle, "GoogleAnalytics_Options_Create"); + if (proc_GoogleAnalytics_Options_Create) { + ptr_GoogleAnalytics_Options_Create = (GoogleAnalytics_Options* (*)())proc_GoogleAnalytics_Options_Create; + count++; + } + FARPROC proc_GoogleAnalytics_Options_Destroy = GetProcAddress(dll_handle, "GoogleAnalytics_Options_Destroy"); + if (proc_GoogleAnalytics_Options_Destroy) { + ptr_GoogleAnalytics_Options_Destroy = (void (*)(GoogleAnalytics_Options* options))proc_GoogleAnalytics_Options_Destroy; + count++; + } FARPROC proc_GoogleAnalytics_Item_Create = GetProcAddress(dll_handle, "GoogleAnalytics_Item_Create"); if (proc_GoogleAnalytics_Item_Create) { ptr_GoogleAnalytics_Item_Create = (GoogleAnalytics_Item* (*)())proc_GoogleAnalytics_Item_Create; @@ -240,6 +274,11 @@ int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) { ptr_GoogleAnalytics_EventParameters_Destroy = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map))proc_GoogleAnalytics_EventParameters_Destroy; count++; } + FARPROC proc_GoogleAnalytics_Initialize = GetProcAddress(dll_handle, "GoogleAnalytics_Initialize"); + if (proc_GoogleAnalytics_Initialize) { + ptr_GoogleAnalytics_Initialize = (bool (*)(const GoogleAnalytics_Options* options))proc_GoogleAnalytics_Initialize; + count++; + } FARPROC proc_GoogleAnalytics_LogEvent = GetProcAddress(dll_handle, "GoogleAnalytics_LogEvent"); if (proc_GoogleAnalytics_LogEvent) { ptr_GoogleAnalytics_LogEvent = (void (*)(const char* name, GoogleAnalytics_EventParameters* parameters))proc_GoogleAnalytics_LogEvent; @@ -270,6 +309,8 @@ int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) { } void FirebaseAnalytics_UnloadDynamicFunctions(void) { + ptr_GoogleAnalytics_Options_Create = &Stub_GoogleAnalytics_Options_Create; + ptr_GoogleAnalytics_Options_Destroy = &Stub_GoogleAnalytics_Options_Destroy; ptr_GoogleAnalytics_Item_Create = &Stub_GoogleAnalytics_Item_Create; ptr_GoogleAnalytics_Item_InsertInt = &Stub_GoogleAnalytics_Item_InsertInt; ptr_GoogleAnalytics_Item_InsertDouble = &Stub_GoogleAnalytics_Item_InsertDouble; @@ -284,6 +325,7 @@ void FirebaseAnalytics_UnloadDynamicFunctions(void) { ptr_GoogleAnalytics_EventParameters_InsertString = &Stub_GoogleAnalytics_EventParameters_InsertString; ptr_GoogleAnalytics_EventParameters_InsertItemVector = &Stub_GoogleAnalytics_EventParameters_InsertItemVector; ptr_GoogleAnalytics_EventParameters_Destroy = &Stub_GoogleAnalytics_EventParameters_Destroy; + ptr_GoogleAnalytics_Initialize = &Stub_GoogleAnalytics_Initialize; ptr_GoogleAnalytics_LogEvent = &Stub_GoogleAnalytics_LogEvent; ptr_GoogleAnalytics_SetUserProperty = &Stub_GoogleAnalytics_SetUserProperty; ptr_GoogleAnalytics_SetUserId = &Stub_GoogleAnalytics_SetUserId; diff --git a/analytics/src/analytics_desktop_dynamic.h b/analytics/src/analytics_desktop_dynamic.h index 4d7560388b..55567bd1ba 100644 --- a/analytics/src/analytics_desktop_dynamic.h +++ b/analytics/src/analytics_desktop_dynamic.h @@ -17,11 +17,86 @@ #ifndef FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_ #define FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_ +#define ANALYTICS_API // filter out from header copy + #include // needed for bool type in pure C // --- Copied from original header --- +#include #include +typedef struct GoogleAnalytics_Reserved_Opaque GoogleAnalytics_Reserved; + +/** + * @brief GoogleAnalytics_Options for initializing the Analytics SDK. + * GoogleAnalytics_Options_Create() must be used to create an instance of this + * struct with default values. If these options are created manually instead of + * using GoogleAnalytics_Options_Create(), initialization will fail, and the + * caller will be responsible for destroying the options. + */ +ANALYTICS_API typedef struct { + /** + * @brief The unique identifier for the Firebase app across all of Firebase + * with a platform-specific format. This is a required field, can not be null + * or empty, and must be UTF-8 encoded. + * + * The caller is responsible for allocating this memory, and deallocating it + * once the options instance has been destroyed. + * + * Example: 1:1234567890:android:321abc456def7890 + */ + const char* app_id; + + /** + * @brief Unique identifier for the application implementing the SDK. The + * format typically follows a reversed domain name convention. This is a + * required field, can not be null or empty, and must be UTF-8 encoded. + * + * The caller is responsible for allocating this memory, and deallocating it + * once the options instance has been destroyed. + * + * Example: com.google.analytics.AnalyticsApp + */ + const char* package_name; + + /** + * @brief Whether Analytics is enabled at the very first launch. + * This value is then persisted across app sessions, and from then on, takes + * precedence over the value of this field. + * GoogleAnalytics_SetAnalyticsCollectionEnabled() can be used to + * enable/disable after that point. + */ + bool analytics_collection_enabled_at_first_launch; + + /** + * @brief Reserved for internal use by the SDK. + */ + GoogleAnalytics_Reserved* reserved; +} GoogleAnalytics_Options; + +/** + * @brief Creates an instance of GoogleAnalytics_Options with default values. + * + * The caller is responsible for destroying the options using the + * GoogleAnalytics_Options_Destroy() function, unless it has been passed to the + * GoogleAnalytics_Initialize() function, in which case it will be destroyed + * automatically. + * + * @return A pointer to a newly allocated GoogleAnalytics_Options instance. + */ +ANALYTICS_API GoogleAnalytics_Options* GoogleAnalytics_Options_Create(); + +/** + * @brief Destroys the GoogleAnalytics_Options instance. Must not be called if + * the options were created with GoogleAnalytics_Options_Create() and passed to + * the GoogleAnalytics_Initialize() function, which would destroy them + * automatically. + * + * @param[in] options The GoogleAnalytics_Options instance to destroy. + */ +ANALYTICS_API void GoogleAnalytics_Options_Destroy( + GoogleAnalytics_Options* options); + /** * @brief Opaque type for an item. * @@ -71,6 +146,8 @@ extern "C" { // --- Function Pointer Declarations --- // clang-format off +extern GoogleAnalytics_Options* (*ptr_GoogleAnalytics_Options_Create)(); +extern void (*ptr_GoogleAnalytics_Options_Destroy)(GoogleAnalytics_Options* options); extern GoogleAnalytics_Item* (*ptr_GoogleAnalytics_Item_Create)(); extern void (*ptr_GoogleAnalytics_Item_InsertInt)(GoogleAnalytics_Item* item, const char* key, int64_t value); extern void (*ptr_GoogleAnalytics_Item_InsertDouble)(GoogleAnalytics_Item* item, const char* key, double value); @@ -85,12 +162,15 @@ extern void (*ptr_GoogleAnalytics_EventParameters_InsertDouble)(GoogleAnalytics_ extern void (*ptr_GoogleAnalytics_EventParameters_InsertString)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, const char* value); extern void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, GoogleAnalytics_ItemVector* value); 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_SetUserProperty)(const char* name, const char* value); extern void (*ptr_GoogleAnalytics_SetUserId)(const char* user_id); extern void (*ptr_GoogleAnalytics_ResetAnalyticsData)(); extern void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled); +#define GoogleAnalytics_Options_Create ptr_GoogleAnalytics_Options_Create +#define GoogleAnalytics_Options_Destroy ptr_GoogleAnalytics_Options_Destroy #define GoogleAnalytics_Item_Create ptr_GoogleAnalytics_Item_Create #define GoogleAnalytics_Item_InsertInt ptr_GoogleAnalytics_Item_InsertInt #define GoogleAnalytics_Item_InsertDouble ptr_GoogleAnalytics_Item_InsertDouble @@ -105,6 +185,7 @@ extern void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled); #define GoogleAnalytics_EventParameters_InsertString ptr_GoogleAnalytics_EventParameters_InsertString #define GoogleAnalytics_EventParameters_InsertItemVector ptr_GoogleAnalytics_EventParameters_InsertItemVector #define GoogleAnalytics_EventParameters_Destroy ptr_GoogleAnalytics_EventParameters_Destroy +#define GoogleAnalytics_Initialize ptr_GoogleAnalytics_Initialize #define GoogleAnalytics_LogEvent ptr_GoogleAnalytics_LogEvent #define GoogleAnalytics_SetUserProperty ptr_GoogleAnalytics_SetUserProperty #define GoogleAnalytics_SetUserId ptr_GoogleAnalytics_SetUserId @@ -120,8 +201,10 @@ extern const int FirebaseAnalytics_DynamicFunctionCount; #include -// Google Analytics Windows DLL SHA256 hash, to be verified before loading. -extern const unsigned char FirebaseAnalytics_WindowsDllHash[32]; +// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings). +extern const char* FirebaseAnalytics_KnownWindowsDllHashes[]; +// Count of known Google Analytics Windows DLL SHA256 hashes. +extern const int FirebaseAnalytics_KnownWindowsDllHashCount; // Load Analytics functions from the given DLL handle into function pointers. // Returns the number of functions successfully loaded. diff --git a/analytics/src/analytics_windows.cc b/analytics/src/analytics_windows.cc index 2eb7ad0efd..5398d8136c 100644 --- a/analytics/src/analytics_windows.cc +++ b/analytics/src/analytics_windows.cc @@ -88,17 +88,18 @@ static std::wstring GetExecutablePath() { } } -// Helper function to calculate SHA256 hash of a file. -static std::vector CalculateFileSha256(HANDLE hFile) { +// Helper function to calculate the SHA256 hash of a file and return it as a hex +// string (upper-case). +static std::string CalculateFileSha256(HANDLE hFile) { HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; - std::vector result_hash_value; + // Ensure the file pointer is at the beginning of the file. if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { DWORD dwError = GetLastError(); LogError(LOG_TAG "CalculateFileSha256.SetFilePointer failed. Error: %u", dwError); - return result_hash_value; + return ""; // Return empty string on failure } // Acquire Crypto Provider. @@ -110,81 +111,115 @@ static std::vector CalculateFileSha256(HANDLE hFile) { LogError(LOG_TAG "CalculateFileSha256.CryptAcquireContextW failed. Error: %u", dwError); - return result_hash_value; + return ""; } + // Create a hash object. if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) { DWORD dwError = GetLastError(); LogError(LOG_TAG "CalculateFileSha256.CryptCreateHash failed. Error: %u", dwError); CryptReleaseContext(hProv, 0); - return result_hash_value; + return ""; } + // Read the file in chunks and hash the data. BYTE rgbFile[1024]; DWORD cbRead = 0; - BOOL bReadSuccessLoop = TRUE; - while (true) { - bReadSuccessLoop = ReadFile(hFile, rgbFile, sizeof(rgbFile), &cbRead, NULL); - if (!bReadSuccessLoop) { + if (!ReadFile(hFile, rgbFile, sizeof(rgbFile), &cbRead, NULL)) { DWORD dwError = GetLastError(); LogError(LOG_TAG "CalculateFileSha256.ReadFile failed. Error: %u", dwError); CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); - return result_hash_value; + return ""; } + // End of file if (cbRead == 0) { break; } + // Add the chunk to the hash object. if (!CryptHashData(hHash, rgbFile, cbRead, 0)) { DWORD dwError = GetLastError(); LogError(LOG_TAG "CalculateFileSha256.CryptHashData failed. Error: %u", dwError); CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); - return result_hash_value; + return ""; } } + // --- Get the binary hash value --- DWORD cbHashValue = 0; DWORD dwCount = sizeof(DWORD); if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashValue, &dwCount, 0)) { DWORD dwError = GetLastError(); LogError(LOG_TAG - "CalculateFileSha256.CryptGetHashParam " - "(HP_HASHSIZE) failed. Error: " - "%u", + "CalculateFileSha256.CryptGetHashParam (HP_HASHSIZE) failed. " + "Error: %u", dwError); CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); - return result_hash_value; + return ""; } - result_hash_value.resize(cbHashValue); - if (!CryptGetHashParam(hHash, HP_HASHVAL, result_hash_value.data(), + std::vector binary_hash_value(cbHashValue); + if (!CryptGetHashParam(hHash, HP_HASHVAL, binary_hash_value.data(), &cbHashValue, 0)) { DWORD dwError = GetLastError(); LogError(LOG_TAG "CalculateFileSha256.CryptGetHashParam (HP_HASHVAL) failed. " "Error: %u", dwError); - result_hash_value.clear(); CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); - return result_hash_value; + return ""; + } + + // --- Convert the binary hash to a hex string --- + DWORD hex_string_size = 0; + if (!CryptBinaryToStringA(binary_hash_value.data(), binary_hash_value.size(), + CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, NULL, + &hex_string_size)) { + DWORD dwError = GetLastError(); + LogError( + LOG_TAG + "CalculateFileSha256.CryptBinaryToStringA (size) failed. Error: %u", + dwError); + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return ""; } + std::string hex_hash_string(hex_string_size, '\0'); + if (!CryptBinaryToStringA(binary_hash_value.data(), binary_hash_value.size(), + CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, + &hex_hash_string[0], &hex_string_size)) { + DWORD dwError = GetLastError(); + LogError(LOG_TAG + "CalculateFileSha256.CryptBinaryToStringA (conversion) failed. " + "Error: %u", + dwError); + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + return ""; + } + + // Remove the null terminator from the string. + hex_hash_string.resize(hex_string_size); + + // --- Final Cleanup --- CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); - return result_hash_value; + + return hex_hash_string; } HMODULE VerifyAndLoadAnalyticsLibrary( const wchar_t* library_filename, - const std::vector>& allowed_hashes) { + const std::vector& allowed_hashes) { if (library_filename == nullptr || library_filename[0] == L'\0') { LogError(LOG_TAG "Invalid arguments."); return nullptr; @@ -245,24 +280,19 @@ HMODULE VerifyAndLoadAnalyticsLibrary( HMODULE hModule = nullptr; - std::vector calculated_hash = CalculateFileSha256(hFile); + std::string calculated_hash = CalculateFileSha256(hFile); - if (calculated_hash.empty()) { + if (calculated_hash.length() == 0) { LogError(LOG_TAG "Hash failed for Analytics DLL."); } else { bool hash_matched = false; for (const auto& expected_hash : allowed_hashes) { - if (calculated_hash.size() != expected_hash.size()) { - LogDebug(LOG_TAG - "Hash size mismatch for Analytics DLL. Expected: %zu, " - "Calculated: %zu. Trying next allowed hash.", - expected_hash.size(), calculated_hash.size()); - continue; - } - if (memcmp(calculated_hash.data(), expected_hash.data(), - expected_hash.size()) == 0) { + if (calculated_hash == expected_hash) { hash_matched = true; break; + } else { + LogDebug(LOG_TAG "Hash mismatch: got %s expected %s", + calculated_hash.c_str(), expected_hash.c_str()); } } diff --git a/analytics/src/analytics_windows.h b/analytics/src/analytics_windows.h index f18683e026..7d9e4489fe 100644 --- a/analytics/src/analytics_windows.h +++ b/analytics/src/analytics_windows.h @@ -17,6 +17,7 @@ #include +#include #include namespace firebase { @@ -25,7 +26,7 @@ namespace internal { HMODULE VerifyAndLoadAnalyticsLibrary( const wchar_t* library_filename, - const std::vector>& allowed_hashes); + const std::vector& allowed_hashes); } // namespace internal } // namespace analytics diff --git a/analytics/src/windows/analytics_dynamic.c b/analytics/src/windows/analytics_dynamic.c deleted file mode 100644 index d7f483b72d..0000000000 --- a/analytics/src/windows/analytics_dynamic.c +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2025 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. - -// Generated from analytics.h by generate_windows_stubs.py - -#include "analytics/src/windows/analytics_dynamic.h" -#include - -// clang-format off - -static void* g_stub_memory = NULL; - -// --- Stub Function Definitions --- -// Stub for GoogleAnalytics_Item_Create -static GoogleAnalytics_Item* Stub_GoogleAnalytics_Item_Create() { - return (GoogleAnalytics_Item*)(&g_stub_memory); -} - -// Stub for GoogleAnalytics_Item_InsertInt -static void Stub_GoogleAnalytics_Item_InsertInt(GoogleAnalytics_Item* item, - const char* key, - int64_t value) { - // No return value. -} - -// Stub for GoogleAnalytics_Item_InsertDouble -static void Stub_GoogleAnalytics_Item_InsertDouble(GoogleAnalytics_Item* item, - const char* key, - double value) { - // No return value. -} - -// Stub for GoogleAnalytics_Item_InsertString -static void Stub_GoogleAnalytics_Item_InsertString(GoogleAnalytics_Item* item, - const char* key, - const char* value) { - // No return value. -} - -// Stub for GoogleAnalytics_Item_Destroy -static void Stub_GoogleAnalytics_Item_Destroy(GoogleAnalytics_Item* item) { - // No return value. -} - -// Stub for GoogleAnalytics_ItemVector_Create -static GoogleAnalytics_ItemVector* Stub_GoogleAnalytics_ItemVector_Create() { - return (GoogleAnalytics_ItemVector*)(&g_stub_memory); -} - -// Stub for GoogleAnalytics_ItemVector_InsertItem -static void Stub_GoogleAnalytics_ItemVector_InsertItem(GoogleAnalytics_ItemVector* item_vector, GoogleAnalytics_Item* item) { - // No return value. -} - -// Stub for GoogleAnalytics_ItemVector_Destroy -static void Stub_GoogleAnalytics_ItemVector_Destroy(GoogleAnalytics_ItemVector* item_vector) { - // No return value. -} - -// Stub for GoogleAnalytics_EventParameters_Create -static GoogleAnalytics_EventParameters* Stub_GoogleAnalytics_EventParameters_Create() { - return (GoogleAnalytics_EventParameters*)(&g_stub_memory); -} - -// Stub for GoogleAnalytics_EventParameters_InsertInt -static void Stub_GoogleAnalytics_EventParameters_InsertInt(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, - int64_t value) { - // No return value. -} - -// Stub for GoogleAnalytics_EventParameters_InsertDouble -static void Stub_GoogleAnalytics_EventParameters_InsertDouble(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, - double value) { - // No return value. -} - -// Stub for GoogleAnalytics_EventParameters_InsertString -static void Stub_GoogleAnalytics_EventParameters_InsertString(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, - const char* value) { - // No return value. -} - -// Stub for GoogleAnalytics_EventParameters_InsertItemVector -static void Stub_GoogleAnalytics_EventParameters_InsertItemVector(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, - GoogleAnalytics_ItemVector* value) { - // No return value. -} - -// Stub for GoogleAnalytics_EventParameters_Destroy -static void Stub_GoogleAnalytics_EventParameters_Destroy(GoogleAnalytics_EventParameters* event_parameter_map) { - // No return value. -} - -// Stub for GoogleAnalytics_LogEvent -static void Stub_GoogleAnalytics_LogEvent(const char* name, GoogleAnalytics_EventParameters* parameters) { - // No return value. -} - -// Stub for GoogleAnalytics_SetUserProperty -static void Stub_GoogleAnalytics_SetUserProperty(const char* name, - const char* value) { - // No return value. -} - -// Stub for GoogleAnalytics_SetUserId -static void Stub_GoogleAnalytics_SetUserId(const char* user_id) { - // No return value. -} - -// Stub for GoogleAnalytics_ResetAnalyticsData -static void Stub_GoogleAnalytics_ResetAnalyticsData() { - // No return value. -} - -// Stub for GoogleAnalytics_SetAnalyticsCollectionEnabled -static void Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled(bool enabled) { - // No return value. -} - - -// --- Function Pointer Initializations --- -GoogleAnalytics_Item* (*ptr_GoogleAnalytics_Item_Create)() = &Stub_GoogleAnalytics_Item_Create; -void (*ptr_GoogleAnalytics_Item_InsertInt)(GoogleAnalytics_Item* item, const char* key, int64_t value) = &Stub_GoogleAnalytics_Item_InsertInt; -void (*ptr_GoogleAnalytics_Item_InsertDouble)(GoogleAnalytics_Item* item, const char* key, double value) = &Stub_GoogleAnalytics_Item_InsertDouble; -void (*ptr_GoogleAnalytics_Item_InsertString)(GoogleAnalytics_Item* item, const char* key, const char* value) = &Stub_GoogleAnalytics_Item_InsertString; -void (*ptr_GoogleAnalytics_Item_Destroy)(GoogleAnalytics_Item* item) = &Stub_GoogleAnalytics_Item_Destroy; -GoogleAnalytics_ItemVector* (*ptr_GoogleAnalytics_ItemVector_Create)() = &Stub_GoogleAnalytics_ItemVector_Create; -void (*ptr_GoogleAnalytics_ItemVector_InsertItem)(GoogleAnalytics_ItemVector* item_vector, GoogleAnalytics_Item* item) = &Stub_GoogleAnalytics_ItemVector_InsertItem; -void (*ptr_GoogleAnalytics_ItemVector_Destroy)(GoogleAnalytics_ItemVector* item_vector) = &Stub_GoogleAnalytics_ItemVector_Destroy; -GoogleAnalytics_EventParameters* (*ptr_GoogleAnalytics_EventParameters_Create)() = &Stub_GoogleAnalytics_EventParameters_Create; -void (*ptr_GoogleAnalytics_EventParameters_InsertInt)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, int64_t value) = &Stub_GoogleAnalytics_EventParameters_InsertInt; -void (*ptr_GoogleAnalytics_EventParameters_InsertDouble)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, double value) = &Stub_GoogleAnalytics_EventParameters_InsertDouble; -void (*ptr_GoogleAnalytics_EventParameters_InsertString)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, const char* value) = &Stub_GoogleAnalytics_EventParameters_InsertString; -void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, GoogleAnalytics_ItemVector* value) = &Stub_GoogleAnalytics_EventParameters_InsertItemVector; -void (*ptr_GoogleAnalytics_EventParameters_Destroy)(GoogleAnalytics_EventParameters* event_parameter_map) = &Stub_GoogleAnalytics_EventParameters_Destroy; -void (*ptr_GoogleAnalytics_LogEvent)(const char* name, GoogleAnalytics_EventParameters* parameters) = &Stub_GoogleAnalytics_LogEvent; -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; -void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled) = &Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled; - -// --- Dynamic Loader Function for Windows --- -#if defined(_WIN32) -int FirebaseAnalytics_LoadAnalyticsFunctions(HMODULE dll_handle) { - int count = 0; - - if (!dll_handle) { - return count; - } - - FARPROC proc_GoogleAnalytics_Item_Create = GetProcAddress(dll_handle, "GoogleAnalytics_Item_Create"); - if (proc_GoogleAnalytics_Item_Create) { - ptr_GoogleAnalytics_Item_Create = (GoogleAnalytics_Item* (*)())proc_GoogleAnalytics_Item_Create; - count++; - } - FARPROC proc_GoogleAnalytics_Item_InsertInt = GetProcAddress(dll_handle, "GoogleAnalytics_Item_InsertInt"); - if (proc_GoogleAnalytics_Item_InsertInt) { - ptr_GoogleAnalytics_Item_InsertInt = (void (*)(GoogleAnalytics_Item* item, const char* key, int64_t value))proc_GoogleAnalytics_Item_InsertInt; - count++; - } - FARPROC proc_GoogleAnalytics_Item_InsertDouble = GetProcAddress(dll_handle, "GoogleAnalytics_Item_InsertDouble"); - if (proc_GoogleAnalytics_Item_InsertDouble) { - ptr_GoogleAnalytics_Item_InsertDouble = (void (*)(GoogleAnalytics_Item* item, const char* key, double value))proc_GoogleAnalytics_Item_InsertDouble; - count++; - } - FARPROC proc_GoogleAnalytics_Item_InsertString = GetProcAddress(dll_handle, "GoogleAnalytics_Item_InsertString"); - if (proc_GoogleAnalytics_Item_InsertString) { - ptr_GoogleAnalytics_Item_InsertString = (void (*)(GoogleAnalytics_Item* item, const char* key, const char* value))proc_GoogleAnalytics_Item_InsertString; - count++; - } - FARPROC proc_GoogleAnalytics_Item_Destroy = GetProcAddress(dll_handle, "GoogleAnalytics_Item_Destroy"); - if (proc_GoogleAnalytics_Item_Destroy) { - ptr_GoogleAnalytics_Item_Destroy = (void (*)(GoogleAnalytics_Item* item))proc_GoogleAnalytics_Item_Destroy; - count++; - } - FARPROC proc_GoogleAnalytics_ItemVector_Create = GetProcAddress(dll_handle, "GoogleAnalytics_ItemVector_Create"); - if (proc_GoogleAnalytics_ItemVector_Create) { - ptr_GoogleAnalytics_ItemVector_Create = (GoogleAnalytics_ItemVector* (*)())proc_GoogleAnalytics_ItemVector_Create; - count++; - } - FARPROC proc_GoogleAnalytics_ItemVector_InsertItem = GetProcAddress(dll_handle, "GoogleAnalytics_ItemVector_InsertItem"); - if (proc_GoogleAnalytics_ItemVector_InsertItem) { - ptr_GoogleAnalytics_ItemVector_InsertItem = (void (*)(GoogleAnalytics_ItemVector* item_vector, GoogleAnalytics_Item* item))proc_GoogleAnalytics_ItemVector_InsertItem; - count++; - } - FARPROC proc_GoogleAnalytics_ItemVector_Destroy = GetProcAddress(dll_handle, "GoogleAnalytics_ItemVector_Destroy"); - if (proc_GoogleAnalytics_ItemVector_Destroy) { - ptr_GoogleAnalytics_ItemVector_Destroy = (void (*)(GoogleAnalytics_ItemVector* item_vector))proc_GoogleAnalytics_ItemVector_Destroy; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_Create = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_Create"); - if (proc_GoogleAnalytics_EventParameters_Create) { - ptr_GoogleAnalytics_EventParameters_Create = (GoogleAnalytics_EventParameters* (*)())proc_GoogleAnalytics_EventParameters_Create; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_InsertInt = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_InsertInt"); - if (proc_GoogleAnalytics_EventParameters_InsertInt) { - ptr_GoogleAnalytics_EventParameters_InsertInt = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, int64_t value))proc_GoogleAnalytics_EventParameters_InsertInt; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_InsertDouble = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_InsertDouble"); - if (proc_GoogleAnalytics_EventParameters_InsertDouble) { - ptr_GoogleAnalytics_EventParameters_InsertDouble = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, double value))proc_GoogleAnalytics_EventParameters_InsertDouble; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_InsertString = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_InsertString"); - if (proc_GoogleAnalytics_EventParameters_InsertString) { - ptr_GoogleAnalytics_EventParameters_InsertString = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, const char* value))proc_GoogleAnalytics_EventParameters_InsertString; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_InsertItemVector = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_InsertItemVector"); - if (proc_GoogleAnalytics_EventParameters_InsertItemVector) { - ptr_GoogleAnalytics_EventParameters_InsertItemVector = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, GoogleAnalytics_ItemVector* value))proc_GoogleAnalytics_EventParameters_InsertItemVector; - count++; - } - FARPROC proc_GoogleAnalytics_EventParameters_Destroy = GetProcAddress(dll_handle, "GoogleAnalytics_EventParameters_Destroy"); - if (proc_GoogleAnalytics_EventParameters_Destroy) { - ptr_GoogleAnalytics_EventParameters_Destroy = (void (*)(GoogleAnalytics_EventParameters* event_parameter_map))proc_GoogleAnalytics_EventParameters_Destroy; - count++; - } - FARPROC proc_GoogleAnalytics_LogEvent = GetProcAddress(dll_handle, "GoogleAnalytics_LogEvent"); - if (proc_GoogleAnalytics_LogEvent) { - ptr_GoogleAnalytics_LogEvent = (void (*)(const char* name, GoogleAnalytics_EventParameters* parameters))proc_GoogleAnalytics_LogEvent; - count++; - } - FARPROC proc_GoogleAnalytics_SetUserProperty = GetProcAddress(dll_handle, "GoogleAnalytics_SetUserProperty"); - if (proc_GoogleAnalytics_SetUserProperty) { - ptr_GoogleAnalytics_SetUserProperty = (void (*)(const char* name, const char* value))proc_GoogleAnalytics_SetUserProperty; - count++; - } - FARPROC proc_GoogleAnalytics_SetUserId = GetProcAddress(dll_handle, "GoogleAnalytics_SetUserId"); - if (proc_GoogleAnalytics_SetUserId) { - ptr_GoogleAnalytics_SetUserId = (void (*)(const char* user_id))proc_GoogleAnalytics_SetUserId; - count++; - } - FARPROC proc_GoogleAnalytics_ResetAnalyticsData = GetProcAddress(dll_handle, "GoogleAnalytics_ResetAnalyticsData"); - if (proc_GoogleAnalytics_ResetAnalyticsData) { - ptr_GoogleAnalytics_ResetAnalyticsData = (void (*)())proc_GoogleAnalytics_ResetAnalyticsData; - count++; - } - FARPROC proc_GoogleAnalytics_SetAnalyticsCollectionEnabled = GetProcAddress(dll_handle, "GoogleAnalytics_SetAnalyticsCollectionEnabled"); - if (proc_GoogleAnalytics_SetAnalyticsCollectionEnabled) { - ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled = (void (*)(bool enabled))proc_GoogleAnalytics_SetAnalyticsCollectionEnabled; - count++; - } - - return count; -} - -void FirebaseAnalytics_UnloadAnalyticsFunctions(void) { - ptr_GoogleAnalytics_Item_Create = &Stub_GoogleAnalytics_Item_Create; - ptr_GoogleAnalytics_Item_InsertInt = &Stub_GoogleAnalytics_Item_InsertInt; - ptr_GoogleAnalytics_Item_InsertDouble = &Stub_GoogleAnalytics_Item_InsertDouble; - ptr_GoogleAnalytics_Item_InsertString = &Stub_GoogleAnalytics_Item_InsertString; - ptr_GoogleAnalytics_Item_Destroy = &Stub_GoogleAnalytics_Item_Destroy; - ptr_GoogleAnalytics_ItemVector_Create = &Stub_GoogleAnalytics_ItemVector_Create; - ptr_GoogleAnalytics_ItemVector_InsertItem = &Stub_GoogleAnalytics_ItemVector_InsertItem; - ptr_GoogleAnalytics_ItemVector_Destroy = &Stub_GoogleAnalytics_ItemVector_Destroy; - ptr_GoogleAnalytics_EventParameters_Create = &Stub_GoogleAnalytics_EventParameters_Create; - ptr_GoogleAnalytics_EventParameters_InsertInt = &Stub_GoogleAnalytics_EventParameters_InsertInt; - ptr_GoogleAnalytics_EventParameters_InsertDouble = &Stub_GoogleAnalytics_EventParameters_InsertDouble; - ptr_GoogleAnalytics_EventParameters_InsertString = &Stub_GoogleAnalytics_EventParameters_InsertString; - ptr_GoogleAnalytics_EventParameters_InsertItemVector = &Stub_GoogleAnalytics_EventParameters_InsertItemVector; - ptr_GoogleAnalytics_EventParameters_Destroy = &Stub_GoogleAnalytics_EventParameters_Destroy; - ptr_GoogleAnalytics_LogEvent = &Stub_GoogleAnalytics_LogEvent; - ptr_GoogleAnalytics_SetUserProperty = &Stub_GoogleAnalytics_SetUserProperty; - ptr_GoogleAnalytics_SetUserId = &Stub_GoogleAnalytics_SetUserId; - ptr_GoogleAnalytics_ResetAnalyticsData = &Stub_GoogleAnalytics_ResetAnalyticsData; - ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled = &Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled; -} - -#endif // defined(_WIN32) -// clang-format on diff --git a/analytics/src/windows/analytics_dynamic.h b/analytics/src/windows/analytics_dynamic.h deleted file mode 100644 index a35784e980..0000000000 --- a/analytics/src/windows/analytics_dynamic.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2025 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. - -// Generated from analytics.h by generate_windows_stubs.py - -#ifndef FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DYNAMIC_H_ -#define FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DYNAMIC_H_ - -#include // needed for bool type in pure C - -// --- Copied from original header --- -#include - -/** - * @brief Opaque type for an item. - * - * This type is an opaque object that represents an item in an item vector. - * - * The caller is responsible for creating the item using the - * GoogleAnalytics_Item_Create() function, and destroying it using the - * GoogleAnalytics_Item_Destroy() function, unless it has been added to an - * item vector, in which case it will be destroyed at that time. - */ -typedef struct GoogleAnalytics_Item_Opaque GoogleAnalytics_Item; - -/** - * @brief Opaque type for an item vector. - * - * This type is an opaque object that represents a list of items. It is - * used to pass item vectors to the - * GoogleAnalytics_EventParameters_InsertItemVector() function. - * - * The caller is responsible for creating the item vector using the - * GoogleAnalytics_ItemVector_Create() function, and destroying it using the - * GoogleAnalytics_ItemVector_Destroy() function, unless it has been added - * to an event parameter map, in which case it will be destroyed at that time. - */ -typedef struct GoogleAnalytics_ItemVector_Opaque GoogleAnalytics_ItemVector; - -/** - * @brief Opaque type for an event parameter map. - * - * This type is an opaque object that represents a dictionary of event - * parameters. It is used to pass event parameters to the - * GoogleAnalytics_LogEvent() function. - * - * The caller is responsible for creating the event parameter map using the - * GoogleAnalytics_EventParameters_Create() function, and destroying it using - * the GoogleAnalytics_EventParameters_Destroy() function, unless it has been - * logged, in which case it will be destroyed automatically. - */ -typedef struct GoogleAnalytics_EventParameters_Opaque - GoogleAnalytics_EventParameters; - -// --- End of copied section --- - -#ifdef __cplusplus -extern "C" { -#endif - -// --- Function Pointer Declarations --- -// clang-format off -extern GoogleAnalytics_Item* (*ptr_GoogleAnalytics_Item_Create)(); -extern void (*ptr_GoogleAnalytics_Item_InsertInt)(GoogleAnalytics_Item* item, const char* key, int64_t value); -extern void (*ptr_GoogleAnalytics_Item_InsertDouble)(GoogleAnalytics_Item* item, const char* key, double value); -extern void (*ptr_GoogleAnalytics_Item_InsertString)(GoogleAnalytics_Item* item, const char* key, const char* value); -extern void (*ptr_GoogleAnalytics_Item_Destroy)(GoogleAnalytics_Item* item); -extern GoogleAnalytics_ItemVector* (*ptr_GoogleAnalytics_ItemVector_Create)(); -extern void (*ptr_GoogleAnalytics_ItemVector_InsertItem)(GoogleAnalytics_ItemVector* item_vector, GoogleAnalytics_Item* item); -extern void (*ptr_GoogleAnalytics_ItemVector_Destroy)(GoogleAnalytics_ItemVector* item_vector); -extern GoogleAnalytics_EventParameters* (*ptr_GoogleAnalytics_EventParameters_Create)(); -extern void (*ptr_GoogleAnalytics_EventParameters_InsertInt)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, int64_t value); -extern void (*ptr_GoogleAnalytics_EventParameters_InsertDouble)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, double value); -extern void (*ptr_GoogleAnalytics_EventParameters_InsertString)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, const char* value); -extern void (*ptr_GoogleAnalytics_EventParameters_InsertItemVector)(GoogleAnalytics_EventParameters* event_parameter_map, const char* key, GoogleAnalytics_ItemVector* value); -extern void (*ptr_GoogleAnalytics_EventParameters_Destroy)(GoogleAnalytics_EventParameters* event_parameter_map); -extern void (*ptr_GoogleAnalytics_LogEvent)(const char* name, GoogleAnalytics_EventParameters* 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)(); -extern void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled); - -#define GoogleAnalytics_Item_Create ptr_GoogleAnalytics_Item_Create -#define GoogleAnalytics_Item_InsertInt ptr_GoogleAnalytics_Item_InsertInt -#define GoogleAnalytics_Item_InsertDouble ptr_GoogleAnalytics_Item_InsertDouble -#define GoogleAnalytics_Item_InsertString ptr_GoogleAnalytics_Item_InsertString -#define GoogleAnalytics_Item_Destroy ptr_GoogleAnalytics_Item_Destroy -#define GoogleAnalytics_ItemVector_Create ptr_GoogleAnalytics_ItemVector_Create -#define GoogleAnalytics_ItemVector_InsertItem ptr_GoogleAnalytics_ItemVector_InsertItem -#define GoogleAnalytics_ItemVector_Destroy ptr_GoogleAnalytics_ItemVector_Destroy -#define GoogleAnalytics_EventParameters_Create ptr_GoogleAnalytics_EventParameters_Create -#define GoogleAnalytics_EventParameters_InsertInt ptr_GoogleAnalytics_EventParameters_InsertInt -#define GoogleAnalytics_EventParameters_InsertDouble ptr_GoogleAnalytics_EventParameters_InsertDouble -#define GoogleAnalytics_EventParameters_InsertString ptr_GoogleAnalytics_EventParameters_InsertString -#define GoogleAnalytics_EventParameters_InsertItemVector ptr_GoogleAnalytics_EventParameters_InsertItemVector -#define GoogleAnalytics_EventParameters_Destroy ptr_GoogleAnalytics_EventParameters_Destroy -#define GoogleAnalytics_LogEvent ptr_GoogleAnalytics_LogEvent -#define GoogleAnalytics_SetUserProperty ptr_GoogleAnalytics_SetUserProperty -#define GoogleAnalytics_SetUserId ptr_GoogleAnalytics_SetUserId -#define GoogleAnalytics_ResetAnalyticsData ptr_GoogleAnalytics_ResetAnalyticsData -#define GoogleAnalytics_SetAnalyticsCollectionEnabled ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled -// clang-format on - - -// --- Dynamic Loader Declaration for Windows --- -#if defined(_WIN32) -#include // For HMODULE -// Load Google Analytics functions from the given DLL handle into function pointers. -// Returns the number of functions successfully loaded (out of 19). -int FirebaseAnalytics_LoadAnalyticsFunctions(HMODULE dll_handle); - -// Reset all function pointers back to stubs. -void FirebaseAnalytics_UnloadAnalyticsFunctions(void); - -#endif // defined(_WIN32) - -#ifdef __cplusplus -} -#endif - -#endif // FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DYNAMIC_H_ diff --git a/analytics/tests/CMakeLists.txt b/analytics/tests/CMakeLists.txt index 51e72f2490..ac2e828254 100644 --- a/analytics/tests/CMakeLists.txt +++ b/analytics/tests/CMakeLists.txt @@ -13,7 +13,11 @@ # limitations under the License. - +if(WIN32) + set(ANALYTICS_TEST_PLATFORM_DEPS Crypt32.lib) +else() + set(ANALYTICS_TEST_PLATFORM_DEPS "") +endif() firebase_cpp_cc_test( firebase_analytics_test @@ -23,6 +27,7 @@ firebase_cpp_cc_test( firebase_app_for_testing firebase_analytics firebase_testing + ${ANALYTICS_TEST_PLATFORM_DEPS} ) firebase_cpp_cc_test_on_ios( diff --git a/analytics/windows/analytics_win.dll b/analytics/windows/analytics_win.dll index f0c83825e3..bc2725ffb7 100755 Binary files a/analytics/windows/analytics_win.dll and b/analytics/windows/analytics_win.dll differ diff --git a/analytics/windows/include/public/analytics.h b/analytics/windows/include/public/analytics.h index d2dcc448ae..1781e6e83d 100644 --- a/analytics/windows/include/public/analytics.h +++ b/analytics/windows/include/public/analytics.h @@ -1,4 +1,5 @@ // Copyright 2025 Google LLC + #ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_ANALYTICS_H_ #define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_ANALYTICS_H_ @@ -32,6 +33,38 @@ class Analytics { std::variant; using EventParameters = std::unordered_map; + /** + * @brief Options for initializing the Analytics SDK. + */ + struct Options { + /** + * @brief The unique identifier for the Firebase app across all of Firebase + * with a platform-specific format. This is a required field, can not be + * empty, and must be UTF-8 encoded. + * + * Example: 1:1234567890:android:321abc456def7890 + */ + std::string app_id; + + /** + * @brief Unique identifier for the application implementing the SDK. The + * format typically follows a reversed domain name convention. This is a + * required field, can not be empty, and must be UTF-8 encoded. + * + * Example: com.google.analytics.AnalyticsApp + */ + std::string package_name; + + /** + * @brief Whether Analytics is enabled at the very first launch. + * This value is then persisted across app sessions, and from then on, takes + * precedence over the value of this field. + * SetAnalyticsCollectionEnabled() can be used to enable/disable after that + * point. + */ + bool analytics_collection_enabled_at_first_launch = true; + }; + /** * @brief Returns the singleton instance of the Analytics class. */ @@ -46,6 +79,26 @@ class Analytics { Analytics(Analytics&&) = delete; Analytics& operator=(Analytics&&) = delete; + /** + * @brief Initializes the Analytics SDK with the given options. Until this is + * called, all analytics methods below will be no-ops. + * + * @param[in] options The options to initialize the Analytics SDK with. + * + * @return true if the Analytics SDK was successfully initialized, false + * otherwise. Also returns false if the Analytics SDK has already been + * initialized. + */ + bool Initialize(const Options& options) { + GoogleAnalytics_Options* google_analytics_options = + GoogleAnalytics_Options_Create(); + google_analytics_options->app_id = options.app_id.c_str(); + google_analytics_options->package_name = options.package_name.c_str(); + google_analytics_options->analytics_collection_enabled_at_first_launch = + options.analytics_collection_enabled_at_first_launch; + return GoogleAnalytics_Initialize(google_analytics_options); + } + /** * @brief Logs an app event. * diff --git a/analytics/windows/include/public/c/analytics.h b/analytics/windows/include/public/c/analytics.h index cb3047f310..dc6ddd3ceb 100644 --- a/analytics/windows/include/public/c/analytics.h +++ b/analytics/windows/include/public/c/analytics.h @@ -1,7 +1,9 @@ // Copyright 2025 Google LLC + #ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_C_ANALYTICS_H_ #define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_C_ANALYTICS_H_ +#include #include #if defined(ANALYTICS_DLL) && defined(_WIN32) @@ -14,6 +16,78 @@ extern "C" { #endif +typedef struct GoogleAnalytics_Reserved_Opaque GoogleAnalytics_Reserved; + +/** + * @brief GoogleAnalytics_Options for initializing the Analytics SDK. + * GoogleAnalytics_Options_Create() must be used to create an instance of this + * struct with default values. If these options are created manually instead of + * using GoogleAnalytics_Options_Create(), initialization will fail, and the + * caller will be responsible for destroying the options. + */ +ANALYTICS_API typedef struct { + /** + * @brief The unique identifier for the Firebase app across all of Firebase + * with a platform-specific format. This is a required field, can not be null + * or empty, and must be UTF-8 encoded. + * + * The caller is responsible for allocating this memory, and deallocating it + * once the options instance has been destroyed. + * + * Example: 1:1234567890:android:321abc456def7890 + */ + const char* app_id; + + /** + * @brief Unique identifier for the application implementing the SDK. The + * format typically follows a reversed domain name convention. This is a + * required field, can not be null or empty, and must be UTF-8 encoded. + * + * The caller is responsible for allocating this memory, and deallocating it + * once the options instance has been destroyed. + * + * Example: com.google.analytics.AnalyticsApp + */ + const char* package_name; + + /** + * @brief Whether Analytics is enabled at the very first launch. + * This value is then persisted across app sessions, and from then on, takes + * precedence over the value of this field. + * GoogleAnalytics_SetAnalyticsCollectionEnabled() can be used to + * enable/disable after that point. + */ + bool analytics_collection_enabled_at_first_launch; + + /** + * @brief Reserved for internal use by the SDK. + */ + GoogleAnalytics_Reserved* reserved; +} GoogleAnalytics_Options; + +/** + * @brief Creates an instance of GoogleAnalytics_Options with default values. + * + * The caller is responsible for destroying the options using the + * GoogleAnalytics_Options_Destroy() function, unless it has been passed to the + * GoogleAnalytics_Initialize() function, in which case it will be destroyed + * automatically. + * + * @return A pointer to a newly allocated GoogleAnalytics_Options instance. + */ +ANALYTICS_API GoogleAnalytics_Options* GoogleAnalytics_Options_Create(); + +/** + * @brief Destroys the GoogleAnalytics_Options instance. Must not be called if + * the options were created with GoogleAnalytics_Options_Create() and passed to + * the GoogleAnalytics_Initialize() function, which would destroy them + * automatically. + * + * @param[in] options The GoogleAnalytics_Options instance to destroy. + */ +ANALYTICS_API void GoogleAnalytics_Options_Destroy( + GoogleAnalytics_Options* options); + /** * @brief Opaque type for an item. * @@ -210,6 +284,20 @@ ANALYTICS_API void GoogleAnalytics_EventParameters_InsertItemVector( ANALYTICS_API void GoogleAnalytics_EventParameters_Destroy( GoogleAnalytics_EventParameters* event_parameter_map); +/** + * @brief Initializes the Analytics SDK. Until this is called, all analytics + * functions below will be no-ops. + * + * @param[in] options The options for initializing the Analytics + * SDK. Deleted regardless of return value, if it was allocated with the + * GoogleAnalytics_Options_Create() function. + * @return true if the Analytics SDK was successfully initialized, false + * otherwise. Also returns false if the Analytics SDK has already been + * initialized. + */ +ANALYTICS_API bool GoogleAnalytics_Initialize( + const GoogleAnalytics_Options* options); + /** * @brief Logs an app event. * @@ -296,7 +384,7 @@ ANALYTICS_API void GoogleAnalytics_LogEvent( ANALYTICS_API void GoogleAnalytics_SetUserProperty(const char* name, const char* value); -/* +/** * @brief Sets the user ID property. * * This feature must be used in accordance with @@ -309,13 +397,13 @@ ANALYTICS_API void GoogleAnalytics_SetUserProperty(const char* name, */ ANALYTICS_API void GoogleAnalytics_SetUserId(const char* user_id); -/* +/** * @brief Clears all analytics data for this instance from the device and resets * the app instance ID. */ ANALYTICS_API void GoogleAnalytics_ResetAnalyticsData(); -/* +/** * @brief Sets whether analytics collection is enabled for this app on this * device. * diff --git a/analytics/windows/include/public/event_names.h b/analytics/windows/include/public/event_names.h index ef8330751f..3a3566070e 100644 --- a/analytics/windows/include/public/event_names.h +++ b/analytics/windows/include/public/event_names.h @@ -1,4 +1,5 @@ // Copyright 2025 Google LLC + #ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_EVENT_NAMES_H_ #define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_EVENT_NAMES_H_ @@ -14,7 +15,7 @@ // alphabetic character. The "firebase_", "google_", and "ga_" prefixes are // reserved and should not be used. -namespace firebase::analytics { +namespace google::analytics { // Ad Impression event. This event signifies when a user sees an ad impression. // Note: If you supply the @c kParameterValue parameter, you must also supply @@ -421,6 +422,6 @@ inline constexpr char kEventViewPromotion[] = "view_promotion"; // inline constexpr char kEventViewSearchResults[] = "view_search_results"; -} // namespace firebase::analytics +} // namespace google::analytics #endif // ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_EVENT_NAMES_H_ diff --git a/analytics/windows/include/public/parameter_names.h b/analytics/windows/include/public/parameter_names.h index 7c5f45695e..c0181beea9 100644 --- a/analytics/windows/include/public/parameter_names.h +++ b/analytics/windows/include/public/parameter_names.h @@ -1,8 +1,9 @@ // Copyright 2025 Google LLC + #ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_PARAMETER_NAMES_H_ #define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_PARAMETER_NAMES_H_ -namespace firebase::analytics { +namespace google::analytics { // Game achievement ID (string). inline constexpr char kParameterAchievementId[] = "achievement_id"; @@ -248,6 +249,6 @@ inline constexpr char kParameterValue[] = "value"; // The type of virtual currency being used (string). inline constexpr char kParameterVirtualCurrencyName[] = "virtual_currency_name"; -} // namespace firebase::analytics +} // namespace google::analytics #endif // ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_PARAMETER_NAMES_H_ diff --git a/analytics/windows/known_dll_hashes.txt b/analytics/windows/known_dll_hashes.txt new file mode 100644 index 0000000000..ecfa9d04ad --- /dev/null +++ b/analytics/windows/known_dll_hashes.txt @@ -0,0 +1,2 @@ +c1b9ff6e9119c30bbeb7472326dcde418f45682e6b822e25eed922fe6e3cc698 +13ae5f9349b24186f1f3667b52832076e8d14ad9656c3546b1b7fca79ac8144b