Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import <objc/runtime.h>
18
#include <sys/utsname.h>
19
 
20
#import <GoogleDataTransport/GoogleDataTransport.h>
21
 
22
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
23
#import <GoogleUtilities/GULHeartbeatDateStorage.h>
24
#import <GoogleUtilities/GULLogger.h>
25
 
26
#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h"
27
#import "Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h"
28
 
29
#import <nanopb/pb.h>
30
#import <nanopb/pb_decode.h>
31
#import <nanopb/pb_encode.h>
32
 
33
#import "Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h"
34
 
35
/** The logger service string to use when printing to the console. */
36
static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]";
37
 
38
#ifdef FIREBASE_BUILD_ZIP_FILE
39
static BOOL kUsingZipFile = YES;
40
#else   // FIREBASE_BUILD_ZIP_FILE
41
static BOOL kUsingZipFile = NO;
42
#endif  // FIREBASE_BUILD_ZIP_FILE
43
 
44
#if SWIFT_PACKAGE
45
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM
46
#elif FIREBASE_BUILD_CARTHAGE
47
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE
48
#elif FIREBASE_BUILD_ZIP_FILE
49
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE
50
#else
51
#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS
52
#endif
53
 
54
static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter";
55
 
56
static NSString *const kFIRServiceAdMob = @"AdMob";
57
static NSString *const kFIRServiceAuth = @"Auth";
58
static NSString *const kFIRServiceAuthUI = @"AuthUI";
59
static NSString *const kFIRServiceCrash = @"Crash";
60
static NSString *const kFIRServiceDatabase = @"Database";
61
static NSString *const kFIRServiceDynamicLinks = @"DynamicLinks";
62
static NSString *const kFIRServiceFirestore = @"Firestore";
63
static NSString *const kFIRServiceFunctions = @"Functions";
64
static NSString *const kFIRServiceIAM = @"InAppMessaging";
65
static NSString *const kFIRServiceInstanceID = @"InstanceID";
66
static NSString *const kFIRServiceInvites = @"Invites";
67
static NSString *const kFIRServiceMessaging = @"Messaging";
68
static NSString *const kFIRServiceMeasurement = @"Measurement";
69
static NSString *const kFIRServicePerformance = @"Performance";
70
static NSString *const kFIRServiceRemoteConfig = @"RemoteConfig";
71
static NSString *const kFIRServiceStorage = @"Storage";
72
static NSString *const kGGLServiceAnalytics = @"Analytics";
73
static NSString *const kGGLServiceSignIn = @"SignIn";
74
static NSString *const kFIRAppDiagnosticsConfigurationTypeKey =
75
    @"FIRAppDiagnosticsConfigurationTypeKey";
76
static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey";
77
static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey";
78
static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey";
79
static NSString *const kFIRCoreDiagnosticsHeartbeatTag = @"FIRCoreDiagnostics";
80
 
81
/**
82
 * The file name to the recent heartbeat date.
83
 */
84
NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE";
85
 
86
/**
87
 * @note This should implement the GDTCOREventDataObject protocol, but can't because of
88
 * weak-linking.
89
 */
90
@interface FIRCoreDiagnosticsLog : NSObject
91
 
92
/** The config that will be converted to proto bytes. */
93
@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config;
94
 
95
@end
96
 
97
@implementation FIRCoreDiagnosticsLog
98
 
99
- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config {
100
  self = [super init];
101
  if (self) {
102
    _config = config;
103
  }
104
  return self;
105
}
106
 
107
// Provided and required by the GDTCOREventDataObject protocol.
108
- (NSData *)transportBytes {
109
  pb_ostream_t sizestream = PB_OSTREAM_SIZING;
110
 
111
  // Encode 1 time to determine the size.
112
  if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
113
    GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s",
114
                   PB_GET_ERROR(&sizestream));
115
  }
116
 
117
  // Encode a 2nd time to actually get the bytes from it.
118
  size_t bufferSize = sizestream.bytes_written;
119
  CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
120
  CFDataSetLength(dataRef, bufferSize);
121
  pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
122
  if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) {
123
    GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for bytes: %s",
124
                   PB_GET_ERROR(&ostream));
125
  }
126
  CFDataSetLength(dataRef, ostream.bytes_written);
127
 
128
  return CFBridgingRelease(dataRef);
129
}
130
 
131
- (void)dealloc {
132
  pb_release(logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config);
133
}
134
 
135
@end
136
 
137
NS_ASSUME_NONNULL_BEGIN
138
 
139
/** This class produces a protobuf containing diagnostics and usage data to be logged. */
140
@interface FIRCoreDiagnostics : NSObject <FIRCoreDiagnosticsInterop>
141
 
142
/** The queue on which all diagnostics collection will occur. */
143
@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue;
144
 
145
/** The transport object used to send data. */
146
@property(nonatomic, readonly) GDTCORTransport *transport;
147
 
148
/** The storage to store the date of the last sent heartbeat. */
149
@property(nonatomic, readonly) GULHeartbeatDateStorage *heartbeatDateStorage;
150
 
151
@end
152
 
153
NS_ASSUME_NONNULL_END
154
 
155
@implementation FIRCoreDiagnostics
156
 
157
+ (instancetype)sharedInstance {
158
  static FIRCoreDiagnostics *sharedInstance;
159
  static dispatch_once_t onceToken;
160
  dispatch_once(&onceToken, ^{
161
    sharedInstance = [[FIRCoreDiagnostics alloc] init];
162
  });
163
  return sharedInstance;
164
}
165
 
166
- (instancetype)init {
167
  GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"137"
168
                                                             transformers:nil
169
                                                                   target:kGDTCORTargetFLL];
170
 
171
  GULHeartbeatDateStorage *dateStorage =
172
      [[GULHeartbeatDateStorage alloc] initWithFileName:kFIRCoreDiagnosticsHeartbeatDateFileName];
173
 
174
  return [self initWithTransport:transport heartbeatDateStorage:dateStorage];
175
}
176
 
177
/** Initializer for unit tests.
178
 *
179
 * @param transport A `GDTCORTransport` instance which that be used to send event.
180
 * @param heartbeatDateStorage An instanse of date storage to track heartbeat sending.
181
 * @return Returns the initialized `FIRCoreDiagnostics` instance.
182
 */
183
- (instancetype)initWithTransport:(GDTCORTransport *)transport
184
             heartbeatDateStorage:(GULHeartbeatDateStorage *)heartbeatDateStorage {
185
  self = [super init];
186
  if (self) {
187
    _diagnosticsQueue =
188
        dispatch_queue_create("com.google.FIRCoreDiagnostics", DISPATCH_QUEUE_SERIAL);
189
    _transport = transport;
190
    _heartbeatDateStorage = heartbeatDateStorage;
191
  }
192
  return self;
193
}
194
 
195
#pragma mark - nanopb helper functions
196
 
197
/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
198
 *
199
 * @note Memory needs to be free manually, through pb_free or pb_release.
200
 * @param string The string to encode as pb_bytes.
201
 */
202
pb_bytes_array_t *FIREncodeString(NSString *string) {
203
  NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
204
  return FIREncodeData(stringBytes);
205
}
206
 
207
/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array.
208
 *
209
 * @note Memory needs to be free manually, through pb_free or pb_release.
210
 * @param data The data to copy into the new bytes array.
211
 */
212
pb_bytes_array_t *FIREncodeData(NSData *data) {
213
  pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
214
  if (pbBytesArray != NULL) {
215
    [data getBytes:pbBytesArray->bytes length:data.length];
216
    pbBytesArray->size = (pb_size_t)data.length;
217
  }
218
  return pbBytesArray;
219
}
220
 
221
/** Maps a service string to the representative nanopb enum.
222
 *
223
 * @param serviceString The SDK service string to convert.
224
 * @return The representative nanopb enum.
225
 */
226
logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum(
227
    NSString *serviceString) {
228
  static NSDictionary<NSString *, NSNumber *> *serviceStringToTypeEnum;
229
  if (serviceStringToTypeEnum == nil) {
230
    serviceStringToTypeEnum = @{
231
      kFIRServiceAdMob : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB),
232
      kFIRServiceMessaging : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING),
233
      kFIRServiceMeasurement :
234
          @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT),
235
      kFIRServiceRemoteConfig :
236
          @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG),
237
      kFIRServiceDatabase : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE),
238
      kFIRServiceDynamicLinks :
239
          @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS),
240
      kFIRServiceAuth : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH),
241
      kFIRServiceAuthUI : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI),
242
      kFIRServiceFirestore : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE),
243
      kFIRServiceFunctions : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS),
244
      kFIRServicePerformance :
245
          @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE),
246
      kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE),
247
      kFIRServiceMLModelInterpreter :
248
          @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER),
249
      kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS),
250
      kGGLServiceSignIn : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN),
251
      kFIRServiceIAM : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING),
252
    };
253
  }
254
  if (serviceStringToTypeEnum[serviceString] != nil) {
255
    return (int32_t)serviceStringToTypeEnum[serviceString].longLongValue;
256
  }
257
  return logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE;
258
}
259
 
260
#pragma mark - Proto population functions
261
 
262
/** Populates the given proto with data related to an SDK logDiagnostics call from the
263
 * diagnosticObjects dictionary.
264
 *
265
 * @param config The proto to populate
266
 * @param diagnosticObjects The dictionary of diagnostics objects.
267
 */
268
void FIRPopulateProtoWithInfoFromUserInfoParams(logs_proto_mobilesdk_ios_ICoreConfiguration *config,
269
                                                NSDictionary<NSString *, id> *diagnosticObjects) {
270
  NSNumber *configurationType = diagnosticObjects[kFIRCDConfigurationTypeKey];
271
  if (configurationType != nil) {
272
    switch (configurationType.integerValue) {
273
      case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE:
274
        config->configuration_type =
275
            logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE;
276
        config->has_configuration_type = 1;
277
        break;
278
      case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK:
279
        config->configuration_type =
280
            logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK;
281
        config->has_configuration_type = 1;
282
        break;
283
      default:
284
        break;
285
    }
286
  }
287
 
288
  NSString *sdkName = diagnosticObjects[kFIRCDSdkNameKey];
289
  if (sdkName) {
290
    config->sdk_name = FIRMapFromServiceStringToTypeEnum(sdkName);
291
    config->has_sdk_name = 1;
292
  }
293
 
294
  NSString *version = diagnosticObjects[kFIRCDSdkVersionKey];
295
  if (version) {
296
    config->sdk_version = FIREncodeString(version);
297
  }
298
}
299
 
300
/** Populates the given proto with data from the calling FIRApp using the given
301
 * diagnosticObjects dictionary.
302
 *
303
 * @param config The proto to populate
304
 * @param diagnosticObjects The dictionary of diagnostics objects.
305
 */
306
void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfiguration *config,
307
                                           NSDictionary<NSString *, id> *diagnosticObjects) {
308
  config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE;
309
  config->has_pod_name = 1;
310
 
311
  if (!diagnosticObjects[kFIRCDllAppsCountKey]) {
312
    GDTCORLogError(GDTCORMCEGeneralError, @"%@",
313
                   @"App count is a required value in the data dict.");
314
  }
315
  config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue];
316
  config->has_app_count = 1;
317
 
318
  NSString *googleAppID = diagnosticObjects[kFIRCDGoogleAppIDKey];
319
  if (googleAppID.length) {
320
    config->app_id = FIREncodeString(googleAppID);
321
  }
322
 
323
  NSString *bundleID = diagnosticObjects[kFIRCDBundleIDKey];
324
  if (bundleID.length) {
325
    config->bundle_id = FIREncodeString(bundleID);
326
  }
327
 
328
  NSString *firebaseUserAgent = diagnosticObjects[kFIRCDFirebaseUserAgentKey];
329
  if (firebaseUserAgent.length) {
330
    config->platform_info = FIREncodeString(firebaseUserAgent);
331
  }
332
 
333
  NSNumber *usingOptionsFromDefaultPlist = diagnosticObjects[kFIRCDUsingOptionsFromDefaultPlistKey];
334
  if (usingOptionsFromDefaultPlist != nil) {
335
    config->use_default_app = [usingOptionsFromDefaultPlist boolValue];
336
    config->has_use_default_app = 1;
337
  }
338
 
339
  NSString *libraryVersionID = diagnosticObjects[kFIRCDLibraryVersionIDKey];
340
  if (libraryVersionID) {
341
    config->icore_version = FIREncodeString(libraryVersionID);
342
  }
343
 
344
  NSString *deviceModel = [GULAppEnvironmentUtil deviceModel];
345
  if (deviceModel.length) {
346
    config->device_model = FIREncodeString(deviceModel);
347
  }
348
 
349
  NSString *osVersion = [GULAppEnvironmentUtil systemVersion];
350
  if (osVersion.length) {
351
    config->os_version = FIREncodeString(osVersion);
352
  }
353
 
354
  config->using_zip_file = kUsingZipFile;
355
  config->has_using_zip_file = 1;
356
  config->deployment_type = kDeploymentType;
357
  config->has_deployment_type = 1;
358
  config->deployed_in_app_store = [GULAppEnvironmentUtil isFromAppStore];
359
  config->has_deployed_in_app_store = 1;
360
}
361
 
362
/** Populates the given proto with installed services data.
363
 *
364
 * @param config The proto to populate
365
 */
366
void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
367
  NSMutableArray<NSNumber *> *sdkServiceInstalledArray = [NSMutableArray array];
368
 
369
  // AdMob
370
  if (NSClassFromString(@"GADBannerView") != nil) {
371
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAdMob))];
372
  }
373
  // CloudMessaging
374
  if (NSClassFromString(@"FIRMessaging") != nil) {
375
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMessaging))];
376
  }
377
  // RemoteConfig
378
  if (NSClassFromString(@"FIRRemoteConfig") != nil) {
379
    [sdkServiceInstalledArray
380
        addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceRemoteConfig))];
381
  }
382
  // Measurement/Analtyics
383
  if (NSClassFromString(@"FIRAnalytics") != nil) {
384
    [sdkServiceInstalledArray
385
        addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))];
386
  }
387
  // ML Model Interpreter
388
  if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) {
389
    [sdkServiceInstalledArray
390
        addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLModelInterpreter))];
391
  }
392
  // Database
393
  if (NSClassFromString(@"FIRDatabase") != nil) {
394
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDatabase))];
395
  }
396
  // DynamicDeepLink
397
  if (NSClassFromString(@"FIRDynamicLinks") != nil) {
398
    [sdkServiceInstalledArray
399
        addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDynamicLinks))];
400
  }
401
  // Auth
402
  if (NSClassFromString(@"FIRAuth") != nil) {
403
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuth))];
404
  }
405
  // AuthUI
406
  if (NSClassFromString(@"FUIAuth") != nil) {
407
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuthUI))];
408
  }
409
  // Firestore
410
  if (NSClassFromString(@"FIRFirestore") != nil) {
411
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFirestore))];
412
  }
413
  // Functions
414
  if (NSClassFromString(@"FIRFunctions") != nil) {
415
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFunctions))];
416
  }
417
  // Performance
418
  if (NSClassFromString(@"FIRPerformance") != nil) {
419
    [sdkServiceInstalledArray
420
        addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServicePerformance))];
421
  }
422
  // Storage
423
  if (NSClassFromString(@"FIRStorage") != nil) {
424
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceStorage))];
425
  }
426
  // SignIn via Google pod
427
  if (NSClassFromString(@"GIDSignIn") != nil && NSClassFromString(@"GGLContext") != nil) {
428
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceSignIn))];
429
  }
430
  // Analytics via Google pod
431
  if (NSClassFromString(@"GAI") != nil && NSClassFromString(@"GGLContext") != nil) {
432
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceAnalytics))];
433
  }
434
 
435
  // In-App Messaging
436
  if (NSClassFromString(@"FIRInAppMessaging") != nil) {
437
    [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceIAM))];
438
  }
439
 
440
  logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *servicesInstalled =
441
      calloc(sdkServiceInstalledArray.count,
442
             sizeof(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType));
443
  if (servicesInstalled == NULL) {
444
    return;
445
  }
446
  for (NSUInteger i = 0; i < sdkServiceInstalledArray.count; i++) {
447
    NSNumber *typeEnum = sdkServiceInstalledArray[i];
448
    logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType serviceType =
449
        (int32_t)typeEnum.integerValue;
450
    servicesInstalled[i] = serviceType;
451
  }
452
 
453
  config->sdk_service_installed = servicesInstalled;
454
  config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count;
455
}
456
 
457
/** Populates the proto with Info.plist values.
458
 *
459
 * @param config The proto to populate.
460
 */
461
void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfiguration *config) {
462
  NSDictionary<NSString *, id> *info = [[NSBundle mainBundle] infoDictionary];
463
 
464
  NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @"";
465
  NSString *sdkVersion = info[@"DTSDKBuild"] ?: @"";
466
  NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion];
467
  config->apple_framework_version = FIREncodeString(combinedVersions);
468
 
469
  NSString *minVersion = info[@"MinimumOSVersion"];
470
  if (minVersion) {
471
    config->min_supported_ios_version = FIREncodeString(minVersion);
472
  }
473
 
474
  // Apps can turn off swizzling in the Info.plist, check if they've explicitly set the value and
475
  // report it. It's enabled by default.
476
  NSNumber *appDelegateSwizzledNum = info[@"FirebaseAppDelegateProxyEnabled"];
477
  BOOL appDelegateSwizzled = YES;
478
  if ([appDelegateSwizzledNum isKindOfClass:[NSNumber class]]) {
479
    appDelegateSwizzled = [appDelegateSwizzledNum boolValue];
480
  }
481
  config->swizzling_enabled = appDelegateSwizzled;
482
  config->has_swizzling_enabled = 1;
483
}
484
 
485
#pragma mark - FIRCoreDiagnosticsInterop
486
 
487
+ (void)sendDiagnosticsData:(nonnull id<FIRCoreDiagnosticsData>)diagnosticsData {
488
  FIRCoreDiagnostics *diagnostics = [FIRCoreDiagnostics sharedInstance];
489
  [diagnostics sendDiagnosticsData:diagnosticsData];
490
}
491
 
492
- (void)sendDiagnosticsData:(nonnull id<FIRCoreDiagnosticsData>)diagnosticsData {
493
  dispatch_async(self.diagnosticsQueue, ^{
494
    NSDictionary<NSString *, id> *diagnosticObjects = diagnosticsData.diagnosticObjects;
495
    NSNumber *isDataCollectionDefaultEnabled =
496
        diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey];
497
    if (isDataCollectionDefaultEnabled && ![isDataCollectionDefaultEnabled boolValue]) {
498
      return;
499
    }
500
 
501
    // Create the proto.
502
    logs_proto_mobilesdk_ios_ICoreConfiguration icore_config =
503
        logs_proto_mobilesdk_ios_ICoreConfiguration_init_default;
504
 
505
    icore_config.using_gdt = 1;
506
    icore_config.has_using_gdt = 1;
507
 
508
    // Populate the proto with information.
509
    FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects);
510
    FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects);
511
    FIRPopulateProtoWithInstalledServices(&icore_config);
512
    FIRPopulateProtoWithInfoPlistValues(&icore_config);
513
    [self setHeartbeatFlagIfNeededToConfig:&icore_config];
514
 
515
    // This log object is capable of converting the proto to bytes.
516
    FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config];
517
 
518
    // Send the log as a telemetry event.
519
    GDTCOREvent *event = [self.transport eventForTransport];
520
    event.dataObject = (id<GDTCOREventDataObject>)log;
521
    [self.transport sendTelemetryEvent:event];
522
  });
523
}
524
 
525
#pragma mark - Heartbeat
526
 
527
- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config {
528
  // Check if need to send a heartbeat.
529
  NSDate *currentDate = [NSDate date];
530
  NSDate *lastCheckin =
531
      [self.heartbeatDateStorage heartbeatDateForTag:kFIRCoreDiagnosticsHeartbeatTag];
532
  if (lastCheckin) {
533
    // Ensure the previous checkin was on a different date in the past.
534
    if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) {
535
      return;
536
    }
537
  }
538
 
539
  // Update heartbeat sent date.
540
  [self.heartbeatDateStorage setHearbeatDate:currentDate forTag:kFIRCoreDiagnosticsHeartbeatTag];
541
  // Set the flag.
542
  config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE;
543
  config->has_sdk_name = 1;
544
}
545
 
546
- (BOOL)isDate:(NSDate *)date1 inSameDayOrBeforeThan:(NSDate *)date2 {
547
  return [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2] ||
548
         [date1 compare:date2] == NSOrderedAscending;
549
}
550
 
551
@end