Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions analytics/integration_test/src/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,29 @@ TEST_F(FirebaseAnalyticsTest, TestSetLogCallback) {
}
#endif // defined(_WIN32)

TEST_F(FirebaseAnalyticsTest, TestDesktopInitialization) {
// The analytics dll does not work on 32 bit systems.
SKIP_TEST_ON_WINDOWS_32BIT;

// Check to see if the desktop DLL is loaded.
bool initialized = firebase::analytics::IsDesktopInitialized();

#if defined(_WIN32)
// On Windows, it should be true.
EXPECT_TRUE(initialized);
#else
// On other platforms, it should return false.
EXPECT_FALSE(initialized);
#endif
}

TEST_F(FirebaseAnalyticsTest, TestDesktopDebugMode) {
// SetDebugMode doesn't return anything, so we just call it to ensure
// it doesn't crash.
firebase::analytics::SetDesktopDebugMode(true);
firebase::analytics::SetDesktopDebugMode(false);
}

TEST_F(FirebaseAnalyticsTest, TestLogEvents) {
// Log an event with no parameters.
firebase::analytics::LogEvent(firebase::analytics::kEventLogin);
Expand Down
6 changes: 6 additions & 0 deletions analytics/src/analytics_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,12 @@ void SetLogCallback(const LogCallback&) {}
// NO-OP in Android and iOS. Only used in Windows.
void NotifyAppLifecycleChange(AppLifecycleState) {}

// NO-OP in Android and iOS. Only used in Windows.
bool IsDesktopInitialized() { return false; }

// NO-OP in Android and iOS. Only used in Windows.
void SetDesktopDebugMode(bool enabled) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to remove the "enabled" part, just so anything that warns about unused parameters doesn't complain. Also in the other stub implementations


Future<std::string> GetAnalyticsInstanceId() {
FIREBASE_ASSERT_RETURN(GetAnalyticsInstanceIdLastResult(),
internal::IsInitialized());
Expand Down
12 changes: 12 additions & 0 deletions analytics/src/analytics_desktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,18 @@ void NotifyAppLifecycleChange(AppLifecycleState state) {
static_cast<GoogleAnalytics_AppLifecycleState>(state));
}

// Returns true if the desktop Analytics dll is initialized.
bool IsDesktopInitialized() {
FIREBASE_ASSERT_RETURN(false, internal::IsInitialized());
return GoogleAnalytics_IsInitialized();
}

// Sends the enabled Flag to the desktop Analytics dll.
void SetDesktopDebugMode(bool enabled) {
FIREBASE_ASSERT_RETURN_VOID(internal::IsInitialized());
GoogleAnalytics_SetDebugMode(enabled);
}

// Overloaded versions of LogEvent for convenience.

void LogEvent(const char* name) {
Expand Down
32 changes: 28 additions & 4 deletions analytics/src/analytics_desktop_dynamic.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@ 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 = 24;
const int FirebaseAnalytics_DynamicFunctionCount = 26;

#if defined(_WIN32)
// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings).
const char* FirebaseAnalytics_KnownWindowsDllHashes[] = {
"c1b9ff6e9119c30bbeb7472326dcde418f45682e6b822e25eed922fe6e3cc698",
"13ae5f9349b24186f1f3667b52832076e8d14ad9656c3546b1b7fca79ac8144b",
"3f1fb1bb21bce0061c4b89bb674d3b6c94eaea2c8de98802198a35ea94c97900"
"3f1fb1bb21bce0061c4b89bb674d3b6c94eaea2c8de98802198a35ea94c97900",
"1e944cd4a2b8d115a32d01f4cc900f23805934b5587b55305df9cd189f9d78d5"
};

// Count of known Google Analytics Windows DLL SHA256 hashes.
const int FirebaseAnalytics_KnownWindowsDllHashCount = 3;
const int FirebaseAnalytics_KnownWindowsDllHashCount = 4;
#endif // defined(_WIN32)

// --- Stub Function Definitions ---
Expand Down Expand Up @@ -175,6 +176,16 @@ static void Stub_GoogleAnalytics_NotifyAppLifecycleChange(GoogleAnalytics_AppLif
// No return value.
}

// Stub for GoogleAnalytics_IsInitialized
static bool Stub_GoogleAnalytics_IsInitialized() {
return 0;
}

// Stub for GoogleAnalytics_SetDebugMode
static void Stub_GoogleAnalytics_SetDebugMode(bool enabled) {
// No return value.
}


// --- Function Pointer Initializations ---
GoogleAnalytics_Options* (*ptr_GoogleAnalytics_Options_Create)() = &Stub_GoogleAnalytics_Options_Create;
Expand Down Expand Up @@ -202,7 +213,8 @@ void (*ptr_GoogleAnalytics_ResetAnalyticsData)() = &Stub_GoogleAnalytics_ResetAn
void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled) = &Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled;
void (*ptr_GoogleAnalytics_SetLogCallback)(GoogleAnalytics_LogCallback callback) = &Stub_GoogleAnalytics_SetLogCallback;
void (*ptr_GoogleAnalytics_NotifyAppLifecycleChange)(GoogleAnalytics_AppLifecycleState state) = &Stub_GoogleAnalytics_NotifyAppLifecycleChange;

bool (*ptr_GoogleAnalytics_IsInitialized)() = &Stub_GoogleAnalytics_IsInitialized;
void (*ptr_GoogleAnalytics_SetDebugMode)(bool enabled) = &Stub_GoogleAnalytics_SetDebugMode;
// --- Dynamic Loader Function for Windows ---
#if defined(_WIN32)
int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) {
Expand Down Expand Up @@ -333,6 +345,16 @@ int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) {
count++;
}

FARPROC proc_GoogleAnalytics_IsInitialized = GetProcAddress(dll_handle, "GoogleAnalytics_IsInitialized");
if (proc_GoogleAnalytics_IsInitialized) {
ptr_GoogleAnalytics_IsInitialized = (bool (*)())proc_GoogleAnalytics_IsInitialized;
count++;
}
FARPROC proc_GoogleAnalytics_SetDebugMode = GetProcAddress(dll_handle, "GoogleAnalytics_SetDebugMode");
if (proc_GoogleAnalytics_SetDebugMode) {
ptr_GoogleAnalytics_SetDebugMode = (void (*)(bool enabled))proc_GoogleAnalytics_SetDebugMode;
count++;
}
return count;
}

Expand Down Expand Up @@ -361,6 +383,8 @@ void FirebaseAnalytics_UnloadDynamicFunctions(void) {
ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled = &Stub_GoogleAnalytics_SetAnalyticsCollectionEnabled;
ptr_GoogleAnalytics_SetLogCallback = &Stub_GoogleAnalytics_SetLogCallback;
ptr_GoogleAnalytics_NotifyAppLifecycleChange = &Stub_GoogleAnalytics_NotifyAppLifecycleChange;
ptr_GoogleAnalytics_IsInitialized = &Stub_GoogleAnalytics_IsInitialized;
ptr_GoogleAnalytics_SetDebugMode = &Stub_GoogleAnalytics_SetDebugMode;
}

#endif // defined(_WIN32)
Expand Down
4 changes: 4 additions & 0 deletions analytics/src/analytics_desktop_dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ extern void (*ptr_GoogleAnalytics_ResetAnalyticsData)();
extern void (*ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled)(bool enabled);
extern void (*ptr_GoogleAnalytics_SetLogCallback)(GoogleAnalytics_LogCallback callback);
extern void (*ptr_GoogleAnalytics_NotifyAppLifecycleChange)(GoogleAnalytics_AppLifecycleState state);
extern bool (*ptr_GoogleAnalytics_IsInitialized)();
extern void (*ptr_GoogleAnalytics_SetDebugMode)(bool enabled);

#define GoogleAnalytics_Options_Create ptr_GoogleAnalytics_Options_Create
#define GoogleAnalytics_Options_Destroy ptr_GoogleAnalytics_Options_Destroy
Expand All @@ -238,6 +240,8 @@ extern void (*ptr_GoogleAnalytics_NotifyAppLifecycleChange)(GoogleAnalytics_AppL
#define GoogleAnalytics_SetAnalyticsCollectionEnabled ptr_GoogleAnalytics_SetAnalyticsCollectionEnabled
#define GoogleAnalytics_SetLogCallback ptr_GoogleAnalytics_SetLogCallback
#define GoogleAnalytics_NotifyAppLifecycleChange ptr_GoogleAnalytics_NotifyAppLifecycleChange
#define GoogleAnalytics_IsInitialized ptr_GoogleAnalytics_IsInitialized
#define GoogleAnalytics_SetDebugMode ptr_GoogleAnalytics_SetDebugMode
// clang-format on

// Number of Google Analytics functions expected to be loaded from the DLL.
Expand Down
6 changes: 6 additions & 0 deletions analytics/src/analytics_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,12 @@ void SetLogCallback(const LogCallback&) {}
// No-Op on iOS and Android. Only used in Windows desktop apps.
void NotifyAppLifecycleChange(AppLifecycleState) {}

// NO-OP in Android and iOS. Only used in Windows.
bool IsDesktopInitialized() { return false; }

// NO-OP in Android and iOS. Only used in Windows.
void SetDesktopDebugMode(bool enabled) {}

Future<std::string> GetAnalyticsInstanceId() {
MutexLock lock(g_mutex);
FIREBASE_ASSERT_RETURN(Future<std::string>(), internal::IsInitialized());
Expand Down
16 changes: 15 additions & 1 deletion analytics/src/include/firebase/analytics.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ enum AppLifecycleState { kUnknown = 0, kTermination };
///
/// This method is used to notify the Analytics SDK about the current state of
/// the app's lifecycle. The Analytics SDK will use this information to log
/// events, update user properties, upload data, etc. The method only work on
/// events, update user properties, upload data, etc. The method only works on
/// windows and is a NO-OP on iOS and Android.
///
/// kTermination is used to indicate that the app is about to be terminated.
Expand All @@ -645,6 +645,20 @@ enum AppLifecycleState { kUnknown = 0, kTermination };
/// @param[in] state The current state of the app's lifecycle.
void NotifyAppLifecycleChange(AppLifecycleState state);

/// @brief Returns whether the desktop Analytics SDK is initialized.
///
/// Returns true if the Analytics SDK is initialized, false otherwise. The
/// method only works on windows and is a NO-OP on iOS and Android.
bool IsDesktopInitialized();

/// @brief Sets whether desktop debug mode is enabled.
///
/// This methods enables desktop debug mode for the analytics SDK. The
/// method only works on windows and is a NO-OP on iOS and Android.
///
/// @param[in] enabled A flag that enables or disables debug mode.
void SetDesktopDebugMode(bool enabled);

/// Get the instance ID from the analytics service.
///
/// @note This is *not* the same ID as the ID returned by
Expand Down
Binary file modified analytics/windows/google_analytics.dll
Binary file not shown.
84 changes: 60 additions & 24 deletions analytics/windows/include/public/analytics.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
// 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.
/*
* 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.
*/

#ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_ANALYTICS_H_
#define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_ANALYTICS_H_
#ifndef ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PRERELEASE_ANALYTICS_H_
#define ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PRERELEASE_ANALYTICS_H_

#include <cstdint>
#include <functional>
Expand Down Expand Up @@ -60,6 +62,15 @@ class Analytics {
* @brief The app is about to be terminated.
*/
kTermination,
/**
* @brief The application has user focus (e.g., is in the foreground).
*/
kFocused,
/**
* @brief The application does not have user focus (e.g., is in the
* background).
*/
kUnfocused,
};

/**
Expand Down Expand Up @@ -155,13 +166,26 @@ class Analytics {
google_analytics_options->analytics_collection_enabled_at_first_launch =
options.analytics_collection_enabled_at_first_launch;
google_analytics_options->app_data_directory =
(options.app_data_directory.has_value() &&
!options.app_data_directory->empty())
? options.app_data_directory->c_str()
: nullptr;
options.app_data_directory.value_or("").empty()
? nullptr
: options.app_data_directory.value().c_str();
return GoogleAnalytics_Initialize(google_analytics_options);
}

/**
* @brief Returns whether the Analytics SDK is initialized.
*
* @return true if the Analytics SDK is initialized, false otherwise.
*/
bool IsInitialized() { return GoogleAnalytics_IsInitialized(); }

/**
* @brief Sets whether debug mode is enabled.
*
* @param[in] enabled A flag that enables or disables debug mode.
*/
void SetDebugMode(bool enabled) { GoogleAnalytics_SetDebugMode(enabled); }

/**
* @brief Logs an app event.
*
Expand Down Expand Up @@ -353,16 +377,16 @@ class Analytics {
[](GoogleAnalytics_LogLevel log_level, const char* message) {
LogLevel cpp_log_level;
switch (log_level) {
case GoogleAnalytics_LogLevel::kDebug:
case GoogleAnalytics_LogLevel_kDebug:
cpp_log_level = LogLevel::kDebug;
break;
case GoogleAnalytics_LogLevel::kInfo:
case GoogleAnalytics_LogLevel_kInfo:
cpp_log_level = LogLevel::kInfo;
break;
case GoogleAnalytics_LogLevel::kWarning:
case GoogleAnalytics_LogLevel_kWarning:
cpp_log_level = LogLevel::kWarning;
break;
case GoogleAnalytics_LogLevel::kError:
case GoogleAnalytics_LogLevel_kError:
cpp_log_level = LogLevel::kError;
break;
default:
Expand Down Expand Up @@ -392,11 +416,23 @@ class Analytics {
* occurs. The caller must ensure the OS does not terminate background threads
* before the call returns.
*
* kFocused is used to indicate that the app has user focus (e.g., is in the
* foreground).
*
* kUnfocused is used to indicate that the app does not have user focus (e.g.,
* is in the background).
*
* @param[in] state The current state of the app's lifecycle.
*/
void NotifyAppLifecycleChange(AppLifecycleState state) {
GoogleAnalytics_AppLifecycleState c_state;
switch (state) {
case AppLifecycleState::kFocused:
c_state = GoogleAnalytics_AppLifecycleState_kFocused;
break;
case AppLifecycleState::kUnfocused:
c_state = GoogleAnalytics_AppLifecycleState_kUnfocused;
break;
case AppLifecycleState::kTermination:
c_state = GoogleAnalytics_AppLifecycleState_kTermination;
break;
Expand All @@ -417,4 +453,4 @@ class Analytics {

} // namespace google::analytics

#endif // ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PUBLIC_ANALYTICS_H_
#endif // ANALYTICS_MOBILE_CONSOLE_MEASUREMENT_PRERELEASE_ANALYTICS_H_
Loading
Loading