12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- #include " analytics/src/windows/analytics_windows .h"
15
+ #include " analytics/src/windows/analytics_dynamic .h"
16
16
#include " app/src/include/firebase/app.h"
17
17
#include " analytics/src/include/firebase/analytics.h"
18
- #include " analytics/src/common/ analytics_common.h"
19
- #include " common /src/include/firebase/variant.h"
18
+ #include " analytics/src/analytics_common.h"
19
+ #include " app /src/include/firebase/variant.h"
20
20
#include " app/src/include/firebase/future.h"
21
21
#include " app/src/include/firebase/log.h"
22
22
#include " app/src/future_manager.h" // For FutureData
23
23
24
24
#include < vector>
25
25
#include < string>
26
26
#include < map>
27
+ #include < sstream>
28
+
29
+ #if defined(_WIN32)
30
+ #include < windows.h>
31
+ #endif // defined(_WIN32)
27
32
28
33
namespace firebase {
29
34
namespace analytics {
30
35
36
+ #if defined(_WIN32)
37
+ #define ANALYTICS_DLL_DEFAULT_FILENAME " analytics_win.dll"
38
+ const char *g_analytics_dll_filename = nullptr ;
39
+ static HMODULE g_analytics_dll = 0 ;
40
+
41
+ void SetAnalyticsLibraryPath (const char * path) {
42
+ if (g_analytics_dll_filename) {
43
+ delete g_analytics_dll_filename;
44
+ g_analytics_dll_filename = nullptr ;
45
+ }
46
+ if (path) {
47
+ g_analytics_dll_filename = new char [strlen (path)+1 ];
48
+ strcpy (g_analytics_dll_filename, path);
49
+ }
50
+ }
51
+ #endif
52
+
31
53
// Future data for analytics.
32
54
// This is initialized in `Initialize()` and cleaned up in `Terminate()`.
33
- static FutureData* g_future_data = nullptr ;
55
+ static bool g_initialized = false ;
56
+ static int g_fake_instance_id = 0 ;
34
57
35
58
// Initializes the Analytics desktop API.
36
59
// This function must be called before any other Analytics methods.
@@ -40,22 +63,48 @@ void Initialize(const App& app) {
40
63
// with other Firebase platforms.
41
64
(void )app;
42
65
43
- if (g_future_data) {
44
- LogWarning (" Analytics: Initialize() called when already initialized." );
45
- } else {
46
- g_future_data = new FutureData (internal::kAnalyticsFnCount );
66
+ g_initialized = true ;
67
+ internal::RegisterTerminateOnDefaultAppDestroy ();
68
+ internal::FutureData::Create ();
69
+ g_fake_instance_id = 0 ;
70
+
71
+ #if defined(_WIN32)
72
+ if (!g_analytics_dll) {
73
+ const char * dll_filename = g_analytics_dll_filename;
74
+ if (!dll_filename) dll_filename = ANALYTICS_DLL_DEFAULT_FILENAME;
75
+ auto wFilename = toUtf16 (dll_filename);
76
+ g_analytics_dll = LoadLibraryW (wFilename);
77
+ if (g_analytics_dll) {
78
+ LogInfo (" Successfully loaded Analytics DLL %s" , g_analytics_dll_filename);
79
+ } else {
80
+ LogError (" Failed to load Analytics DLL %s" , g_analytics_dll_filename);
81
+ }
47
82
}
83
+ FirebaseAnalytics_LoadAnalyticsFunctions (g_analytics_dll);
84
+ #endif
48
85
}
49
86
87
+ namespace internal {
88
+
89
+ // Determine whether the analytics module is initialized.
90
+ bool IsInitialized () { return g_initialized; }
91
+
92
+ } // namespace internal
93
+
50
94
// Terminates the Analytics desktop API.
51
95
// Call this function when Analytics is no longer needed to free up resources.
52
96
void Terminate () {
53
- if (g_future_data) {
54
- delete g_future_data ;
55
- g_future_data = nullptr ;
56
- } else {
57
- LogWarning ( " Analytics: Terminate() called when not initialized or already terminated. " ) ;
97
+ # if defined(_WIN32)
98
+ FirebaseAnalytics_UnloadAnalyticsFunctions () ;
99
+ if (g_analytics_dll) {
100
+ FreeLibrary (g_analytics_dll);
101
+ g_analytics_dll = 0 ;
58
102
}
103
+ #endif
104
+
105
+ internal::FutureData::Destroy ();
106
+ internal::UnregisterTerminateOnDefaultAppDestroy ();
107
+ g_initialized = false ;
59
108
}
60
109
61
110
static void ConvertParametersToGAParams (
@@ -95,8 +144,8 @@ static void ConvertParametersToGAParams(
95
144
// is set as the property's value.
96
145
// All these GoogleAnalytics_Items are then bundled into a single
97
146
// GoogleAnalytics_ItemVector, which is associated with the original parameter's name.
98
- const std::map<std::string , firebase::Variant>& user_map =
99
- param.value .map_value ();
147
+ const std::map<firebase::Variant , firebase::Variant>& user_map =
148
+ param.value .map ();
100
149
if (user_map.empty ()) {
101
150
LogWarning (" Analytics: Parameter '%s' is an empty map. Skipping." , param.name );
102
151
continue ; // Skip this parameter
@@ -111,7 +160,12 @@ static void ConvertParametersToGAParams(
111
160
112
161
bool item_vector_populated = false ;
113
162
for (const auto & entry : user_map) {
114
- const std::string& key_from_map = entry.first ;
163
+ const firebase::Variant& key_variant = entry.first ;
164
+ if (!key_variant.is_string ()) {
165
+ LogError (" Analytics: Non-string map key found. Skipping." );
166
+ continue ;
167
+ }
168
+ const std::string& key_from_map = key_variant.mutable_string ();
115
169
const firebase::Variant& value_from_map = entry.second ;
116
170
117
171
GoogleAnalytics_Item* c_item = GoogleAnalytics_Item_Create ();
@@ -164,6 +218,8 @@ static void ConvertParametersToGAParams(
164
218
void LogEvent (const char * name,
165
219
const Parameter* parameters,
166
220
size_t number_of_parameters) {
221
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
222
+
167
223
if (name == nullptr || name[0 ] == ' \0 ' ) {
168
224
LogError (" Analytics: Event name cannot be null or empty." );
169
225
return ;
@@ -196,6 +252,8 @@ void LogEvent(const char* name,
196
252
// characters long. Setting the value to `nullptr` or an empty string will
197
253
// clear the user property. Must be UTF-8 encoded if not nullptr.
198
254
void SetUserProperty (const char * name, const char * property) {
255
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
256
+
199
257
if (name == nullptr || name[0 ] == ' \0 ' ) {
200
258
LogError (" Analytics: User property name cannot be null or empty." );
201
259
return ;
@@ -216,6 +274,7 @@ void SetUserProperty(const char* name, const char* property) {
216
274
// characters long, and UTF-8 encoded. Setting user_id to `nullptr` removes
217
275
// the user ID.
218
276
void SetUserId (const char * user_id) {
277
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
219
278
// The C API GoogleAnalytics_SetUserId allows user_id to be nullptr to clear the user ID.
220
279
// The C API documentation also mentions: "The user ID must be non-empty and
221
280
// no more than 256 characters long".
@@ -235,18 +294,24 @@ void SetUserId(const char* user_id) {
235
294
//
236
295
// @param[in] enabled A flag that enables or disables Analytics collection.
237
296
void SetAnalyticsCollectionEnabled (bool enabled) {
297
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
298
+
238
299
GoogleAnalytics_SetAnalyticsCollectionEnabled (enabled);
239
300
}
240
301
241
302
// Clears all analytics data for this app from the device and resets the app
242
303
// instance ID.
243
304
void ResetAnalyticsData () {
305
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
306
+
244
307
GoogleAnalytics_ResetAnalyticsData ();
245
308
}
246
309
247
310
// --- Stub Implementations for Unsupported Features ---
248
311
249
312
void SetConsent (const std::map<ConsentType, ConsentStatus>& consent_settings) {
313
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
314
+
250
315
// Not supported by the Windows C API.
251
316
(void )consent_settings; // Mark as unused
252
317
LogWarning (" Analytics: SetConsent() is not supported and has no effect on Desktop." );
@@ -298,75 +363,79 @@ void LogEvent(const char* name, const char* parameter_name,
298
363
299
364
void InitiateOnDeviceConversionMeasurementWithEmailAddress (
300
365
const char * email_address) {
366
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
301
367
(void )email_address;
302
368
LogWarning (" Analytics: InitiateOnDeviceConversionMeasurementWithEmailAddress() is not supported and has no effect on Desktop." );
303
369
}
304
370
305
371
void InitiateOnDeviceConversionMeasurementWithPhoneNumber (
306
372
const char * phone_number) {
373
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
307
374
(void )phone_number;
308
375
LogWarning (" Analytics: InitiateOnDeviceConversionMeasurementWithPhoneNumber() is not supported and has no effect on Desktop." );
309
376
}
310
377
311
378
void InitiateOnDeviceConversionMeasurementWithHashedEmailAddress (
312
379
std::vector<unsigned char > hashed_email_address) {
380
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
313
381
(void )hashed_email_address;
314
382
LogWarning (" Analytics: InitiateOnDeviceConversionMeasurementWithHashedEmailAddress() is not supported and has no effect on Desktop." );
315
383
}
316
384
317
385
void InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber (
318
386
std::vector<unsigned char > hashed_phone_number) {
387
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
319
388
(void )hashed_phone_number;
320
389
LogWarning (" Analytics: InitiateOnDeviceConversionMeasurementWithHashedPhoneNumber() is not supported and has no effect on Desktop." );
321
390
}
322
391
323
392
void SetSessionTimeoutDuration (int64_t milliseconds) {
393
+ FIREBASE_ASSERT_RETURN_VOID (internal::IsInitialized ());
324
394
(void )milliseconds;
325
395
LogWarning (" Analytics: SetSessionTimeoutDuration() is not supported and has no effect on Desktop." );
326
396
}
327
397
328
398
Future<std::string> GetAnalyticsInstanceId () {
329
- LogWarning (" Analytics: GetAnalyticsInstanceId() is not supported on Desktop." );
330
- if (!g_future_data) {
331
- LogError (" Analytics: API not initialized; call Initialize() first." );
332
- static firebase::Future<std::string> invalid_future; // Default invalid
333
- if (!g_future_data) return invalid_future; // Or some other error future
399
+ FIREBASE_ASSERT_RETURN (Future<std::string>(), internal::IsInitialized ());
400
+ auto * api = internal::FutureData::Get ()->api ();
401
+ const auto future_handle =
402
+ api->SafeAlloc <std::string>(internal::kAnalyticsFnGetAnalyticsInstanceId );
403
+ std::string instance_id = std::string (" FakeAnalyticsInstanceId" );
404
+ {
405
+ std::stringstream ss;
406
+ ss << g_fake_instance_id;
407
+ instance_id += ss.str ();
334
408
}
335
- const auto handle =
336
- g_future_data->CreateFuture (internal::kAnalyticsFn_GetAnalyticsInstanceId , nullptr );
337
- g_future_data->CompleteFuture (handle, 0 /* error_code */ , nullptr /* error_message_string */ );
338
- return g_future_data->GetFuture <std::string>(handle);
409
+ api->CompleteWithResult (future_handle, 0 , " " , instance_id);
410
+ LogWarning (" Analytics: GetAnalyticsInstanceId() is not supported on Desktop." );
411
+ return Future<std::string>(api, future_handle.get ());
339
412
}
340
413
341
414
Future<std::string> GetAnalyticsInstanceIdLastResult () {
342
- if (!g_future_data) {
343
- LogError (" Analytics: API not initialized; call Initialize() first." );
344
- static firebase::Future<std::string> invalid_future;
345
- return invalid_future;
346
- }
347
- return g_future_data->LastResult <std::string>(internal::kAnalyticsFn_GetAnalyticsInstanceId );
415
+ FIREBASE_ASSERT_RETURN (Future<std::string>(), internal::IsInitialized ());
416
+ LogWarning (" Analytics: GetAnalyticsInstanceIdLastResult() is not supported on Desktop." );
417
+ return static_cast <const Future<std::string>&>(
418
+ internal::FutureData::Get ()->api ()->LastResult (
419
+ internal::kAnalyticsFnGetAnalyticsInstanceId ));
348
420
}
349
421
350
422
Future<int64_t > GetSessionId () {
423
+ FIREBASE_ASSERT_RETURN (Future<int64_t >(), internal::IsInitialized ());
424
+ auto * api = internal::FutureData::Get ()->api ();
425
+ const auto future_handle =
426
+ api->SafeAlloc <int64_t >(internal::kAnalyticsFnGetSessionId );
427
+ int64_t session_id = 0x5E5510171D570BL ; // "SESSIONIDSTUB", kinda
428
+ api->CompleteWithResult (future_handle, 0 , " " , session_id);
351
429
LogWarning (" Analytics: GetSessionId() is not supported on Desktop." );
352
- if (!g_future_data) {
353
- LogError (" Analytics: API not initialized; call Initialize() first." );
354
- static firebase::Future<int64_t > invalid_future;
355
- return invalid_future;
356
- }
357
- const auto handle =
358
- g_future_data->CreateFuture (internal::kAnalyticsFn_GetSessionId , nullptr );
359
- g_future_data->CompleteFuture (handle, 0 /* error_code */ , nullptr /* error_message_string */ );
360
- return g_future_data->GetFuture <int64_t >(handle);
430
+ return Future<int64_t >(api, future_handle.get ());
361
431
}
362
432
363
433
Future<int64_t > GetSessionIdLastResult () {
364
- if (!g_future_data) {
365
- LogError (" Analytics: API not initialized; call Initialize() first." );
366
- static firebase::Future<int64_t > invalid_future;
367
- return invalid_future;
368
- }
369
- return g_future_data->LastResult <int64_t >(internal::kAnalyticsFn_GetSessionId );
434
+ FIREBASE_ASSERT_RETURN (Future<int64_t >(), internal::IsInitialized ());
435
+ LogWarning (" Analytics: GetSessionIdLastResult() is not supported on Desktop." );
436
+ return static_cast <const Future<int64_t >&>(
437
+ internal::FutureData::Get ()->api ()->LastResult (
438
+ internal::kAnalyticsFnGetSessionId ));
370
439
}
371
440
372
441
} // namespace analytics
0 commit comments