diff --git a/CMakeLists.txt b/CMakeLists.txt index 07a46c9a7d..831ce32212 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,8 +230,35 @@ podspec_framework( SPECS Logger ) +podspec_framework(${FIREBASE_SOURCE_DIR}/GoogleDataTransport.podspec) + +podspec_framework(${FIREBASE_SOURCE_DIR}/GoogleDataTransportCCTSupport.podspec) + podspec_framework(${FIREBASE_SOURCE_DIR}/FirebaseCore.podspec) +podspec_framework(${FIREBASE_SOURCE_DIR}/FirebaseCoreDiagnostics.podspec) + +podspec_framework( + ${FIREBASE_SOURCE_DIR}/FirebaseCoreDiagnosticsInterop.podspec +) + +if(APPLE) + # FirebaseCoreDiagnosticsInterop has no source files but CMake can't build + # frameworks that don't have sources. Generate an inconsequential source + # file so that the library can be linked. + file( + WRITE ${CMAKE_CURRENT_BINARY_DIR}/FirebaseCoreDiagnosticsInteropDummy.c + "// generated file for header-only CMake support. + __attribute__((unused)) + static void FirebaseCoreDiagnosticsInteropFakeSymbol() {} + " + ) + target_sources( + FirebaseCoreDiagnosticsInterop + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/FirebaseCoreDiagnosticsInteropDummy.c + ) +endif() + podspec_framework(${FIREBASE_SOURCE_DIR}/FirebaseAuthInterop.podspec) if(APPLE) diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_frameworks/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_frameworks/Podfile index ba9f0da36a..28470a48d4 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_frameworks/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_frameworks/Podfile @@ -5,8 +5,9 @@ target 'CocoapodsIntegrationTest' do use_frameworks! pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -15,5 +16,7 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' end diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_staticLibs/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_staticLibs/Podfile index 5d49a5ba8d..8159db57fa 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_staticLibs/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_6_1_staticLibs/Podfile @@ -3,8 +3,9 @@ platform :ios, '9.0' target 'CocoapodsIntegrationTest' do pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -13,5 +14,7 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' end diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_frameworks/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_frameworks/Podfile index 1ad0177e5d..21508a998a 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_frameworks/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_frameworks/Podfile @@ -5,8 +5,9 @@ target 'CocoapodsIntegrationTest' do use_frameworks! pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -15,5 +16,7 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' end \ No newline at end of file diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_frameworks/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_frameworks/Podfile index ed45548a20..60b9a33489 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_frameworks/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_frameworks/Podfile @@ -6,8 +6,9 @@ target 'CocoapodsIntegrationTest' do use_frameworks! pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -16,6 +17,8 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' end diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_staticLibs/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_staticLibs/Podfile index c20dc63811..a675fcb233 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_staticLibs/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_multiprojects_staticLibs/Podfile @@ -3,8 +3,9 @@ platform :ios, '9.0' target 'CocoapodsIntegrationTest' do pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -13,6 +14,8 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' end diff --git a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_staticLibs/Podfile b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_staticLibs/Podfile index 5d49a5ba8d..35f033ade1 100644 --- a/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_staticLibs/Podfile +++ b/CocoapodsIntegrationTest/TestEnvironments/Cocoapods1_7_0_staticLibs/Podfile @@ -3,8 +3,9 @@ platform :ios, '9.0' target 'CocoapodsIntegrationTest' do pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FirebaseAuth', :path => '../' - pod 'FirebaseCore', :path => '../' pod 'FirebaseDatabase', :path => '../' pod 'FirebaseDynamicLinks', :path => '../' pod 'FirebaseFirestore', :path => '../' @@ -13,5 +14,7 @@ target 'CocoapodsIntegrationTest' do pod 'FirebaseInstanceID', :path => '../' pod 'FirebaseMessaging', :path => '../' pod 'FirebaseStorage', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransport', :path => '../' pod 'GoogleUtilities', :path => '../' end diff --git a/Example/Auth/AuthSample/Podfile b/Example/Auth/AuthSample/Podfile index d6afd39f65..995842bcca 100644 --- a/Example/Auth/AuthSample/Podfile +++ b/Example/Auth/AuthSample/Podfile @@ -9,9 +9,12 @@ use_frameworks! target 'AuthSample' do platform :ios, '8.0' pod 'FirebaseCore', :path => '../../../' + pod 'FirebaseCoreDiagnostics', :path => '../../../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../../../' + pod 'GoogleDataTransport', :path => '../../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../../' pod 'GoogleUtilities', :path => '../../../' pod 'FirebaseAuth', :path => '../../../', :testspecs => ['unit'] - pod 'FirebaseCore', :path => '../../../' pod 'FirebaseInstanceID', :path => '../../..' pod 'FBSDKLoginKit' pod 'GoogleSignIn' diff --git a/Example/Core/Tests/FIRAppTest.m b/Example/Core/Tests/FIRAppTest.m index 3fec154af2..a326862bd1 100644 --- a/Example/Core/Tests/FIRAppTest.m +++ b/Example/Core/Tests/FIRAppTest.m @@ -15,6 +15,9 @@ #import "FIRTestCase.h" #import "FIRTestComponents.h" +#import +#import + #import #import #import @@ -262,7 +265,7 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; - (void)testErrorForSubspecConfigurationFailure { NSError *error = [FIRApp errorForSubspecConfigurationFailureWithDomain:kFirebaseCoreErrorDomain errorCode:-38 - service:kFIRServiceAuth + service:@"Auth" reason:@"some reason"]; XCTAssertNotNil(error); XCTAssert([error.domain isEqualToString:kFirebaseCoreErrorDomain]); @@ -632,9 +635,6 @@ NSString *const kFIRTestAppName2 = @"test-app-name-2"; // Ensure configure doesn't fire a notification. [FIRApp configure]; - NSError *error = [NSError errorWithDomain:@"com.firebase" code:42 userInfo:nil]; - [app sendLogsWithServiceName:@"Service" version:@"Version" error:error]; - // The observer mock is strict and will raise an exception when an unexpected notification is // received. OCMVerifyAll(self.observerMock); diff --git a/Example/Core/Tests/FIRDiagnosticsDataTest.m b/Example/Core/Tests/FIRDiagnosticsDataTest.m new file mode 100644 index 0000000000..cfd8c39f8d --- /dev/null +++ b/Example/Core/Tests/FIRDiagnosticsDataTest.m @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +#import + +@interface FIRDiagnosticsDataTest : XCTestCase + +@end + +@implementation FIRDiagnosticsDataTest + +/** Tests initialization. */ +- (void)testInit { + FIRDiagnosticsData *data = [[FIRDiagnosticsData alloc] init]; + XCTAssertNotNil(data); +} + +/** Tests that -diagnosticObjects returns a valid default dictionary. */ +- (void)testFIRCoreDiagnosticsData { + FIRDiagnosticsData *data = [[FIRDiagnosticsData alloc] init]; + XCTAssertNotNil(data.diagnosticObjects); + XCTAssertNotNil(data.diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]); + XCTAssertNotNil(data.diagnosticObjects[kFIRCDllAppsCountKey]); + XCTAssertNotNil(data.diagnosticObjects[kFIRCDFirebaseUserAgentKey]); +} + +/** Tests that setting diagnosticObjects throws. */ +- (void)testSettingDiagnosticObjectsThrows { + FIRDiagnosticsData *data = [[FIRDiagnosticsData alloc] init]; + XCTAssertThrows(data.diagnosticObjects = @{}); +} + +@end diff --git a/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsDateFileStorageTests.m b/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsDateFileStorageTests.m new file mode 100644 index 0000000000..12f0b303d8 --- /dev/null +++ b/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsDateFileStorageTests.m @@ -0,0 +1,79 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import +#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h" + +@interface FIRCoreDiagnosticsDateFileStorageTests : XCTestCase +@property(nonatomic) NSURL *fileURL; +@property(nonatomic) FIRCoreDiagnosticsDateFileStorage *storage; +@end + +@implementation FIRCoreDiagnosticsDateFileStorageTests + +- (void)setUp { + NSString *documentsPath = [NSSearchPathForDirectoriesInDomains( + NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject]; + XCTAssertNotNil(documentsPath); + NSURL *documentsURL = [NSURL fileURLWithPath:documentsPath]; + self.fileURL = [documentsURL URLByAppendingPathComponent:@"FIRDiagnosticsDateFileStorageTests" + isDirectory:NO]; + + NSError *error; + if (![documentsURL checkResourceIsReachableAndReturnError:&error]) { + XCTAssert([[NSFileManager defaultManager] createDirectoryAtURL:documentsURL + withIntermediateDirectories:YES + attributes:nil + error:&error], + @"Error: %@", error); + } + + self.storage = [[FIRCoreDiagnosticsDateFileStorage alloc] initWithFileURL:self.fileURL]; +} + +- (void)tearDown { + [[NSFileManager defaultManager] removeItemAtURL:self.fileURL error:nil]; + self.fileURL = nil; + self.storage = nil; +} + +- (void)testDateStorage { + NSDate *dateToSave = [NSDate date]; + + XCTAssertNil([self.storage date]); + + NSError *error; + XCTAssertTrue([self.storage setDate:dateToSave error:&error]); + + XCTAssertEqualObjects([self.storage date], dateToSave); + + XCTAssertTrue([self.storage setDate:nil error:&error]); + XCTAssertNil([self.storage date]); +} + +- (void)testDateIsStoredToFileSystem { + NSDate *date = [NSDate date]; + + NSError *error; + XCTAssert([self.storage setDate:date error:&error], @"Error: %@", error); + + FIRCoreDiagnosticsDateFileStorage *anotherStorage = + [[FIRCoreDiagnosticsDateFileStorage alloc] initWithFileURL:self.fileURL]; + + XCTAssertEqualObjects([anotherStorage date], date); +} + +@end diff --git a/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsTest.m b/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsTest.m new file mode 100644 index 0000000000..aa68dcf244 --- /dev/null +++ b/Example/CoreDiagnostics/Tests/FIRCoreDiagnosticsTest.m @@ -0,0 +1,351 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h" + +#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h" + +extern NSString *const kFIRAppDiagnosticsNotification; +extern NSString *const kFIRLastCheckinDateKey; + +static NSString *const kGoogleAppID = @"1:123:ios:123abc"; +static NSString *const kBundleID = @"com.google.FirebaseSDKTests"; +static NSString *const kLibraryVersionID = @"1.2.3"; + +#pragma mark - Testing interfaces + +@interface FIRCoreDiagnostics : NSObject +// Initialization. ++ (instancetype)sharedInstance; +- (instancetype)initWithTransport:(GDTTransport *)transport + heartbeatDateStorage:(FIRCoreDiagnosticsDateFileStorage *)heartbeatDateStorage; + +// Properties. +@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue; +@property(nonatomic, readonly) GDTTransport *transport; +@property(nonatomic, readonly) FIRCoreDiagnosticsDateFileStorage *heartbeatDateStorage; + +// Install string helpers. ++ (NSString *)installString; ++ (BOOL)writeString:(NSString *)string toURL:(NSURL *)filePathURL; ++ (NSURL *)filePathURLWithName:(NSString *)fileName; ++ (NSString *)stringAtURL:(NSURL *)filePathURL; + +// Metadata helpers. ++ (NSString *)deviceModel; + +// nanopb helper functions. +extern pb_bytes_array_t *FIREncodeString(NSString *string); +extern pb_bytes_array_t *FIREncodeData(NSData *data); +extern logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum( + NSString *serviceString); + +// Proto population functions. +extern void FIRPopulateProtoWithInfoFromUserInfoParams( + logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects); +extern void FIRPopulateProtoWithCommonInfoFromApp( + logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects); +extern void FIRPopulateProtoWithInstalledServices( + logs_proto_mobilesdk_ios_ICoreConfiguration *config); +extern void FIRPopulateProtoWithNumberOfLinkedFrameworks( + logs_proto_mobilesdk_ios_ICoreConfiguration *config); +extern void FIRPopulateProtoWithInfoPlistValues( + logs_proto_mobilesdk_ios_ICoreConfiguration *config); + +// FIRCoreDiagnosticsInterop. ++ (void)sendDiagnosticsData:(nonnull id)diagnosticsData; +- (void)sendDiagnosticsData:(nonnull id)diagnosticsData; + +@end + +#pragma mark - Testing classes + +@interface FIRCoreDiagnosticsTestData : NSObject + +@end + +@implementation FIRCoreDiagnosticsTestData + +@synthesize diagnosticObjects = _diagnosticObjects; + +- (instancetype)init { + self = [super init]; + if (self) { + _diagnosticObjects = + @{kFIRCDGoogleAppIDKey : kGoogleAppID, @"BUNDLE_ID" : kBundleID, kFIRCDllAppsCountKey : @1}; + } + return self; +} + +@end + +@interface FIRCoreDiagnosticsLog : NSObject + +@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config; + +- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config; + +@end + +#pragma mark - Tests + +@interface FIRCoreDiagnosticsTest : XCTestCase + +@property(nonatomic) id optionsInstanceMock; +@property(nonatomic) NSDictionary *expectedUserInfo; +@property(nonatomic) FIRCoreDiagnostics *diagnostics; +@property(nonatomic) id mockDateStorage; +@property(nonatomic) id mockTransport; + +@end + +@implementation FIRCoreDiagnosticsTest + +- (void)setUp { + [super setUp]; + + self.mockTransport = OCMClassMock([GDTTransport class]); + OCMStub([self.mockTransport eventForTransport]) + .andReturn([[GDTEvent alloc] initWithMappingID:@"111" target:2]); + + self.mockDateStorage = OCMClassMock([FIRCoreDiagnosticsDateFileStorage class]); + self.diagnostics = [[FIRCoreDiagnostics alloc] initWithTransport:self.mockTransport + heartbeatDateStorage:self.mockDateStorage]; +} + +- (void)tearDown { + self.diagnostics = nil; + self.mockTransport = nil; + self.mockDateStorage = nil; + [super tearDown]; +} + +/** Tests populating the proto correctly. */ +- (void)testProtoPopulation { + logs_proto_mobilesdk_ios_ICoreConfiguration icoreConfiguration = + logs_proto_mobilesdk_ios_ICoreConfiguration_init_default; + FIRPopulateProtoWithCommonInfoFromApp(&icoreConfiguration, @{ + kFIRCDllAppsCountKey : @1, + kFIRCDGoogleAppIDKey : kGoogleAppID, + kFIRCDBundleIDKey : kBundleID, + kFIRCDLibraryVersionIDKey : kLibraryVersionID, + kFIRCDUsingOptionsFromDefaultPlistKey : @YES + }); + icoreConfiguration.using_gdt = 1; + icoreConfiguration.has_using_gdt = 1; + FIRPopulateProtoWithNumberOfLinkedFrameworks(&icoreConfiguration); + FIRPopulateProtoWithInfoPlistValues(&icoreConfiguration); + icoreConfiguration.configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE; + + logs_proto_mobilesdk_ios_ICoreConfiguration icoreExpectedConfiguration = + logs_proto_mobilesdk_ios_ICoreConfiguration_init_default; + [self populateProto:&icoreExpectedConfiguration]; + + FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icoreConfiguration]; + FIRCoreDiagnosticsLog *expectedLog = + [[FIRCoreDiagnosticsLog alloc] initWithConfig:icoreExpectedConfiguration]; + + XCTAssert([[log transportBytes] isEqualToData:[expectedLog transportBytes]]); + // A pb_release here should not be necessary here, as FIRCoreDiagnosticsLog should do it. +} + +// Populates the ICoreConfiguration proto. +- (void)populateProto:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config { + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @""; + NSString *sdkVersion = info[@"DTSDKBuild"] ?: @""; + NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion]; + + config->using_gdt = 1; + config->has_using_gdt = 1; + config->configuration_type = logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE; + config->icore_version = FIREncodeString(kLibraryVersionID); + config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE; + config->has_pod_name = 1; + config->app_id = FIREncodeString(kGoogleAppID); + config->bundle_id = FIREncodeString(kBundleID); + config->device_model = FIREncodeString([FIRCoreDiagnostics deviceModel]); + config->os_version = FIREncodeString([GULAppEnvironmentUtil systemVersion]); + config->app_count = 1; + config->has_app_count = 1; + config->use_default_app = 1; + config->has_use_default_app = 1; + + int numFrameworks = -1; // Subtract the app binary itself. + unsigned int numImages; + const char **imageNames = objc_copyImageNames(&numImages); + for (unsigned int i = 0; i < numImages; i++) { + NSString *imageName = [NSString stringWithUTF8String:imageNames[i]]; + if ([imageName rangeOfString:@"System/Library"].length != 0 // Apple .frameworks + || [imageName rangeOfString:@"Developer/Library"].length != 0 // Xcode debug .frameworks + || [imageName rangeOfString:@"usr/lib"].length != 0) { // Public .dylibs + continue; + } + numFrameworks++; + } + free(imageNames); + config->dynamic_framework_count = numFrameworks; + config->has_dynamic_framework_count = 1; + config->apple_framework_version = FIREncodeString(combinedVersions); +#if !TARGET_OS_IOS + NSString *minVersion = [[NSBundle mainBundle] infoDictionary][@"MinimumOSVersion"]; + if (minVersion) { + config->min_supported_ios_version = FIREncodeString(minVersion); + } +#endif // TARGET_OS_IOS + config->using_zip_file = 0; + config->has_using_zip_file = 1; + config->deployment_type = logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS; + config->has_deployment_type = 1; + config->deployed_in_app_store = 0; + config->has_deployed_in_app_store = 1; + config->swizzling_enabled = 1; + config->has_swizzling_enabled = 1; +} + +#pragma mark - Heartbeats + +- (void)testHeartbeatNotSentTheSameDay { + NSCalendar *calendar = [NSCalendar currentCalendar]; + + NSCalendarUnit unitFlags = NSCalendarUnitDay | NSCalendarUnitYear | NSCalendarUnitMonth; + NSDateComponents *dateComponents = [calendar components:unitFlags fromDate:[NSDate date]]; + + // Verify start of the day + NSDate *startOfTheDay = [calendar dateFromComponents:dateComponents]; + OCMExpect([self.mockDateStorage date]).andReturn(startOfTheDay); + OCMReject([self.mockDateStorage setDate:[self OCMArgToCheckDateEqualTo:[OCMArg any]] + error:[OCMArg anyObjectRef]]); + + [self assertEventSentWithHeartbeat:NO]; + + // Verify middle of the day + dateComponents.hour = 12; + NSDate *middleOfTheDay = [calendar dateFromComponents:dateComponents]; + OCMExpect([self.mockDateStorage date]).andReturn(middleOfTheDay); + OCMReject([self.mockDateStorage setDate:[self OCMArgToCheckDateEqualTo:[OCMArg any]] + error:[OCMArg anyObjectRef]]); + + [self assertEventSentWithHeartbeat:NO]; + + // Verify end of the day + dateComponents.hour = 0; + dateComponents.day += 1; + NSDate *startOfNextDay = [calendar dateFromComponents:dateComponents]; + NSDate *endOfTheDay = [startOfNextDay dateByAddingTimeInterval:-1]; + OCMExpect([self.mockDateStorage date]).andReturn(endOfTheDay); + OCMReject([self.mockDateStorage setDate:[self OCMArgToCheckDateEqualTo:[OCMArg any]] + error:[OCMArg anyObjectRef]]); + + [self assertEventSentWithHeartbeat:NO]; +} + +- (void)testHeartbeatSentNoPreviousCheckin { + OCMExpect([self.mockDateStorage date]).andReturn(nil); + OCMExpect([self.mockDateStorage setDate:[self OCMArgToCheckDateEqualTo:[NSDate date]] + error:[OCMArg anyObjectRef]]); + + [self assertEventSentWithHeartbeat:YES]; +} + +- (void)testHeartbeatSentNextDayDefaultApp { + NSDate *startOfToday = [[NSCalendar currentCalendar] startOfDayForDate:[NSDate date]]; + NSDate *endOfYesterday = [startOfToday dateByAddingTimeInterval:-1]; + + OCMExpect([self.mockDateStorage date]).andReturn(endOfYesterday); + OCMExpect([self.mockDateStorage setDate:[self OCMArgToCheckDateEqualTo:[NSDate date]] + error:[OCMArg anyObjectRef]]); + + [self assertEventSentWithHeartbeat:YES]; +} + +#pragma mark - Singleton + +- (void)testSharedInstanceDateStorageProperlyInitialized { + FIRCoreDiagnostics *sharedInstance = [FIRCoreDiagnostics sharedInstance]; + XCTAssertNotNil(sharedInstance.heartbeatDateStorage); + XCTAssert([sharedInstance.heartbeatDateStorage + isKindOfClass:[FIRCoreDiagnosticsDateFileStorage class]]); + + NSDate *date = [NSDate date]; + + NSError *error; + XCTAssertTrue([sharedInstance.heartbeatDateStorage setDate:date error:&error], @"Error %@", + error); + + XCTAssertEqualObjects([sharedInstance.heartbeatDateStorage date], date); +} + +#pragma mark - Helpers + +- (void)assertEventSentWithHeartbeat:(BOOL)isHeartbeat { + [self expectEventToBeSentToTransportWithHeartbeat:isHeartbeat]; + + [self.diagnostics sendDiagnosticsData:[[FIRCoreDiagnosticsTestData alloc] init]]; + + OCMVerifyAllWithDelay(self.mockTransport, 0.5); + OCMVerifyAllWithDelay(self.mockDateStorage, 0.5); +} + +- (void)expectEventToBeSentToTransportWithHeartbeat:(BOOL)isHeartbeat { + id eventValidation = [OCMArg checkWithBlock:^BOOL(GDTEvent *obj) { + XCTAssert([obj isKindOfClass:[GDTEvent class]]); + FIRCoreDiagnosticsLog *dataObject = obj.dataObject; + XCTAssert([dataObject isKindOfClass:[FIRCoreDiagnosticsLog class]]); + + BOOL isSentEventHeartbeat = + dataObject.config.sdk_name == logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE; + XCTAssertEqual(isSentEventHeartbeat, isHeartbeat); + + return YES; + }]; + OCMExpect([self.mockTransport sendTelemetryEvent:eventValidation]); +} + +- (BOOL)isDate:(NSDate *)date1 approximatelyEqual:(NSDate *)date2 { + NSTimeInterval precision = 10; + NSTimeInterval diff = ABS([date1 timeIntervalSinceDate:date2]); + return diff <= precision; +} + +- (id)OCMArgToCheckDateEqualTo:(NSDate *)date { + return [OCMArg checkWithBlock:^BOOL(id obj) { + XCTAssert([obj isKindOfClass:[NSDate class]], "%@", self.name); + return [self isDate:obj approximatelyEqual:date]; + }]; +} + +@end diff --git a/Example/Firebase.xcodeproj/project.pbxproj b/Example/Firebase.xcodeproj/project.pbxproj index 2ccbcd0da0..86576490db 100644 --- a/Example/Firebase.xcodeproj/project.pbxproj +++ b/Example/Firebase.xcodeproj/project.pbxproj @@ -5753,6 +5753,7 @@ "\"${PODS_ROOT}/Headers/Public\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAnalyticsInterop\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAuthInterop\"", + "\"${PODS_ROOT}/Headers/Public/FirebaseCoreDiagnosticsInterop\"", ); INFOPLIST_FILE = "$(SRCROOT)/Messaging/App/tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -5830,6 +5831,7 @@ "\"${PODS_ROOT}/Headers/Public\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAnalyticsInterop\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAuthInterop\"", + "\"${PODS_ROOT}/Headers/Public/FirebaseCoreDiagnosticsInterop\"", "\"${PODS_ROOT}/Headers/Private\"", "\"${PODS_ROOT}/../../Firebase/Messaging\"", ); @@ -5877,6 +5879,7 @@ "\"${PODS_ROOT}/Headers/Public\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAnalyticsInterop\"", "\"${PODS_ROOT}/Headers/Public/FirebaseAuthInterop\"", + "\"${PODS_ROOT}/Headers/Public/FirebaseCoreDiagnosticsInterop\"", "\"${PODS_ROOT}/../../Firebase/Messaging\"", ); INFOPLIST_FILE = Messaging/Tests/Info.plist; diff --git a/Example/Podfile b/Example/Podfile index 20868c007f..460e9cccec 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -9,6 +9,10 @@ use_frameworks! pod 'FirebaseAnalyticsInterop', :path => '../' pod 'FirebaseAuthInterop', :path => '../' pod 'FirebaseCore', :path => '../' +pod 'FirebaseCoreDiagnostics', :path => '../' +pod 'FirebaseCoreDiagnosticsInterop', :path => '../' +pod 'GoogleDataTransport', :path => '../' +pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GoogleUtilities', :path => '../' target 'Core_Example_iOS' do @@ -126,9 +130,13 @@ target 'Auth_Sample' do platform :ios, '8.0' pod 'FirebaseAuth', :path => '../' pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' pod 'FBSDKLoginKit' pod 'GoogleSignIn' pod 'FirebaseInstanceID', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' pod 'GTMSessionFetcher/Core' target 'Auth_ApiTests' do @@ -145,6 +153,10 @@ target 'Core_Example_macOS' do platform :osx, '10.11' pod 'FirebaseCore', :path => '../' + pod 'FirebaseCoreDiagnostics', :path => '../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../' + pod 'GoogleDataTransport', :path => '../' + pod 'GoogleDataTransportCCTSupport', :path => '../' target 'Core_Tests_macOS' do inherit! :search_paths diff --git a/Example/tvOSSample/Podfile b/Example/tvOSSample/Podfile index 1e79a07d1d..6aeddcb8da 100644 --- a/Example/tvOSSample/Podfile +++ b/Example/tvOSSample/Podfile @@ -7,8 +7,12 @@ target 'tvOSSample' do # Pods for tvOSSample pod 'FirebaseCore', :path => '../../' + pod 'FirebaseCoreDiagnostics', :path => '../../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../../' pod 'FirebaseAuth', :path => '../../' pod 'FirebaseDatabase', :path => '../../' pod 'FirebaseStorage', :path => '../../' + pod 'GoogleDataTransport', :path => '../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../' end diff --git a/Firebase/Core/FIRApp.m b/Firebase/Core/FIRApp.m index 7d17127f49..cab4a34479 100644 --- a/Firebase/Core/FIRApp.m +++ b/Firebase/Core/FIRApp.m @@ -15,32 +15,38 @@ #include #import "FIRApp.h" + +#import + #import "Private/FIRAnalyticsConfiguration.h" #import "Private/FIRAppInternal.h" #import "Private/FIRBundleUtil.h" #import "Private/FIRComponentContainerInternal.h" #import "Private/FIRConfigurationInternal.h" +#import "Private/FIRCoreDiagnosticsConnector.h" #import "Private/FIRLibrary.h" #import "Private/FIRLogger.h" #import "Private/FIROptionsInternal.h" -NSString *const kFIRServiceAdMob = @"AdMob"; -NSString *const kFIRServiceAuth = @"Auth"; -NSString *const kFIRServiceAuthUI = @"AuthUI"; -NSString *const kFIRServiceCrash = @"Crash"; -NSString *const kFIRServiceDatabase = @"Database"; -NSString *const kFIRServiceDynamicLinks = @"DynamicLinks"; -NSString *const kFIRServiceFirestore = @"Firestore"; -NSString *const kFIRServiceFunctions = @"Functions"; -NSString *const kFIRServiceInstanceID = @"InstanceID"; -NSString *const kFIRServiceInvites = @"Invites"; -NSString *const kFIRServiceMessaging = @"Messaging"; -NSString *const kFIRServiceMeasurement = @"Measurement"; -NSString *const kFIRServicePerformance = @"Performance"; -NSString *const kFIRServiceRemoteConfig = @"RemoteConfig"; -NSString *const kFIRServiceStorage = @"Storage"; -NSString *const kGGLServiceAnalytics = @"Analytics"; -NSString *const kGGLServiceSignIn = @"SignIn"; +// The kFIRService strings are only here while transitioning CoreDiagnostics from the Analytics +// pod to a Core dependency. These symbols are not used and should be deleted after the transition. +NSString *const kFIRServiceAdMob; +NSString *const kFIRServiceAuth; +NSString *const kFIRServiceAuthUI; +NSString *const kFIRServiceCrash; +NSString *const kFIRServiceDatabase; +NSString *const kFIRServiceDynamicLinks; +NSString *const kFIRServiceFirestore; +NSString *const kFIRServiceFunctions; +NSString *const kFIRServiceInstanceID; +NSString *const kFIRServiceInvites; +NSString *const kFIRServiceMessaging; +NSString *const kFIRServiceMeasurement; +NSString *const kFIRServicePerformance; +NSString *const kFIRServiceRemoteConfig; +NSString *const kFIRServiceStorage; +NSString *const kGGLServiceAnalytics; +NSString *const kGGLServiceSignIn; NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; @@ -103,19 +109,6 @@ static NSMutableDictionary *sLibraryVersions; + (void)configure { FIROptions *options = [FIROptions defaultOptions]; if (!options) { - // Read the Info.plist to see if the flag is set. At this point we can't check any user defaults - // since the app isn't configured at all, so only rely on the Info.plist value. - NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; - if (collectionEnabledPlistValue == nil || [collectionEnabledPlistValue boolValue]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsErrorKey : [FIRApp errorForMissingOptions] - }]; - } - [NSException raise:kFirebaseCoreErrorDomain format:@"`[FIRApp configure];` (`FirebaseApp.configure()` in Swift) could not find " @"a valid GoogleService-Info.plist in your project. Please download one " @@ -293,26 +286,11 @@ static NSMutableDictionary *sLibraryVersions; - (BOOL)configureCore { [self checkExpectedBundleID]; if (![self isAppIDValid]) { - if (_options.usingOptionsFromDefaultPlist && [self isDataCollectionDefaultEnabled]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsErrorKey : [FIRApp errorForInvalidAppID], - }]; - } return NO; } if ([self isDataCollectionDefaultEnabled]) { - [[NSNotificationCenter defaultCenter] - postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeCore), - kFIRAppDiagnosticsFIRAppKey : self - }]; + [FIRCoreDiagnosticsConnector logConfigureCoreWithOptions:_options]; } #if TARGET_OS_IOS @@ -809,26 +787,13 @@ static NSMutableDictionary *sLibraryVersions; #pragma mark - Sending Logs +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" - (void)sendLogsWithServiceName:(NSString *)serviceName version:(NSString *)version error:(NSError *)error { - // If the user has manually turned off data collection, return and don't send logs. - if (![self isDataCollectionDefaultEnabled]) { - return; - } - - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeSDK), - kFIRAppDiagnosticsSDKNameKey : serviceName, - kFIRAppDiagnosticsSDKVersionKey : version, - kFIRAppDiagnosticsFIRAppKey : self - }]; - if (error) { - userInfo[kFIRAppDiagnosticsErrorKey] = error; - } - [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDiagnosticsNotification - object:nil - userInfo:userInfo]; + // Do nothing. Please remove calls to this method. } +#pragma clang diagnostic pop @end diff --git a/Firebase/Core/FIRCoreDiagnosticsConnector.m b/Firebase/Core/FIRCoreDiagnosticsConnector.m new file mode 100644 index 0000000000..10e1b4407d --- /dev/null +++ b/Firebase/Core/FIRCoreDiagnosticsConnector.m @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "Private/FIRCoreDiagnosticsConnector.h" + +#import + +#import + +#import "Private/FIRAppInternal.h" +#import "Private/FIRDiagnosticsData.h" +#import "Private/FIROptionsInternal.h" + +// Define the interop class symbol declared as an extern in FIRCoreDiagnosticsInterop. +Class FIRCoreDiagnosticsImplementation; + +@implementation FIRCoreDiagnosticsConnector + ++ (void)initialize { + if (!FIRCoreDiagnosticsImplementation) { + FIRCoreDiagnosticsImplementation = NSClassFromString(@"FIRCoreDiagnostics"); + if (FIRCoreDiagnosticsImplementation) { + NSAssert([FIRCoreDiagnosticsImplementation + conformsToProtocol:@protocol(FIRCoreDiagnosticsInterop)], + @"If FIRCoreDiagnostics is implemented, it must conform to the interop protocol."); + NSAssert( + [FIRCoreDiagnosticsImplementation respondsToSelector:@selector(sendDiagnosticsData:)], + @"If FIRCoreDiagnostics is implemented, it must implement +sendDiagnosticsData."); + } + } +} + ++ (void)logConfigureCoreWithOptions:(FIROptions *)options { + if (FIRCoreDiagnosticsImplementation) { + FIRDiagnosticsData *diagnosticsData = [[FIRDiagnosticsData alloc] init]; + [diagnosticsData insertValue:@(YES) forKey:kFIRCDIsDataCollectionDefaultEnabledKey]; + [diagnosticsData insertValue:[FIRApp firebaseUserAgent] forKey:kFIRCDFirebaseUserAgentKey]; + [diagnosticsData insertValue:@(FIRConfigTypeCore) forKey:kFIRCDConfigurationTypeKey]; + [diagnosticsData insertValue:options.googleAppID forKey:kFIRCDGoogleAppIDKey]; + [diagnosticsData insertValue:options.bundleID forKey:kFIRCDBundleIDKey]; + [diagnosticsData insertValue:@(options.usingOptionsFromDefaultPlist) + forKey:kFIRCDUsingOptionsFromDefaultPlistKey]; + [diagnosticsData insertValue:options.libraryVersionID forKey:kFIRCDLibraryVersionIDKey]; + [FIRCoreDiagnosticsImplementation sendDiagnosticsData:diagnosticsData]; + } +} + +@end diff --git a/Firebase/Core/FIRDiagnosticsData.m b/Firebase/Core/FIRDiagnosticsData.m new file mode 100644 index 0000000000..04769737f5 --- /dev/null +++ b/Firebase/Core/FIRDiagnosticsData.m @@ -0,0 +1,66 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "Private/FIRDiagnosticsData.h" + +#import + +#import "Private/FIRAppInternal.h" +#import "Private/FIROptionsInternal.h" + +@implementation FIRDiagnosticsData { + /** Backing ivar for the diagnosticObjects property. */ + NSMutableDictionary *_diagnosticObjects; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _diagnosticObjects = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)insertValue:(nullable id)value forKey:(NSString *)key { + if (key) { + _diagnosticObjects[key] = value; + } +} + +#pragma mark - FIRCoreDiagnosticsData + +- (NSDictionary *)diagnosticObjects { + if (!_diagnosticObjects[kFIRCDllAppsCountKey]) { + _diagnosticObjects[kFIRCDllAppsCountKey] = @([FIRApp allApps].count); + } + if (!_diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]) { + _diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey] = + @([[FIRApp defaultApp] isDataCollectionDefaultEnabled]); + } + if (!_diagnosticObjects[kFIRCDFirebaseUserAgentKey]) { + _diagnosticObjects[kFIRCDFirebaseUserAgentKey] = [FIRApp firebaseUserAgent]; + } + return _diagnosticObjects; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +- (void)setDiagnosticObjects:(NSDictionary *)diagnosticObjects { + NSAssert(NO, @"Please use -insertValue:forKey:"); +} +#pragma clang diagnostic pop + +@end diff --git a/Firebase/Core/Private/FIRAppInternal.h b/Firebase/Core/Private/FIRAppInternal.h index 09728cd33b..ad1a186b93 100644 --- a/Firebase/Core/Private/FIRAppInternal.h +++ b/Firebase/Core/Private/FIRAppInternal.h @@ -34,26 +34,6 @@ typedef NS_ENUM(NSInteger, FIRConfigType) { FIRConfigTypeSDK = 2, }; -/** - * Names of services provided by Firebase. - */ -extern NSString *const kFIRServiceAdMob; -extern NSString *const kFIRServiceAuth; -extern NSString *const kFIRServiceAuthUI; -extern NSString *const kFIRServiceDatabase; -extern NSString *const kFIRServiceDynamicLinks; -extern NSString *const kFIRServiceInstanceID; -extern NSString *const kFIRServiceMessaging; -extern NSString *const kFIRServiceMeasurement; -extern NSString *const kFIRServiceRemoteConfig; -extern NSString *const kFIRServiceStorage; - -/** - * Names of services provided by the Google pod, but logged by the Firebase pod. - */ -extern NSString *const kGGLServiceAnalytics; -extern NSString *const kGGLServiceSignIn; - extern NSString *const kFIRDefaultAppName; extern NSString *const kFIRAppReadyToConfigureSDKNotification; extern NSString *const kFIRAppDeleteNotification; @@ -160,6 +140,8 @@ extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; /** * Used by each SDK to send logs about SDK configuration status to Clearcut. + * + * @note This API is a no-op, please remove calls to it. */ - (void)sendLogsWithServiceName:(NSString *)serviceName version:(NSString *)version diff --git a/Firebase/Core/Private/FIRCoreDiagnosticsConnector.h b/Firebase/Core/Private/FIRCoreDiagnosticsConnector.h new file mode 100644 index 0000000000..23fe2c6bc9 --- /dev/null +++ b/Firebase/Core/Private/FIRCoreDiagnosticsConnector.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +@class FIRDiagnosticsData; +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** Connects FIRCore with the CoreDiagnostics library. */ +@interface FIRCoreDiagnosticsConnector : NSObject + +/** Logs data related to a -configureCore call. + * + * @param options The options object containing data to log. + */ ++ (void)logConfigureCoreWithOptions:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Core/Private/FIRDiagnosticsData.h b/Firebase/Core/Private/FIRDiagnosticsData.h new file mode 100644 index 0000000000..ac5ef2c4f9 --- /dev/null +++ b/Firebase/Core/Private/FIRDiagnosticsData.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Implements the FIRCoreDiagnosticsData protocol to log diagnostics data. */ +@interface FIRDiagnosticsData : NSObject + +/** Inserts values into the diagnosticObjects dictionary if the value isn't nil. + * + * @param value The value to insert if it's not nil. + * @param key The key to associate it with. + */ +- (void)insertValue:(nullable id)value forKey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/CoreDiagnostics/CHANGELOG.md b/Firebase/CoreDiagnostics/CHANGELOG.md new file mode 100644 index 0000000000..39a21afe00 --- /dev/null +++ b/Firebase/CoreDiagnostics/CHANGELOG.md @@ -0,0 +1,8 @@ +# v0.1.0 +- Initial Release--for Google-use only. This library collects diagnostics and +usage data for internal use by Firebase. Data gathered by this library will +only be uploaded at most once every 24 hours whilst on mobile data, and more +frequently on wifi if it's available. This library has been integrated as a +weak dependency and can be safely removed by using a non-Cocoapods distribution +method. You can also use the Firebase global data collection flag to opt-out of +collecting this usage data. \ No newline at end of file diff --git a/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m new file mode 100644 index 0000000000..88b8b952a6 --- /dev/null +++ b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnostics.m @@ -0,0 +1,669 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import +#include + +#import +#import +#import + +#import +#import + +#import +#import + +#import +#import +#import + +#import "FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h" + +#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h" + +/** The logger service string to use when printing to the console. */ +static GULLoggerService kFIRCoreDiagnostics = @"[FirebaseCoreDiagnostics/FIRCoreDiagnostics]"; + +#ifdef FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = YES; +#else // FIREBASE_BUILD_ZIP_FILE +static BOOL kUsingZipFile = NO; +#endif // FIREBASE_BUILD_ZIP_FILE + +#ifdef FIREBASE_BUILD_CARTHAGE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE +#elif FIREBASE_BUILD_ZIP_FILE +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE +#else +#define kDeploymentType logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS +#endif + +static NSString *const kFIRServiceMLVisionOnDeviceAutoML = @"MLVisionOnDeviceAutoML"; +static NSString *const kFIRServiceMLVisionOnDeviceFace = @"MLVisionOnDeviceFace"; +static NSString *const kFIRServiceMLVisionOnDeviceBarcode = @"MLVisionOnDeviceBarcode"; +static NSString *const kFIRServiceMLVisionOnDeviceText = @"MLVisionOnDeviceText"; +static NSString *const kFIRServiceMLVisionOnDeviceLabel = @"MLVisionOnDeviceLabel"; +static NSString *const kFIRServiceMLVisionOnDeviceObjectDetection = + @"MLVisionOnDeviceObjectDetection"; +static NSString *const kFIRServiceMLModelInterpreter = @"MLModelInterpreter"; + +static NSString *const kFIRServiceAdMob = @"AdMob"; +static NSString *const kFIRServiceAuth = @"Auth"; +static NSString *const kFIRServiceAuthUI = @"AuthUI"; +static NSString *const kFIRServiceCrash = @"Crash"; +static NSString *const kFIRServiceDatabase = @"Database"; +static NSString *const kFIRServiceDynamicLinks = @"DynamicLinks"; +static NSString *const kFIRServiceFirestore = @"Firestore"; +static NSString *const kFIRServiceFunctions = @"Functions"; +static NSString *const kFIRServiceIAM = @"InAppMessaging"; +static NSString *const kFIRServiceInstanceID = @"InstanceID"; +static NSString *const kFIRServiceInvites = @"Invites"; +static NSString *const kFIRServiceMessaging = @"Messaging"; +static NSString *const kFIRServiceMeasurement = @"Measurement"; +static NSString *const kFIRServicePerformance = @"Performance"; +static NSString *const kFIRServiceRemoteConfig = @"RemoteConfig"; +static NSString *const kFIRServiceStorage = @"Storage"; +static NSString *const kGGLServiceAnalytics = @"Analytics"; +static NSString *const kGGLServiceSignIn = @"SignIn"; +static NSString *const kFIRAppDiagnosticsConfigurationTypeKey = + @"FIRAppDiagnosticsConfigurationTypeKey"; +static NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRAppDiagnosticsFIRAppKey"; +static NSString *const kFIRAppDiagnosticsSDKNameKey = @"FIRAppDiagnosticsSDKNameKey"; +static NSString *const kFIRAppDiagnosticsSDKVersionKey = @"FIRAppDiagnosticsSDKVersionKey"; + +/** + * The file name to the recent heartbeat date. + */ +NSString *const kFIRCoreDiagnosticsHeartbeatDateFileName = @"FIREBASE_DIAGNOSTICS_HEARTBEAT_DATE"; + +/** + * @note This should implement the GDTEventDataObject protocol, but can't because of weak-linking. + */ +@interface FIRCoreDiagnosticsLog : NSObject + +/** The config that will be converted to proto bytes. */ +@property(nonatomic) logs_proto_mobilesdk_ios_ICoreConfiguration config; + +@end + +@implementation FIRCoreDiagnosticsLog + +- (instancetype)initWithConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration)config { + self = [super init]; + if (self) { + _config = config; + } + return self; +} + +// Provided and required by the GDTEventDataObject protocol. +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + NSCAssert(NO, @"Error in nanopb encoding for size: %s", PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config)) { + NSCAssert(NO, @"Error in nanopb encoding for bytes: %s", PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + return CFBridgingRelease(dataRef); +} + +- (void)dealloc { + pb_release(logs_proto_mobilesdk_ios_ICoreConfiguration_fields, &_config); +} + +@end + +NS_ASSUME_NONNULL_BEGIN + +/** This class produces a protobuf containing diagnostics and usage data to be logged. */ +@interface FIRCoreDiagnostics : NSObject + +/** The queue on which all diagnostics collection will occur. */ +@property(nonatomic, readonly) dispatch_queue_t diagnosticsQueue; + +/** The transport object used to send data. */ +@property(nonatomic, readonly) GDTTransport *transport; + +/** The storage to store the date of the last sent heartbeat. */ +@property(nonatomic, readonly) FIRCoreDiagnosticsDateFileStorage *heartbeatDateStorage; + +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRCoreDiagnostics + ++ (instancetype)sharedInstance { + static FIRCoreDiagnostics *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRCoreDiagnostics alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + GDTTransport *transport = [[GDTTransport alloc] initWithMappingID:@"137" + transformers:nil + target:kGDTTargetCCT]; + + FIRCoreDiagnosticsDateFileStorage *dateStorage = [[FIRCoreDiagnosticsDateFileStorage alloc] + initWithFileURL:[[self class] filePathURLWithName:kFIRCoreDiagnosticsHeartbeatDateFileName]]; + + return [self initWithTransport:transport heartbeatDateStorage:dateStorage]; +} + +/** Initializer for unit tests. + * + * @param transport A `GDTTransport` instance which that be used to send event. + * @param heartbeatDateStorage An instanse of date storage to track heartbeat sending. + * @return Returns the initialized `FIRCoreDiagnostics` instance. + */ +- (instancetype)initWithTransport:(GDTTransport *)transport + heartbeatDateStorage:(FIRCoreDiagnosticsDateFileStorage *)heartbeatDateStorage { + self = [super init]; + if (self) { + _diagnosticsQueue = + dispatch_queue_create("com.google.FIRCoreDiagnostics", DISPATCH_QUEUE_SERIAL); + _transport = transport; + _heartbeatDateStorage = heartbeatDateStorage; + } + return self; +} + +#pragma mark - File path helpers + +/** Returns the URL path of the file with name fileName under the Application Support folder for + * local logging. Creates the Application Support folder if the folder doesn't exist. + * + * @return the URL path of the file with the name fileName in Application Support. + */ ++ (NSURL *)filePathURLWithName:(NSString *)fileName { + @synchronized(self) { + NSArray *paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSArray *components = @[ paths.lastObject, @"Google/FIRApp" ]; + NSString *directoryString = [NSString pathWithComponents:components]; + NSURL *directoryURL = [NSURL fileURLWithPath:directoryString]; + + NSError *error; + if (![directoryURL checkResourceIsReachableAndReturnError:&error]) { + // If fail creating the Application Support directory, return nil. + if (![[NSFileManager defaultManager] createDirectoryAtURL:directoryURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + GULLogWarning(kFIRCoreDiagnostics, YES, @"I-COR100001", + @"Unable to create internal state storage: %@", error); + return nil; + } + } + return [directoryURL URLByAppendingPathComponent:fileName]; + } +} + +#pragma mark - Metadata helpers + +/** Returns the model of iOS device. Sample platform strings are @"iPhone7,1" for iPhone 6 Plus, + * @"iPhone7,2" for iPhone 6, etc. Refer to the Hardware strings at + * https://en.wikipedia.org/wiki/List_of_iOS_devices + * + * @return The device model as an NSString. + */ ++ (NSString *)deviceModel { + static NSString *deviceModel = nil; + if (deviceModel == nil) { + struct utsname systemInfo; + uname(&systemInfo); + deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + } + return deviceModel; +} + +#pragma mark - nanopb helper functions + +/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *FIREncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return FIREncodeData(stringBytes); +} + +/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *FIREncodeData(NSData *data) { + pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + memcpy(pbBytes->bytes, [data bytes], data.length); + pbBytes->size = (pb_size_t)data.length; + return pbBytes; +} + +/** Maps a service string to the representative nanopb enum. + * + * @param serviceString The SDK service string to convert. + * @return The representative nanopb enum. + */ +logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType FIRMapFromServiceStringToTypeEnum( + NSString *serviceString) { + static NSDictionary *serviceStringToTypeEnum; + if (serviceStringToTypeEnum == nil) { + serviceStringToTypeEnum = @{ + kFIRServiceAdMob : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB), + kFIRServiceMessaging : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING), + kFIRServiceMeasurement : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT), + kFIRServiceRemoteConfig : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG), + kFIRServiceDatabase : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE), + kFIRServiceDynamicLinks : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS), + kFIRServiceAuth : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH), + kFIRServiceAuthUI : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI), + kFIRServiceFirestore : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE), + kFIRServiceFunctions : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS), + kFIRServicePerformance : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE), + kFIRServiceStorage : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE), + kFIRServiceMLVisionOnDeviceAutoML : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML), + kFIRServiceMLVisionOnDeviceFace : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE), + kFIRServiceMLVisionOnDeviceBarcode : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE), + kFIRServiceMLVisionOnDeviceText : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT), + kFIRServiceMLVisionOnDeviceLabel : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL), + kFIRServiceMLVisionOnDeviceObjectDetection : @( + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION), + kFIRServiceMLModelInterpreter : + @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER), + kGGLServiceAnalytics : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS), + kGGLServiceSignIn : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN), + kFIRServiceIAM : @(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING), + }; + } + if (serviceStringToTypeEnum[serviceString] != nil) { + return (int32_t)serviceStringToTypeEnum[serviceString].longLongValue; + } + return logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE; +} + +#pragma mark - Proto population functions + +/** Populates the given proto with data related to an SDK logDiagnostics call from the + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithInfoFromUserInfoParams(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + NSNumber *configurationType = diagnosticObjects[kFIRCDConfigurationTypeKey]; + if (configurationType) { + switch (configurationType.integerValue) { + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE; + config->has_configuration_type = 1; + break; + case logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK: + config->configuration_type = + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK; + config->has_configuration_type = 1; + break; + default: + break; + } + } + + NSString *sdkName = diagnosticObjects[kFIRCDSdkNameKey]; + if (sdkName) { + config->sdk_name = FIRMapFromServiceStringToTypeEnum(sdkName); + config->has_sdk_name = 1; + } + + NSString *version = diagnosticObjects[kFIRCDSdkVersionKey]; + if (version) { + config->sdk_version = FIREncodeString(version); + } +} + +/** Populates the given proto with data from the calling FIRApp using the given + * diagnosticObjects dictionary. + * + * @param config The proto to populate + * @param diagnosticObjects The dictionary of diagnostics objects. + */ +void FIRPopulateProtoWithCommonInfoFromApp(logs_proto_mobilesdk_ios_ICoreConfiguration *config, + NSDictionary *diagnosticObjects) { + config->pod_name = logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE; + config->has_pod_name = 1; + + NSCAssert(diagnosticObjects[kFIRCDllAppsCountKey], + @"App count is a required value in the data dict."); + config->app_count = (int32_t)[diagnosticObjects[kFIRCDllAppsCountKey] integerValue]; + config->has_app_count = 1; + + NSString *googleAppID = diagnosticObjects[kFIRCDGoogleAppIDKey]; + if (googleAppID.length) { + config->app_id = FIREncodeString(googleAppID); + } + + NSString *bundleID = diagnosticObjects[kFIRCDBundleIDKey]; + if (bundleID.length) { + config->bundle_id = FIREncodeString(bundleID); + } + + NSString *firebaseUserAgent = diagnosticObjects[kFIRCDFirebaseUserAgentKey]; + if (firebaseUserAgent.length) { + config->platform_info = FIREncodeString(firebaseUserAgent); + } + + NSNumber *usingOptionsFromDefaultPlist = diagnosticObjects[kFIRCDUsingOptionsFromDefaultPlistKey]; + if (usingOptionsFromDefaultPlist) { + config->use_default_app = [usingOptionsFromDefaultPlist boolValue]; + config->has_use_default_app = 1; + } + + NSString *libraryVersionID = diagnosticObjects[kFIRCDLibraryVersionIDKey]; + if (libraryVersionID) { + config->icore_version = FIREncodeString(libraryVersionID); + } + + NSString *deviceModel = [FIRCoreDiagnostics deviceModel]; + if (deviceModel.length) { + config->device_model = FIREncodeString(deviceModel); + } + + NSString *osVersion = [GULAppEnvironmentUtil systemVersion]; + if (osVersion.length) { + config->os_version = FIREncodeString(osVersion); + } + + config->using_zip_file = kUsingZipFile; + config->has_using_zip_file = 1; + config->deployment_type = kDeploymentType; + config->has_deployment_type = 1; + config->deployed_in_app_store = [GULAppEnvironmentUtil isFromAppStore]; + config->has_deployed_in_app_store = 1; +} + +/** Populates the given proto with installed services data. + * + * @param config The proto to populate + */ +void FIRPopulateProtoWithInstalledServices(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSMutableArray *sdkServiceInstalledArray = [NSMutableArray array]; + + // AdMob + if (NSClassFromString(@"GADBannerView") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAdMob))]; + } + // CloudMessaging + if (NSClassFromString(@"FIRMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMessaging))]; + } + // RemoteConfig + if (NSClassFromString(@"FIRRemoteConfig") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceRemoteConfig))]; + } + // Measurement/Analtyics + if (NSClassFromString(@"FIRAnalytics") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMeasurement))]; + } + // ML Vision On Device AutoML. + if (NSClassFromString(@"FIRVisionOnDeviceAutoMLImageLabelerOptions") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceAutoML))]; + } + // ML Vision On Device Face. + if (NSClassFromString(@"FIRVisionFaceDetector") != nil && + NSClassFromString(@"GMVFaceDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceFace))]; + } + // ML Vision On Device Barcode. + if (NSClassFromString(@"FIRVisionBarcodeDetector") != nil && + NSClassFromString(@"GMVBarcodeDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceBarcode))]; + } + // ML Vision On Device Text. + if (NSClassFromString(@"FIRVisionTextDetector") != nil && + NSClassFromString(@"GMVTextDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceText))]; + } + // ML Vision On Device Image Label. + if (NSClassFromString(@"FIRVisionLabelDetector") != nil && + NSClassFromString(@"GMVLabelDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceLabel))]; + } + // ML Vision On Device Object. + if (NSClassFromString(@"FIRVisionObjectDetector") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLVisionOnDeviceObjectDetection))]; + } + // ML Model Interpreter + if (NSClassFromString(@"FIRCustomModelInterpreter") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceMLModelInterpreter))]; + } + // Database + if (NSClassFromString(@"FIRDatabase") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDatabase))]; + } + // DynamicDeepLink + if (NSClassFromString(@"FIRDynamicLinks") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceDynamicLinks))]; + } + // Auth + if (NSClassFromString(@"FIRAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuth))]; + } + // AuthUI + if (NSClassFromString(@"FUIAuth") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceAuthUI))]; + } + // Firestore + if (NSClassFromString(@"FIRFirestore") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFirestore))]; + } + // Functions + if (NSClassFromString(@"FIRFunctions") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceFunctions))]; + } + // Performance + if (NSClassFromString(@"FIRPerformance") != nil) { + [sdkServiceInstalledArray + addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServicePerformance))]; + } + // Storage + if (NSClassFromString(@"FIRStorage") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceStorage))]; + } + // SignIn via Google pod + if (NSClassFromString(@"GIDSignIn") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceSignIn))]; + } + // Analytics via Google pod + if (NSClassFromString(@"GAI") != nil && NSClassFromString(@"GGLContext") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kGGLServiceAnalytics))]; + } + + // In-App Messaging + if (NSClassFromString(@"FIRInAppMessaging") != nil) { + [sdkServiceInstalledArray addObject:@(FIRMapFromServiceStringToTypeEnum(kFIRServiceIAM))]; + } + + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *servicesInstalled = + malloc(sizeof(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType) * + sdkServiceInstalledArray.count); + for (NSUInteger i = 0; i < sdkServiceInstalledArray.count; i++) { + NSNumber *typeEnum = sdkServiceInstalledArray[i]; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType serviceType = + (int32_t)typeEnum.integerValue; + servicesInstalled[i] = serviceType; + } + + config->sdk_service_installed = servicesInstalled; + config->sdk_service_installed_count = (int32_t)sdkServiceInstalledArray.count; +} + +/** Populates the proto with the number of linked frameworks. + * + * @param config The proto to populate. + */ +void FIRPopulateProtoWithNumberOfLinkedFrameworks( + logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + int numFrameworks = -1; // Subtract the app binary itself. + unsigned int numImages; + const char **imageNames = objc_copyImageNames(&numImages); + for (unsigned int i = 0; i < numImages; i++) { + NSString *imageName = [NSString stringWithUTF8String:imageNames[i]]; + if ([imageName rangeOfString:@"System/Library"].length != 0 // Apple .frameworks + || [imageName rangeOfString:@"Developer/Library"].length != 0 // Xcode debug .frameworks + || [imageName rangeOfString:@"usr/lib"].length != 0) { // Public .dylibs + continue; + } + numFrameworks++; + } + free(imageNames); + config->dynamic_framework_count = numFrameworks; + config->has_dynamic_framework_count = 1; +} + +/** Populates the proto with Info.plist values. + * + * @param config The proto to populate. + */ +void FIRPopulateProtoWithInfoPlistValues(logs_proto_mobilesdk_ios_ICoreConfiguration *config) { + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + + NSString *xcodeVersion = info[@"DTXcodeBuild"] ?: @""; + NSString *sdkVersion = info[@"DTSDKBuild"] ?: @""; + NSString *combinedVersions = [NSString stringWithFormat:@"%@-%@", xcodeVersion, sdkVersion]; + config->apple_framework_version = FIREncodeString(combinedVersions); + + NSString *minVersion = info[@"MinimumOSVersion"]; + if (minVersion) { + config->min_supported_ios_version = FIREncodeString(minVersion); + } + + // Apps can turn off swizzling in the Info.plist, check if they've explicitly set the value and + // report it. It's enabled by default. + NSNumber *appDelegateSwizzledNum = info[@"FirebaseAppDelegateProxyEnabled"]; + BOOL appDelegateSwizzled = YES; + if ([appDelegateSwizzledNum isKindOfClass:[NSNumber class]]) { + appDelegateSwizzled = [appDelegateSwizzledNum boolValue]; + } + config->swizzling_enabled = appDelegateSwizzled; + config->has_swizzling_enabled = 1; +} + +#pragma mark - FIRCoreDiagnosticsInterop + ++ (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + FIRCoreDiagnostics *diagnostics = [FIRCoreDiagnostics sharedInstance]; + [diagnostics sendDiagnosticsData:diagnosticsData]; +} + +- (void)sendDiagnosticsData:(nonnull id)diagnosticsData { + dispatch_async(self.diagnosticsQueue, ^{ + NSDictionary *diagnosticObjects = diagnosticsData.diagnosticObjects; + NSNumber *isDataCollectionDefaultEnabled = + diagnosticObjects[kFIRCDIsDataCollectionDefaultEnabledKey]; + if (isDataCollectionDefaultEnabled && ![isDataCollectionDefaultEnabled boolValue]) { + return; + } + + // Create the proto. + logs_proto_mobilesdk_ios_ICoreConfiguration icore_config = + logs_proto_mobilesdk_ios_ICoreConfiguration_init_default; + + icore_config.using_gdt = 1; + icore_config.has_using_gdt = 1; + + // Populate the proto with information. + FIRPopulateProtoWithInfoFromUserInfoParams(&icore_config, diagnosticObjects); + FIRPopulateProtoWithCommonInfoFromApp(&icore_config, diagnosticObjects); + FIRPopulateProtoWithInstalledServices(&icore_config); + FIRPopulateProtoWithNumberOfLinkedFrameworks(&icore_config); + FIRPopulateProtoWithInfoPlistValues(&icore_config); + [self setHeartbeatFlagIfNeededToConfig:&icore_config]; + + // This log object is capable of converting the proto to bytes. + FIRCoreDiagnosticsLog *log = [[FIRCoreDiagnosticsLog alloc] initWithConfig:icore_config]; + + // Send the log as a telemetry event. + GDTEvent *event = [self.transport eventForTransport]; + event.dataObject = (id)log; + [self.transport sendTelemetryEvent:event]; + }); +} + +#pragma mark - Heartbeat + +- (void)setHeartbeatFlagIfNeededToConfig:(logs_proto_mobilesdk_ios_ICoreConfiguration *)config { + // Check if need to send a heartbeat. + NSDate *currentDate = [NSDate date]; + NSDate *lastCheckin = [self.heartbeatDateStorage date]; + if (lastCheckin) { + // Ensure the previous checkin was on a different date in the past. + if ([self isDate:currentDate inSameDayOrBeforeThan:lastCheckin]) { + return; + } + } + + // Update heartbeat sent date. + NSError *error; + if (![self.heartbeatDateStorage setDate:currentDate error:&error]) { + GULLogError(kFIRCoreDiagnostics, NO, @"I-COR100004", @"Unable to persist internal state: %@", + error); + } + + // Set the flag. + config->sdk_name = logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE; +} + +- (BOOL)isDate:(NSDate *)date1 inSameDayOrBeforeThan:(NSDate *)date2 { + return [[NSCalendar currentCalendar] isDate:date1 inSameDayAsDate:date2] || + [date1 compare:date2] == NSOrderedAscending; +} + +@end diff --git a/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h new file mode 100644 index 0000000000..93e406a4da --- /dev/null +++ b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Stores a date to a specified file. +@interface FIRCoreDiagnosticsDateFileStorage : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Default initializer. + * @param fileURL The URL of the file to store the date. The directory must exist, the file may not + * exist, it will be created if needed. + */ +- (instancetype)initWithFileURL:(NSURL *)fileURL; + +/** + * Saves the date to the specified file. + * @return YES on success, NO otherwise. + */ +- (BOOL)setDate:(nullable NSDate *)date error:(NSError **)outError; + +/** + * Reads the date to the specified file. + * @return Returns date if exists, otherwise `nil`. + */ +- (nullable NSDate *)date; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.m b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.m new file mode 100644 index 0000000000..f4dca12a7b --- /dev/null +++ b/Firebase/CoreDiagnostics/FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.m @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import "FIRCDLibrary/FIRCoreDiagnosticsDateFileStorage.h" + +@interface FIRCoreDiagnosticsDateFileStorage () +@property(nonatomic, readonly) NSURL *fileURL; +@end + +@implementation FIRCoreDiagnosticsDateFileStorage + +- (instancetype)initWithFileURL:(NSURL *)fileURL { + if (fileURL == nil) { + return nil; + } + + self = [super init]; + if (self) { + _fileURL = fileURL; + } + + return self; +} + +- (BOOL)setDate:(nullable NSDate *)date error:(NSError **)outError { + NSString *stringToSave = @""; + + if (date != nil) { + NSTimeInterval timestamp = [date timeIntervalSinceReferenceDate]; + stringToSave = [NSString stringWithFormat:@"%f", timestamp]; + } + + return [stringToSave writeToURL:self.fileURL + atomically:YES + encoding:NSUTF8StringEncoding + error:outError]; +} + +- (nullable NSDate *)date { + NSString *timestampString = [NSString stringWithContentsOfURL:self.fileURL + encoding:NSUTF8StringEncoding + error:nil]; + if (timestampString.length == 0) { + return nil; + } + + NSTimeInterval timestamp = timestampString.doubleValue; + return [NSDate dateWithTimeIntervalSinceReferenceDate:timestamp]; +} + +@end diff --git a/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c b/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c new file mode 100644 index 0000000000..3c35ffb1d6 --- /dev/null +++ b/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.c @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.2 */ + +#include "firebasecore.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, logs_proto_mobilesdk_ios_ICoreConfiguration, configuration_type, configuration_type, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, version_name, configuration_type, 0), + PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_number, version_name, 0), + PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, build_type, build_number, 0), + PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, plist_version, build_type, 0), + PB_FIELD( 6, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_enabled, plist_version, 0), + PB_FIELD( 7, UENUM , REPEATED, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_service_installed, sdk_service_enabled, 0), + PB_FIELD( 9, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, device_model, sdk_service_installed, 0), + PB_FIELD( 10, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_id, device_model, 0), + PB_FIELD( 11, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, project_number, app_id, 0), + PB_FIELD( 12, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, bundle_id, project_number, 0), + PB_FIELD( 13, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, client_id, bundle_id, 0), + PB_FIELD( 14, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, install, client_id, 0), + PB_FIELD( 16, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, pod_name, install, 0), + PB_FIELD( 18, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, icore_version, pod_name, 0), + PB_FIELD( 19, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_version, icore_version, 0), + PB_FIELD( 20, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, sdk_name, sdk_version, 0), + PB_FIELD( 21, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_count, sdk_name, 0), + PB_FIELD( 22, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, os_version, app_count, 0), + PB_FIELD( 23, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, itunes_id, os_version, 0), + PB_FIELD( 24, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, min_supported_ios_version, itunes_id, 0), + PB_FIELD( 25, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, use_default_app, min_supported_ios_version, 0), + PB_FIELD( 26, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployed_in_app_store, use_default_app, 0), + PB_FIELD( 27, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, dynamic_framework_count, deployed_in_app_store, 0), + PB_FIELD( 28, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, apple_framework_version, dynamic_framework_count, 0), + PB_FIELD( 29, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_zip_file, apple_framework_version, 0), + PB_FIELD( 30, UENUM , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, deployment_type, using_zip_file, 0), + PB_FIELD( 31, BYTES , OPTIONAL, POINTER , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, platform_info, deployment_type, 0), + PB_FIELD( 32, INT64 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, app_extensions, platform_info, 0), + PB_FIELD( 33, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, swizzling_enabled, app_extensions, 0), + PB_FIELD( 34, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_error_count, swizzling_enabled, 0), + PB_FIELD( 35, INT32 , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, log_warning_count, log_error_count, 0), + PB_FIELD( 36, BOOL , OPTIONAL, STATIC , OTHER, logs_proto_mobilesdk_ios_ICoreConfiguration, using_gdt, log_warning_count, 0), + PB_LAST_FIELD +}; + + + + + + + +/* @@protoc_insertion_point(eof) */ diff --git a/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h b/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h new file mode 100644 index 0000000000..41059e5d96 --- /dev/null +++ b/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb/firebasecore.nanopb.h @@ -0,0 +1,224 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.2 */ + +#ifndef PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#define PB_LOGS_PROTO_MOBILESDK_IOS_FIREBASECORE_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_CORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_UNKNOWN_CONFIGURATION_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_SDK+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType { + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_INTERNAL = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_EAP = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD = 3 +} logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_UNKNOWN_BUILD_TYPE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType)(logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_PROD+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType { + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ICORE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ADMOB = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INVITE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SIGN_IN = 5, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_GCM = 6, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAPS = 7, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_SCION = 8, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ANALYTICS = 9, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_APP_INDEXING = 10, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CONFIG = 11, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DURABLE_DEEP_LINKS = 12, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_CRASH = 13, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH = 14, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DATABASE = 15, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_STORAGE = 16, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MESSAGING = 17, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MEASUREMENT = 18, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_REMOTE_CONFIG = 19, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_DYNAMIC_LINKS = 20, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_INVITES = 21, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_AUTH_UI = 22, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FIRESTORE = 23, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_PERFORMANCE = 24, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_FACE = 26, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_BARCODE = 27, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_TEXT = 28, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_LABEL = 29, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_MODEL_INTERPRETER = 30, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_IN_APP_MESSAGING = 31, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_FUNCTIONS = 32, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_NATURAL_LANGUAGE = 33, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_AUTOML = 34, + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION = 35 +} logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_UNKNOWN_SDK_SERVICE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType)(logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_ML_VISION_ON_DEVICE_OBJECT_DETECTION+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName { + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_GOOGLE = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE = 2 +} logs_proto_mobilesdk_ios_ICoreConfiguration_PodName; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_UNKNOWN_POD_NAME +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_PodName)(logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_FIREBASE+1)) + +typedef enum _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType { + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN = 0, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_COCOAPODS = 1, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ZIP_FILE = 2, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_CARTHAGE = 3, + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM = 4 +} logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType; +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_UNKNOWN +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MAX logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM +#define _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_ARRAYSIZE ((logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType)(logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_SPM+1)) + +/* Struct definitions */ +typedef struct _logs_proto_mobilesdk_ios_ICoreConfiguration { + bool has_configuration_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType configuration_type; + pb_bytes_array_t *version_name; + bool has_build_number; + int64_t build_number; + bool has_build_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType build_type; + pb_bytes_array_t *plist_version; + pb_size_t sdk_service_enabled_count; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_enabled; + pb_size_t sdk_service_installed_count; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType *sdk_service_installed; + pb_bytes_array_t *device_model; + pb_bytes_array_t *app_id; + bool has_project_number; + int64_t project_number; + pb_bytes_array_t *bundle_id; + pb_bytes_array_t *client_id; + pb_bytes_array_t *install; + bool has_pod_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_PodName pod_name; + pb_bytes_array_t *icore_version; + pb_bytes_array_t *sdk_version; + bool has_sdk_name; + logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType sdk_name; + bool has_app_count; + int32_t app_count; + pb_bytes_array_t *os_version; + pb_bytes_array_t *itunes_id; + pb_bytes_array_t *min_supported_ios_version; + bool has_use_default_app; + bool use_default_app; + bool has_deployed_in_app_store; + bool deployed_in_app_store; + bool has_dynamic_framework_count; + int32_t dynamic_framework_count; + pb_bytes_array_t *apple_framework_version; + bool has_using_zip_file; + bool using_zip_file; + bool has_deployment_type; + logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType deployment_type; + pb_bytes_array_t *platform_info; + bool has_app_extensions; + int64_t app_extensions; + bool has_swizzling_enabled; + bool swizzling_enabled; + bool has_log_error_count; + int32_t log_error_count; + bool has_log_warning_count; + int32_t log_warning_count; + bool has_using_gdt; + bool using_gdt; +/* @@protoc_insertion_point(struct:logs_proto_mobilesdk_ios_ICoreConfiguration) */ +} logs_proto_mobilesdk_ios_ICoreConfiguration; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_default {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0} +#define logs_proto_mobilesdk_ios_ICoreConfiguration_init_zero {false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ConfigurationType_MIN, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_BuildType_MIN, NULL, 0, NULL, 0, NULL, NULL, NULL, false, 0, NULL, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_PodName_MIN, NULL, NULL, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_ServiceType_MIN, false, 0, NULL, NULL, NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, _logs_proto_mobilesdk_ios_ICoreConfiguration_DeploymentType_MIN, NULL, false, 0, false, 0, false, 0, false, 0, false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define logs_proto_mobilesdk_ios_ICoreConfiguration_pod_name_tag 16 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_configuration_type_tag 1 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_version_name_tag 2 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_icore_version_tag 18 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_version_tag 19 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_number_tag 3 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_build_type_tag 4 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_plist_version_tag 5 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_enabled_tag 6 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_service_installed_tag 7 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_sdk_name_tag 20 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_device_model_tag 9 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_os_version_tag 22 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_id_tag 10 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_project_number_tag 11 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_bundle_id_tag 12 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_client_id_tag 13 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_itunes_id_tag 23 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_min_supported_ios_version_tag 24 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_install_tag 14 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_use_default_app_tag 25 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_count_tag 21 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployed_in_app_store_tag 26 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_dynamic_framework_count_tag 27 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_apple_framework_version_tag 28 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_zip_file_tag 29 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_deployment_type_tag 30 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_platform_info_tag 31 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_app_extensions_tag 32 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_swizzling_enabled_tag 33 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_error_count_tag 34 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_log_warning_count_tag 35 +#define logs_proto_mobilesdk_ios_ICoreConfiguration_using_gdt_tag 36 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t logs_proto_mobilesdk_ios_ICoreConfiguration_fields[34]; + +/* Maximum encoded size of messages (where known) */ +/* logs_proto_mobilesdk_ios_ICoreConfiguration_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define FIREBASECORE_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.options b/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.options new file mode 100644 index 0000000000..908c8e6c4b --- /dev/null +++ b/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.options @@ -0,0 +1,35 @@ +# Copyright 2019 Google +# +# 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. +# + +# Options for firebasecore.proto + +logs.proto.mobilesdk.ios.ICoreConfiguration.version_name type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.plist_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.sdk_service_enabled type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.sdk_service_installed type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.device_model type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.app_id type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.bundle_id type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.client_id type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.install type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.icore_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.sdk_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.os_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.itunes_id type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.min_supported_ios_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.apple_framework_version type:FT_POINTER +logs.proto.mobilesdk.ios.ICoreConfiguration.platform_info type:FT_POINTER + + diff --git a/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.proto b/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.proto new file mode 100644 index 0000000000..c89e098551 --- /dev/null +++ b/Firebase/CoreDiagnostics/ProtoSupport/Protos/firebasecore.proto @@ -0,0 +1,103 @@ +syntax = "proto2"; + +package logs.proto.mobilesdk.ios; + +message ICoreConfiguration { + enum ConfigurationType { + UNKNOWN_CONFIGURATION_TYPE = 0; + CORE = 1; + SDK = 2; + } + enum BuildType { + UNKNOWN_BUILD_TYPE = 0; + INTERNAL = 1; + EAP = 2; + PROD = 3; + } + enum ServiceType { + UNKNOWN_SDK_SERVICE = 0; + ICORE = 1; + ADMOB = 2; + APP_INVITE = 3; + SIGN_IN = 5; + GCM = 6 [deprecated = true]; + MAPS = 7; + SCION = 8 [deprecated = true]; + ANALYTICS = 9; + APP_INDEXING = 10; + CONFIG = 11 [deprecated = true]; + DURABLE_DEEP_LINKS = 12 [deprecated = true]; + CRASH = 13; + AUTH = 14; + DATABASE = 15; + STORAGE = 16; + MESSAGING = 17; + MEASUREMENT = 18; + REMOTE_CONFIG = 19; + DYNAMIC_LINKS = 20; + INVITES = 21; + AUTH_UI = 22; + FIRESTORE = 23; + PERFORMANCE = 24; + ML_VISION_ON_DEVICE_FACE = 26; + ML_VISION_ON_DEVICE_BARCODE = 27; + ML_VISION_ON_DEVICE_TEXT = 28; + ML_VISION_ON_DEVICE_LABEL = 29; + ML_MODEL_INTERPRETER = 30; + IN_APP_MESSAGING = 31; + FUNCTIONS = 32; + ML_NATURAL_LANGUAGE = 33; + ML_VISION_ON_DEVICE_AUTOML = 34; + ML_VISION_ON_DEVICE_OBJECT_DETECTION = 35; + } + enum PodName { + UNKNOWN_POD_NAME = 0; + GOOGLE = 1; + FIREBASE = 2; + } + enum DeploymentType { + UNKNOWN = 0; + COCOAPODS = 1; + ZIP_FILE = 2; + CARTHAGE = 3; + SPM = 4; + } + optional .logs.proto.mobilesdk.ios.ICoreConfiguration.PodName pod_name = 16; + optional .logs.proto.mobilesdk.ios.ICoreConfiguration.ConfigurationType + configuration_type = 1; + optional string version_name = 2; + optional string icore_version = 18; + optional string sdk_version = 19; + optional int64 build_number = 3; + optional .logs.proto.mobilesdk.ios.ICoreConfiguration.BuildType build_type = + 4; + optional string plist_version = 5; + repeated .logs.proto.mobilesdk.ios.ICoreConfiguration.ServiceType + sdk_service_enabled = 6; + repeated .logs.proto.mobilesdk.ios.ICoreConfiguration.ServiceType + sdk_service_installed = 7; + optional .logs.proto.mobilesdk.ios.ICoreConfiguration.ServiceType sdk_name = + 20; + optional string device_model = 9; + optional string os_version = 22; + optional string app_id = 10; + optional int64 project_number = 11; + optional string bundle_id = 12; + optional string client_id = 13; + optional string itunes_id = 23; + optional string min_supported_ios_version = 24; + optional string install = 14; + optional bool use_default_app = 25; + optional int32 app_count = 21; + optional bool deployed_in_app_store = 26; + optional int32 dynamic_framework_count = 27; + optional string apple_framework_version = 28; + optional bool using_zip_file = 29; + optional DeploymentType deployment_type = 30; + optional string platform_info = 31; + optional int64 app_extensions = 32; + optional bool swizzling_enabled = 33; + optional int32 log_error_count = 34; + optional int32 log_warning_count = 35; + optional bool using_gdt = 36; +} diff --git a/Firebase/CoreDiagnostics/ProtoSupport/generate_nanopb_protos.sh b/Firebase/CoreDiagnostics/ProtoSupport/generate_nanopb_protos.sh new file mode 100755 index 0000000000..f5df11530a --- /dev/null +++ b/Firebase/CoreDiagnostics/ProtoSupport/generate_nanopb_protos.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Copyright 2019 Google +# +# 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. +# + +# Example usage: +# ./build_protos + +# Dependencies: git, protobuf, python-protobuf, pyinstaller + +readonly REPO_DIR="$( git rev-parse --show-toplevel )" + +# Current release of nanopb being used to build the CCT protos +readonly NANOPB_VERSION="0.3.9.2" +readonly NANOPB_TEMPDIR="$(mktemp -d)" + +readonly LIBRARY_DIR="${REPO_DIR}/Firebase/CoreDiagnostics/FIRCDLibrary" +readonly PROTO_DIR="${REPO_DIR}/Firebase/CoreDiagnostics/ProtoSupport/Protos/" +readonly PROTOGEN_DIR="${REPO_DIR}/Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/" + +rm -rf "${NANOPB_TEMPDIR}" + +echo "Downloading nanopb..." +git clone --branch "${NANOPB_VERSION}" https://github.com/nanopb/nanopb.git "${NANOPB_TEMPDIR}" + +echo "Building nanopb..." +pushd "${NANOPB_TEMPDIR}" +./tools/make_mac_package.sh +GIT_DESCRIPTION=`git describe --always`-macosx-x86 +NANOPB_BIN_DIR="dist/${GIT_DESCRIPTION}" +popd + +echo "Removing existing generated protos..." +rm -rf "${PROTOGEN_DIR}/*" + +echo "Generating nanopb protos..." +python "${REPO_DIR}/Firebase/CoreDiagnostics/ProtoSupport/nanopb_build_protos.py" \ + --nanopb \ + --protos_dir="${PROTO_DIR}" \ + --pythonpath="${NANOPB_TEMPDIR}/${NANOPB_BIN_DIR}/generator" \ + --output_dir="${PROTOGEN_DIR}" \ + --include="${PROTO_DIR}" + +rm -rf "${NANOPB_TEMPDIR}" \ No newline at end of file diff --git a/Firebase/CoreDiagnostics/ProtoSupport/nanopb_build_protos.py b/Firebase/CoreDiagnostics/ProtoSupport/nanopb_build_protos.py new file mode 100644 index 0000000000..81bd1d549e --- /dev/null +++ b/Firebase/CoreDiagnostics/ProtoSupport/nanopb_build_protos.py @@ -0,0 +1,323 @@ +#! /usr/bin/env python + +# Copyright 2019 Google +# +# 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. + +"""Builds nanopb protos by calling a proto generator wrapper. + +Example usage: + +python Firebase/Core/nanopb_build_protos.py \ + --nanopb \ + --protos_dir=Firebase/Core/Protos/ \ + --pythonpath=Firebase/Core/nanopb_temp/generator/ \ + --output_dir=Firebase/Core/Protos/ +""" + +from __future__ import print_function + +import sys + +import argparse +import os +import os.path +import re +import subprocess + +OBJC_GENERATOR='nanopb_proto_generator.py' + +COPYRIGHT_NOTICE = ''' +/* + * Copyright 2019 Google + * + * 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. + */ +'''.lstrip() + + +def main(): + parser = argparse.ArgumentParser( + description='Generates proto messages.') + parser.add_argument( + '--nanopb', action='store_true', + help='Generates nanopb messages.') + parser.add_argument( + '--objc', action='store_true', + help='Generates Objective-C messages.') + parser.add_argument( + '--protos_dir', + help='Source directory containing .proto files.') + parser.add_argument( + '--output_dir', '-d', + help='Directory to write files; subdirectories will be created.') + parser.add_argument( + '--protoc', default='protoc', + help='Location of the protoc executable') + parser.add_argument( + '--pythonpath', + help='Location of the protoc python library.') + parser.add_argument( + '--include', '-I', action='append', default=[], + help='Adds INCLUDE to the proto path.') + + + args = parser.parse_args() + if args.nanopb is None and args.objc is None: + parser.print_help() + sys.exit(1) + + if args.protos_dir is None: + root_dir = os.path.abspath(os.path.dirname(__file__)) + args.protos_dir = os.path.join(root_dir, 'protos') + + if args.output_dir is None: + root_dir = os.path.abspath(os.path.dirname(__file__)) + args.output_dir = os.path.join(root_dir, 'protogen-please-supply-an-outputdir') + + all_proto_files = collect_files(args.protos_dir, '.proto') + if args.nanopb: + NanopbGenerator(args, all_proto_files).run() + + proto_files = remove_well_known_protos(all_proto_files) + + if args.objc: + ObjcProtobufGenerator(args, proto_files).run() + + +class NanopbGenerator(object): + """Builds and runs the nanopb plugin to protoc.""" + + def __init__(self, args, proto_files): + self.args = args + self.proto_files = proto_files + + def run(self): + """Performs the action of the generator.""" + + nanopb_out = os.path.join(self.args.output_dir, 'nanopb') + mkdir(nanopb_out) + + self.__run_generator(nanopb_out) + + sources = collect_files(nanopb_out, '.nanopb.h', '.nanopb.c') + post_process_files( + sources, + add_copyright, + nanopb_remove_extern_c, + nanopb_rename_delete, + nanopb_use_module_import + ) + + def __run_generator(self, out_dir): + """Invokes protoc using the nanopb plugin.""" + cmd = protoc_command(self.args) + + gen = os.path.join(os.path.dirname(__file__), OBJC_GENERATOR) + cmd.append('--plugin=protoc-gen-nanopb=%s' % gen) + + nanopb_flags = [ + '--extension=.nanopb', + '--source-extension=.c', + '--no-timestamp' + ] + nanopb_flags.extend(['-I%s' % path for path in self.args.include]) + cmd.append('--nanopb_out=%s:%s' % (' '.join(nanopb_flags), out_dir)) + + cmd.extend(self.proto_files) + run_protoc(self.args, cmd) + + +def protoc_command(args): + """Composes the initial protoc command-line including its include path.""" + cmd = [args.protoc] + if args.include is not None: + cmd.extend(['-I=%s' % path for path in args.include]) + return cmd + + +def run_protoc(args, cmd): + """Actually runs the given protoc command. + + Args: + args: The command-line args (including pythonpath) + cmd: The command to run expressed as a list of strings + """ + + kwargs = {} + if args.pythonpath: + env = os.environ.copy() + old_path = env.get('PYTHONPATH') + env['PYTHONPATH'] = os.path.expanduser(args.pythonpath) + if old_path is not None: + env['PYTHONPATH'] += os.pathsep + old_path + kwargs['env'] = env + + try: + print(subprocess.check_output(cmd, stderr=subprocess.STDOUT, **kwargs)) + except subprocess.CalledProcessError as error: + print('command failed: ', ' '.join(cmd), '\nerror: ', error.output) + + +def remove_well_known_protos(filenames): + """Remove "well-known" protos for objc. + + On those platforms we get these for free as a part of the protobuf runtime. + We only need them for nanopb. + + Args: + filenames: A list of filenames, each naming a .proto file. + + Returns: + The filenames with members of google/protobuf removed. + """ + + return [f for f in filenames if 'protos/google/protobuf/' not in f] + + +def post_process_files(filenames, *processors): + for filename in filenames: + lines = [] + with open(filename, 'r') as fd: + lines = fd.readlines() + + for processor in processors: + lines = processor(lines) + + write_file(filename, lines) + + +def write_file(filename, lines): + mkdir(os.path.dirname(filename)) + with open(filename, 'w') as fd: + fd.write(''.join(lines)) + + +def add_copyright(lines): + """Adds a copyright notice to the lines.""" + result = [COPYRIGHT_NOTICE, '\n'] + result.extend(lines) + return result + + +def nanopb_remove_extern_c(lines): + """Removes extern "C" directives from nanopb code. + + Args: + lines: A nanobp-generated source file, split into lines. + Returns: + A list of strings, similar to the input but modified to remove extern "C". + """ + result = [] + state = 'initial' + for line in lines: + if state == 'initial': + if '#ifdef __cplusplus' in line: + state = 'in-ifdef' + continue + + result.append(line) + + elif state == 'in-ifdef': + if '#endif' in line: + state = 'initial' + + return result + + +def nanopb_rename_delete(lines): + """Renames a delete symbol to delete_. + + If a proto uses a field named 'delete', nanopb happily uses that in the + message definition. Works fine for C; not so much for C++. + + Args: + lines: The lines to fix. + + Returns: + The lines, fixed. + """ + delete_keyword = re.compile(r'\bdelete\b') + return [delete_keyword.sub('delete_', line) for line in lines] + + +def nanopb_use_module_import(lines): + """Changes #include to include """ # Don't let Copybara alter these lines. + return [line.replace('#include ', '{}include '.format("#")) for line in lines] + + +def strip_trailing_whitespace(lines): + """Removes trailing whitespace from the given lines.""" + return [line.rstrip() + '\n' for line in lines] + + +def objc_flatten_imports(lines): + """Flattens the import statements for compatibility with CocoaPods.""" + + long_import = re.compile(r'#import ".*/') + return [long_import.sub('#import "', line) for line in lines] + + +def objc_strip_extension_registry(lines): + """Removes extensionRegistry methods from the classes.""" + skip = False + result = [] + for line in lines: + if '+ (GPBExtensionRegistry*)extensionRegistry {' in line: + skip = True + if not skip: + result.append(line) + elif line == '}\n': + skip = False + + return result + + +def collect_files(root_dir, *extensions): + """Finds files with the given extensions in the root_dir. + + Args: + root_dir: The directory from which to start traversing. + *extensions: Filename extensions (including the leading dot) to find. + + Returns: + A list of filenames, all starting with root_dir, that have one of the given + extensions. + """ + result = [] + for root, _, files in os.walk(root_dir): + for basename in files: + for ext in extensions: + if basename.endswith(ext): + filename = os.path.join(root, basename) + result.append(filename) + return result + + +def mkdir(dirname): + if not os.path.isdir(dirname): + os.makedirs(dirname) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Firebase/CoreDiagnostics/ProtoSupport/nanopb_proto_generator.py b/Firebase/CoreDiagnostics/ProtoSupport/nanopb_proto_generator.py new file mode 100755 index 0000000000..be45156649 --- /dev/null +++ b/Firebase/CoreDiagnostics/ProtoSupport/nanopb_proto_generator.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# Copyright 2019 Google +# +# 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. + +"""Generates and massages protocol buffer outputs. +""" + +from __future__ import print_function + +import sys + +import io +import nanopb_generator as nanopb +import os +import os.path +import shlex + +from google.protobuf.descriptor_pb2 import FieldDescriptorProto + +# The plugin_pb2 package loads descriptors on import, but doesn't defend +# against multiple imports. Reuse the plugin package as loaded by the +# nanopb_generator. +plugin_pb2 = nanopb.plugin_pb2 +nanopb_pb2 = nanopb.nanopb_pb2 + + +def main(): + # Parse request + data = io.open(sys.stdin.fileno(), 'rb').read() + request = plugin_pb2.CodeGeneratorRequest.FromString(data) + + # Preprocess inputs, changing types and nanopb defaults + options = nanopb_parse_options(request) + use_anonymous_oneof(request) + use_bytes_for_strings(request) + + # Generate code + parsed_files = nanopb_parse_files(request, options) + results = nanopb_generate(request, options, parsed_files) + response = nanopb_write(results) + + # Write to stdout + io.open(sys.stdout.fileno(), 'wb').write(response.SerializeToString()) + + +def use_anonymous_oneof(request): + """Use anonymous unions for oneofs if they're the only one in a message. + + Equivalent to setting this option on messages where it applies: + + option (nanopb).anonymous_oneof = true; + + Args: + request: A CodeGeneratorRequest from protoc. The descriptors are modified + in place. + """ + for _, message_type in iterate_messages(request): + if len(message_type.oneof_decl) == 1: + ext = message_type.options.Extensions[nanopb_pb2.nanopb_msgopt] + ext.anonymous_oneof = True + + +def use_bytes_for_strings(request): + """Always use the bytes type instead of string. + + By default, nanopb renders proto strings as having the C type char* and does + not include a separate size field, getting the length of the string via + strlen(). Unfortunately this prevents using strings with embedded nulls, + which is something the wire format supports. + + Fortunately, string and bytes proto fields are identical on the wire and + nanopb's bytes representation does have an explicit length, so this function + changes the types of all string fields to bytes. The generated code will now + contain pb_bytes_array_t. + + There's no nanopb or proto option to control this behavior. The equivalent + would be to hand edit all the .proto files :-(. + + Args: + request: A CodeGeneratorRequest from protoc. The descriptors are modified + in place. + """ + for names, message_type in iterate_messages(request): + for field in message_type.field: + if field.type == FieldDescriptorProto.TYPE_STRING: + field.type = FieldDescriptorProto.TYPE_BYTES + + +def iterate_messages(request): + """Iterates over all messages in all files in the request. + + Args: + request: A CodeGeneratorRequest passed by protoc. + + Yields: + names: a nanopb.Names object giving a qualified name for the message + message_type: a DescriptorProto for the message. + """ + for fdesc in request.proto_file: + for names, message_type in nanopb.iterate_messages(fdesc): + yield names, message_type + + +def nanopb_parse_options(request): + """Parses nanopb_generator command-line options from the given request. + + Args: + request: A CodeGeneratorRequest passed by protoc. + + Returns: + Nanopb's options object, obtained via optparser. + """ + # Parse options the same as nanopb_generator.main_plugin() does. + args = shlex.split(request.parameter) + options, _ = nanopb.optparser.parse_args(args) + + # Force certain options + options.extension = '.nanopb' + options.verbose = True + + # Replicate options setup from nanopb_generator.main_plugin. + nanopb.Globals.verbose_options = options.verbose + + # Google's protoc does not currently indicate the full path of proto files. + # Instead always add the main file path to the search dirs, that works for + # the common case. + options.options_path.append(os.path.dirname(request.file_to_generate[0])) + return options + + +def nanopb_parse_files(request, options): + """Parses the files in the given request into nanopb ProtoFile objects. + + Args: + request: A CodeGeneratorRequest, as passed by protoc. + options: The command-line options from nanopb_parse_options. + + Returns: + A dictionary of filename to nanopb.ProtoFile objects, each one representing + the parsed form of a FileDescriptor in the request. + """ + # Process any include files first, in order to have them + # available as dependencies + parsed_files = {} + for fdesc in request.proto_file: + parsed_files[fdesc.name] = nanopb.parse_file(fdesc.name, fdesc, options) + + return parsed_files + + +def nanopb_generate(request, options, parsed_files): + """Generates C sources from the given parsed files. + + Args: + request: A CodeGeneratorRequest, as passed by protoc. + options: The command-line options from nanopb_parse_options. + parsed_files: A dictionary of filename to nanopb.ProtoFile, as returned by + nanopb_parse_files(). + + Returns: + A list of nanopb output dictionaries, each one representing the code + generation result for each file to generate. The output dictionaries have + the following form: + + { + 'headername': Name of header file, ending in .h, + 'headerdata': Contents of the header file, + 'sourcename': Name of the source code file, ending in .c, + 'sourcedata': Contents of the source code file + } + """ + output = [] + + for filename in request.file_to_generate: + for fdesc in request.proto_file: + if fdesc.name == filename: + results = nanopb.process_file(filename, fdesc, options, parsed_files) + output.append(results) + + return output + + +def nanopb_write(results): + """Translates nanopb output dictionaries to a CodeGeneratorResponse. + + Args: + results: A list of generated source dictionaries, as returned by + nanopb_generate(). + + Returns: + A CodeGeneratorResponse describing the result of the code generation + process to protoc. + """ + response = plugin_pb2.CodeGeneratorResponse() + + for result in results: + f = response.file.add() + f.name = result['headername'] + f.content = result['headerdata'] + + f = response.file.add() + f.name = result['sourcename'] + f.content = result['sourcedata'] + + return response + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/Firebase/CoreDiagnostics/generate_project.sh b/Firebase/CoreDiagnostics/generate_project.sh new file mode 100755 index 0000000000..bf63dd7744 --- /dev/null +++ b/Firebase/CoreDiagnostics/generate_project.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright 2018 Google +# +# 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. +# + +readonly REPO_DIR="$( git rev-parse --show-toplevel )" + +"$REPO_DIR/Firebase/CoreDiagnostics/ProtoSupport/generate_nanopb_protos.sh" || { + echo "Something went wrong generating protos." + exit 1 +} + +pod gen "${REPO_DIR}/FirebaseCoreDiagnostics.podspec" --auto-open --gen-directory="${REPO_DIR}/gen" --local-sources="${REPO_DIR}/" --clean diff --git a/Firebase/DynamicLinks/FIRDynamicLinks.m b/Firebase/DynamicLinks/FIRDynamicLinks.m index bd989323c7..af0db47909 100644 --- a/Firebase/DynamicLinks/FIRDynamicLinks.m +++ b/Firebase/DynamicLinks/FIRDynamicLinks.m @@ -190,7 +190,7 @@ static const NSInteger FIRErrorCodeDurableDeepLinkFailed = -119; error = [FIRApp errorForSubspecConfigurationFailureWithDomain:kFirebaseDurableDeepLinkErrorDomain errorCode:FIRErrorCodeDurableDeepLinkFailed - service:kFIRServiceDynamicLinks + service:@"DynamicLinks" reason:errorDescription]; } if (error) { diff --git a/Firebase/InAppMessaging/FIRCore+InAppMessaging.h b/Firebase/InAppMessaging/FIRCore+InAppMessaging.h index e38593b26a..a132e037db 100644 --- a/Firebase/InAppMessaging/FIRCore+InAppMessaging.h +++ b/Firebase/InAppMessaging/FIRCore+InAppMessaging.h @@ -26,9 +26,6 @@ extern FIRLoggerService kFIRLoggerInAppMessaging; // this should eventually be in FIRError.h extern NSString *const kFirebaseInAppMessagingErrorDomain; -// this should eventually be in FIRError.h FIRAppInternal.h:46: -extern NSString *const kFIRServiceInAppMessaging; - // InAppMessaging doesn't provide any functionality to other components, // so it provides a private, empty protocol that it conforms to and use it for registration. diff --git a/Firebase/InAppMessaging/FIRCore+InAppMessaging.m b/Firebase/InAppMessaging/FIRCore+InAppMessaging.m index 219c48bedf..9f4260f839 100644 --- a/Firebase/InAppMessaging/FIRCore+InAppMessaging.m +++ b/Firebase/InAppMessaging/FIRCore+InAppMessaging.m @@ -17,6 +17,5 @@ #import #import "FIRCore+InAppMessaging.h" -NSString *const kFIRServiceInAppMessaging = @"InAppMessaging"; NSString *const kFirebaseInAppMessagingErrorDomain = @"com.firebase.inappmessaging"; FIRLoggerService kFIRLoggerInAppMessaging = @"[Firebase/InAppMessaging]"; diff --git a/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.h b/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.h index 6e18a9a503..2475dbe465 100644 --- a/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.h +++ b/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.h @@ -24,6 +24,3 @@ extern FIRLoggerService kFIRLoggerInAppMessagingDisplay; // this should eventually be in FIRError.h extern NSString *const kFirebaseInAppMessagingDisplayErrorDomain; - -// this should eventually be in FIRError.h FIRAppInternal.h:46: -extern NSString *const kFIRServiceInAppMessagingDisplay; diff --git a/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.m b/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.m index 6f6dcc3de8..fc2ae40990 100644 --- a/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.m +++ b/Firebase/InAppMessagingDisplay/FIRCore+InAppMessagingDisplay.m @@ -17,6 +17,5 @@ #import #import "FIRCore+InAppMessagingDisplay.h" -NSString *const kFIRServiceInAppMessagingDisplay = @"InAppMessagingDisplay"; NSString *const kFirebaseInAppMessagingDisplayErrorDomain = @"com.firebase.inappmessaging.display"; FIRLoggerService kFIRLoggerInAppMessagingDisplay = @"[Firebase/InAppMessagingDisplay]"; diff --git a/FirebaseCore.podspec b/FirebaseCore.podspec index 1436b1b1e9..272a0ff618 100644 --- a/FirebaseCore.podspec +++ b/FirebaseCore.podspec @@ -28,8 +28,11 @@ Firebase Core includes FIRApp and FIROptions which provide central configuration s.public_header_files = 'Firebase/Core/Public/*.h', 'Firebase/Core/Private/*.h' s.private_header_files = 'Firebase/Core/Private/*.h' s.framework = 'Foundation' - s.dependency 'GoogleUtilities/Environment', '~> 6.0' - s.dependency 'GoogleUtilities/Logger', '~> 6.0' + s.dependency 'GoogleUtilities/Environment', '~> 6.2' + s.dependency 'GoogleUtilities/Logger', '~> 6.2' + s.dependency 'FirebaseCoreDiagnosticsInterop', '~> 0.1' + s.dependency 'FirebaseCoreDiagnostics', '~> 0.1' + s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => diff --git a/FirebaseCoreDiagnostics.podspec b/FirebaseCoreDiagnostics.podspec new file mode 100644 index 0000000000..ebaa2fce73 --- /dev/null +++ b/FirebaseCoreDiagnostics.podspec @@ -0,0 +1,58 @@ +Pod::Spec.new do |s| + s.name = 'FirebaseCoreDiagnostics' + s.version = '0.1.0' + s.summary = 'Firebase Core Diagnostics' + + s.description = <<-DESC +Firebase Core Diagnostics collects diagnostic data to help improve and provide Firebase services. +This SDK is integrated using a 'soft-link' mechanism and the bits be omitted by using a +non-Cocoapod integration. This library also respects the Firebase global data collection flag. + DESC + + s.homepage = 'https://firebase.google.com' + s.license = { :type => 'Apache', :file => 'LICENSE' } + s.authors = 'Google, Inc.' + + s.source = { + :git => 'https://github.com/firebase/firebase-ios-sdk.git', + :tag => 'CoreDiagnostics-' + s.version.to_s + } + s.social_media_url = 'https://twitter.com/Firebase' + s.ios.deployment_target = '8.0' + s.osx.deployment_target = '10.11' + s.tvos.deployment_target = '10.0' + + s.cocoapods_version = '>= 1.4.0' + s.static_framework = true + s.prefix_header_file = false + + header_search_paths = { + 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}/Firebase/CoreDiagnostics/"' + } + + s.pod_target_xcconfig = { + 'GCC_C_LANGUAGE_STANDARD' => 'c99', + 'GCC_TREAT_WARNINGS_AS_ERRORS' => 'YES', + 'CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY' => 'YES', + 'GCC_PREPROCESSOR_DEFINITIONS' => + # The nanopb pod sets these defs, so we must too. (We *do* require 16bit + # (or larger) fields, so we'd have to set at least PB_FIELD_16BIT + # anyways.) + 'PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1', + }.merge(header_search_paths) + + s.source_files = 'Firebase/CoreDiagnostics/FIRCDLibrary/**/*.[cmh]' + s.framework = 'Foundation' + + s.dependency 'FirebaseCoreDiagnosticsInterop', '~> 0.1' + s.dependency 'GoogleDataTransportCCTSupport', '~> 0.1' + s.dependency 'GoogleUtilities/Environment', '~> 6.2' + s.dependency 'GoogleUtilities/Logger', '~> 6.2' + + s.test_spec 'unit' do |unit_tests| + unit_tests.dependency 'GoogleUtilities/UserDefaults', '~> 6.2' + unit_tests.dependency 'OCMock' + unit_tests.source_files = 'Example/CoreDiagnostics/Tests/**/*.[mh]' + unit_tests.requires_app_host = false + end +end diff --git a/FirebaseCoreDiagnosticsInterop.podspec b/FirebaseCoreDiagnosticsInterop.podspec new file mode 100644 index 0000000000..de8f4bb2b6 --- /dev/null +++ b/FirebaseCoreDiagnosticsInterop.podspec @@ -0,0 +1,29 @@ +Pod::Spec.new do |s| + s.name = 'FirebaseCoreDiagnosticsInterop' + s.version = '0.1.0' + s.summary = 'Interfaces that allow other Firebase SDKs to use CoreDiagnostics functionality.' + + s.description = <<-DESC + Not for public use. + + A set of protocols that other Firebase SDKs can use to interoperate with FirebaseCoreDiagnostics + in a safe manner. + DESC + + s.homepage = 'https://firebase.google.com' + s.license = { :type => 'Apache', :file => 'LICENSE' } + s.authors = 'Google, Inc.' + + # NOTE that these should not be used externally, this is for Firebase pods to depend on each + # other. + s.source = { + :git => 'https://github.com/firebase/firebase-ios-sdk.git', + :tag => 'CoreDiagnosticsInterop-' + s.version.to_s + } + s.social_media_url = 'https://twitter.com/Firebase' + s.ios.deployment_target = '8.0' + s.osx.deployment_target = '10.11' + s.tvos.deployment_target = '10.0' + s.source_files = 'Interop/CoreDiagnostics/**/*.h' + s.public_header_files = 'Interop/CoreDiagnostics/Public/*.h' +end diff --git a/Firestore/Example/Podfile b/Firestore/Example/Podfile index 6450e5b60b..4613a5c1df 100644 --- a/Firestore/Example/Podfile +++ b/Firestore/Example/Podfile @@ -37,6 +37,10 @@ target 'Firestore_Example_iOS' do pod 'FirebaseAuth', :path => '../../' pod 'FirebaseAuthInterop', :path => '../../' pod 'FirebaseCore', :path => '../../' + pod 'FirebaseCoreDiagnostics', :path => '../../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../../' + pod 'GoogleDataTransport', :path => '../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../' pod 'GoogleUtilities', :path => '../../' pod 'FirebaseFirestore', :path => '../../' @@ -88,8 +92,12 @@ target 'Firestore_Example_macOS' do pod 'FirebaseAuth', :path => '../../' pod 'FirebaseAuthInterop', :path => '../../' pod 'FirebaseCore', :path => '../../' + pod 'FirebaseCoreDiagnostics', :path => '../../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../../' pod 'GoogleUtilities', :path => '../../' pod 'FirebaseFirestore', :path => '../../' + pod 'GoogleDataTransport', :path => '../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../' target 'Firestore_Tests_macOS' do inherit! :search_paths @@ -123,6 +131,8 @@ target 'Firestore_Example_tvOS' do pod 'FirebaseCore', :path => '../../' pod 'GoogleUtilities', :path => '../../' pod 'FirebaseFirestore', :path => '../../' + pod 'GoogleDataTransport', :path => '../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../' target 'Firestore_Tests_tvOS' do inherit! :search_paths diff --git a/Firestore/core/src/firebase/firestore/auth/CMakeLists.txt b/Firestore/core/src/firebase/firestore/auth/CMakeLists.txt index b08c6a5ee8..21a27cef4e 100644 --- a/Firestore/core/src/firebase/firestore/auth/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/auth/CMakeLists.txt @@ -34,6 +34,10 @@ cc_library( DEPENDS FirebaseAuthInterop FirebaseCore + FirebaseCoreDiagnostics + FirebaseCoreDiagnosticsInterop + GoogleDataTransport + GoogleDataTransportCCTSupport GoogleUtilities firebase_firestore_auth_base EXCLUDE_FROM_ALL diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt index 3cfc2afe49..c7436f5d3b 100644 --- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt @@ -94,6 +94,10 @@ cc_library( string_format.h DEPENDS FirebaseCore + FirebaseCoreDiagnostics + FirebaseCoreDiagnosticsInterop + GoogleDataTransport + GoogleDataTransportCCTSupport GoogleUtilities absl_base absl_strings diff --git a/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt b/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt index 8bc210314d..6b5b6afc2f 100644 --- a/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/testutil/CMakeLists.txt @@ -20,6 +20,10 @@ cc_library( xcgmock.h DEPENDS FirebaseCore + FirebaseCoreDiagnostics + FirebaseCoreDiagnosticsInterop + GoogleDataTransport + GoogleDataTransportCCTSupport GoogleUtilities absl_strings EXCLUDE_FROM_ALL diff --git a/Functions/Example/Podfile b/Functions/Example/Podfile index aa1ed37631..36e9be09bb 100644 --- a/Functions/Example/Podfile +++ b/Functions/Example/Podfile @@ -5,7 +5,11 @@ target 'FirebaseFunctions_Example' do pod 'FirebaseAuthInterop', :path => '../../' pod 'FirebaseCore', :path => '../../' + pod 'FirebaseCoreDiagnostics', :path => '../../' + pod 'FirebaseCoreDiagnosticsInterop', :path => '../../' pod 'FirebaseFunctions', :path => '../../', :testspecs => ['unit'] + pod 'GoogleDataTransport', :path => '../../' + pod 'GoogleDataTransportCCTSupport', :path => '../../' pod 'GoogleUtilities', :path => '../../' target 'FirebaseFunctions_Tests' do diff --git a/GoogleDataTransport.podspec b/GoogleDataTransport.podspec index 952422dd15..8dd96683b2 100644 --- a/GoogleDataTransport.podspec +++ b/GoogleDataTransport.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GoogleDataTransport' - s.version = '0.1.3' + s.version = '0.2.0' s.summary = 'Google iOS SDK data transport.' s.description = <<-DESC @@ -12,7 +12,7 @@ Shared library for iOS SDK data transport needs. s.authors = 'Google, Inc.' s.source = { :git => 'https://github.com/firebase/firebase-ios-sdk.git', - :tag => 'GoogleDataTransport-' + s.version.to_s + :tag => 'DataTransport-' + s.version.to_s } s.ios.deployment_target = '8.0' diff --git a/GoogleDataTransport/CHANGELOG.md b/GoogleDataTransport/CHANGELOG.md index e69de29bb2..c1368376df 100644 --- a/GoogleDataTransport/CHANGELOG.md +++ b/GoogleDataTransport/CHANGELOG.md @@ -0,0 +1,9 @@ +# v0.2.0 +- Initial Release--for Google-use only. This library is the foundation of a +network transport layer that focuses on transparently and respectfully +transporting data that is collected for purposes that vary depending on the +adopting SDK. Primarily, we seek to reduce Firebase's impact on binary size, +mobile data consumption, and battery use for end users by aggregating collected +data and transporting it under ideal conditions. Users should expect to see an +increase in the number of Cocoapods/frameworks/libraries, but a decrease in +binary size over time as our codebase becomes more modularized. \ No newline at end of file diff --git a/GoogleDataTransport/GDTLibrary/GDTPlatform.m b/GoogleDataTransport/GDTLibrary/GDTPlatform.m index 975f92ddee..d206c749c7 100644 --- a/GoogleDataTransport/GDTLibrary/GDTPlatform.m +++ b/GoogleDataTransport/GDTLibrary/GDTPlatform.m @@ -38,7 +38,7 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) { @implementation GDTApplication + (void)load { -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV NSAssert(GDTBackgroundIdentifierInvalid == UIBackgroundTaskInvalid, @"GDTBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same."); #endif @@ -57,7 +57,7 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) { - (instancetype)init { self = [super init]; if (self) { -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(iOSApplicationDidEnterBackground:) @@ -79,28 +79,55 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) { selector:@selector(macOSApplicationWillTerminate:) name:NSApplicationWillTerminateNotification object:nil]; -#endif // TARGET_OS_IOS || TARGET_OS_TVOS +#endif // TARGET_OS_IOS || TARGET_OS_TV } return self; } - (GDTBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler { -#if TARGET_OS_IOS || TARGET_OS_TVOS - return [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:handler]; -#else - return GDTBackgroundIdentifierInvalid; -#endif // TARGET_OS_IOS || TARGET_OS_TVOS + return + [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithExpirationHandler:handler]; } - (void)endBackgroundTask:(GDTBackgroundIdentifier)bgID { -#if TARGET_OS_IOS || TARGET_OS_TVOS - [[UIApplication sharedApplication] endBackgroundTask:bgID]; -#endif // TARGET_OS_IOS || TARGET_OS_TVOS + [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID]; +} + +#pragma mark - App environment helpers + +- (BOOL)isAppExtension { +#if TARGET_OS_IOS || TARGET_OS_TV + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +#elif TARGET_OS_OSX + return NO; +#endif +} + +/** Returns a UIApplication instance if on the appropriate platform. + * + * @return The shared UIApplication if on the appropriate platform. + */ +#if TARGET_OS_IOS || TARGET_OS_TV +- (nullable UIApplication *)sharedApplicationForBackgroundTask { +#else +- (nullable id)sharedApplicationForBackgroundTask { +#endif + if ([self isAppExtension]) { + return nil; + } + id sharedApplication = nil; + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedApplication = [uiApplicationClass sharedApplication]; + } + return sharedApplication; } #pragma mark - UIApplicationDelegate -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV - (void)iOSApplicationDidEnterBackground:(NSNotification *)notif { NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; [notifCenter postNotificationName:kGDTApplicationDidEnterBackgroundNotification object:nil]; @@ -115,7 +142,7 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) { NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; [notifCenter postNotificationName:kGDTApplicationWillTerminateNotification object:nil]; } -#endif // TARGET_OS_IOS || TARGET_OS_TVOS +#endif // TARGET_OS_IOS || TARGET_OS_TV #pragma mark - NSApplicationDelegate diff --git a/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m b/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m index 51c9be2012..6217f139a4 100644 --- a/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m +++ b/GoogleDataTransport/GDTLibrary/GDTStoredEvent.m @@ -18,7 +18,7 @@ #import -#import "GDTStorage_Private.h" +#import "GDTLibrary/Private/GDTStorage_Private.h" @implementation GDTStoredEvent diff --git a/GoogleDataTransport/GDTLibrary/Public/GDTPlatform.h b/GoogleDataTransport/GDTLibrary/Public/GDTPlatform.h index 923dd93328..5773700c09 100644 --- a/GoogleDataTransport/GDTLibrary/Public/GDTPlatform.h +++ b/GoogleDataTransport/GDTLibrary/Public/GDTPlatform.h @@ -17,11 +17,11 @@ #import #import -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV #import #elif TARGET_OS_OSX #import -#endif // TARGET_OS_IOS || TARGET_OS_TVOS +#endif // TARGET_OS_IOS || TARGET_OS_TV NS_ASSUME_NONNULL_BEGIN @@ -42,19 +42,19 @@ FOUNDATION_EXPORT NSString *const kGDTApplicationWillTerminateNotification; BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags); /** A typedef identify background identifiers. */ -typedef NSUInteger GDTBackgroundIdentifier NS_TYPED_ENUM; +typedef NSUInteger GDTBackgroundIdentifier; /** A background task's invalid sentinel value. */ FOUNDATION_EXPORT const GDTBackgroundIdentifier GDTBackgroundIdentifierInvalid; -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV /** A protocol that wraps UIApplicationDelegate or NSObject protocol, depending on the platform. */ @protocol GDTApplicationDelegate #elif TARGET_OS_OSX @protocol GDTApplicationDelegate #else @protocol GDTApplicationDelegate -#endif // TARGET_OS_IOS || TARGET_OS_TVOS +#endif // TARGET_OS_IOS || TARGET_OS_TV @end diff --git a/GoogleDataTransportCCTSupport.podspec b/GoogleDataTransportCCTSupport.podspec index 06af6f555c..d4af965ab9 100644 --- a/GoogleDataTransportCCTSupport.podspec +++ b/GoogleDataTransportCCTSupport.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'GoogleDataTransportCCTSupport' - s.version = '0.1.2' + s.version = '0.2.0' s.summary = 'Support library for the GoogleDataTransport CCT backend target.' @@ -14,7 +14,7 @@ Support library to provide event prioritization and uploading for the GoogleData s.authors = 'Google, Inc.' s.source = { :git => 'https://github.com/firebase/firebase-ios-sdk.git', - :tag => 'GoogleDataTransportCCTSupport-' + s.version.to_s + :tag => 'DataTransportCCTSupport-' + s.version.to_s } s.ios.deployment_target = '8.0' @@ -30,7 +30,7 @@ Support library to provide event prioritization and uploading for the GoogleData s.source_files = 'GoogleDataTransportCCTSupport/GDTCCTLibrary/**/*' s.private_header_files = 'GoogleDataTransportCCTSupport/GDTCCTLibrary/Private/*.h' - s.dependency 'GoogleDataTransport', '~> 0.1.1' + s.dependency 'GoogleDataTransport', '~> 0.2' s.dependency 'nanopb' header_search_paths = { diff --git a/GoogleDataTransportCCTSupport/CHANGELOG.md b/GoogleDataTransportCCTSupport/CHANGELOG.md index e69de29bb2..82ae079e4a 100644 --- a/GoogleDataTransportCCTSupport/CHANGELOG.md +++ b/GoogleDataTransportCCTSupport/CHANGELOG.md @@ -0,0 +1,3 @@ +# v0.2.0 +- Initial Release--for Google-use only. This library adds support for the CCT +Google backend. \ No newline at end of file diff --git a/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTNanopbHelpers.m b/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTNanopbHelpers.m index e4fde2330a..b55041361c 100644 --- a/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTNanopbHelpers.m +++ b/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTNanopbHelpers.m @@ -16,11 +16,11 @@ #import "GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV #import #elif TARGET_OS_OSX #import -#endif // TARGET_OS_IOS || TARGET_OS_TVOS +#endif // TARGET_OS_IOS || TARGET_OS_TV #import #import @@ -127,7 +127,7 @@ gdt_cct_ClientInfo GDTCCTConstructClientInfo() { gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default; clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE; clientInfo.has_client_type = 1; -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo(); clientInfo.has_ios_client_info = 1; #elif TARGET_OS_OSX @@ -138,7 +138,7 @@ gdt_cct_ClientInfo GDTCCTConstructClientInfo() { gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo() { gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default; -#if TARGET_OS_IOS || TARGET_OS_TVOS +#if TARGET_OS_IOS || TARGET_OS_TV UIDevice *device = [UIDevice currentDevice]; NSBundle *bundle = [NSBundle mainBundle]; NSLocale *locale = [NSLocale currentLocale]; @@ -165,8 +165,9 @@ gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) { gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default; pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]); if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) { - NSCAssert(NO, @"Error in nanopb decoding for bytes: %s", PB_GET_ERROR(&istream)); - *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil]; + NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)]; + NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error}; + *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo]; response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default; } return response; diff --git a/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTPrioritizer.m b/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTPrioritizer.m index d6c9d7dc09..414cc73153 100644 --- a/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTPrioritizer.m +++ b/GoogleDataTransportCCTSupport/GDTCCTLibrary/GDTCCTPrioritizer.m @@ -21,7 +21,7 @@ #import #import -const static NSUInteger kMillisPerDay = 8.64e+7; +const static int64_t kMillisPerDay = 8.64e+7; @implementation GDTCCTPrioritizer diff --git a/GoogleDataTransportCCTSupport/ProtoSupport/Protos/cct.proto b/GoogleDataTransportCCTSupport/ProtoSupport/Protos/cct.proto index 131e87d018..8b32dcedfe 100644 --- a/GoogleDataTransportCCTSupport/ProtoSupport/Protos/cct.proto +++ b/GoogleDataTransportCCTSupport/ProtoSupport/Protos/cct.proto @@ -13,14 +13,14 @@ // See the License for the specific language governing permissions and // limitations under the License. // - + syntax = "proto2"; package gdt_cct; message LogEvent { optional int64 event_time_ms = 1; - + optional int32 event_code = 11; optional int64 event_uptime_ms = 17; @@ -172,7 +172,7 @@ message QosTierConfiguration { } optional QosTier qos_tier = 2; - + optional int32 log_source = 3 [default = 0]; } diff --git a/GoogleDataTransportCCTSupport/ProtoSupport/proto_generator.py b/GoogleDataTransportCCTSupport/ProtoSupport/proto_generator.py index c1329e6f1b..7c750fd416 100755 --- a/GoogleDataTransportCCTSupport/ProtoSupport/proto_generator.py +++ b/GoogleDataTransportCCTSupport/ProtoSupport/proto_generator.py @@ -173,7 +173,7 @@ def run_protoc(args, cmd): env['PYTHONPATH'] += os.pathsep + old_path kwargs['env'] = env - try: + try: print(subprocess.check_output(cmd, stderr=subprocess.STDOUT, **kwargs)) except subprocess.CalledProcessError as error: print('command failed: ', ' '.join(cmd), '\nerror: ', error.output) @@ -262,8 +262,8 @@ def nanopb_rename_delete(lines): def nanopb_use_module_import(lines): - """Changes #include to #include """ - return [line.replace('#include ', '#include ') for line in lines] + """Changes #include to include """ # Don't let Copybara alter these lines. + return [line.replace('#include ', '{}include '.format("#")) for line in lines] def strip_trailing_whitespace(lines): @@ -277,7 +277,7 @@ def objc_flatten_imports(lines): long_import = re.compile(r'#import ".*/') return [long_import.sub('#import "', line) for line in lines] - + def objc_strip_extension_registry(lines): """Removes extensionRegistry methods from the classes.""" skip = False diff --git a/InAppMessaging/Example/Podfile b/InAppMessaging/Example/Podfile index 534b081b90..1fcc764565 100644 --- a/InAppMessaging/Example/Podfile +++ b/InAppMessaging/Example/Podfile @@ -4,6 +4,10 @@ source 'https://cdn.cocoapods.org/' pod 'FirebaseAnalytics' pod 'FirebaseCore', :path => '../..' +pod 'FirebaseCoreDiagnostics', :path => '../..' +pod 'FirebaseCoreDiagnosticsInterop', :path => '../..' +pod 'GoogleDataTransport', :path => '../..' +pod 'GoogleDataTransportCCTSupport', :path => '../..' target 'InAppMessaging_Example_iOS' do platform :ios, '8.0' diff --git a/InAppMessagingDisplay/Example/Podfile b/InAppMessagingDisplay/Example/Podfile index 1c636382d3..c3f1385728 100644 --- a/InAppMessagingDisplay/Example/Podfile +++ b/InAppMessagingDisplay/Example/Podfile @@ -3,6 +3,10 @@ source 'https://cdn.cocoapods.org/' use_frameworks! pod 'FirebaseCore', :path => '../..' +pod 'FirebaseCoreDiagnostics', :path => '../..' +pod 'FirebaseCoreDiagnosticsInterop', :path => '../..' +pod 'GoogleDataTransport', :path => '../..' +pod 'GoogleDataTransportCCTSupport', :path => '../..' target 'FiamDisplaySwiftExample' do platform :ios, '8.0' diff --git a/Interop/CoreDiagnostics/CHANGELOG.md b/Interop/CoreDiagnostics/CHANGELOG.md new file mode 100644 index 0000000000..062ed264e7 --- /dev/null +++ b/Interop/CoreDiagnostics/CHANGELOG.md @@ -0,0 +1,3 @@ +# v0.1.0 +- Initial Release--for Google-use only. This library defines the interface +needed to exchange data between FirebaseCore andFirebaseCoreDiagnostics. \ No newline at end of file diff --git a/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h b/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h new file mode 100644 index 0000000000..7c74776960 --- /dev/null +++ b/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsData.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** If present, is a BOOL wrapped in an NSNumber. */ +static NSString *const kFIRCDIsDataCollectionDefaultEnabledKey = + @"FIRCDIsDataCollectionDefaultEnabledKey"; + +/** If present, is an int32_t wrapped in an NSNumber. */ +static NSString *const kFIRCDConfigurationTypeKey = @"FIRCDConfigurationTypeKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDSdkNameKey = @"FIRCDSdkNameKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDSdkVersionKey = @"FIRCDSdkVersionKey"; + +/** If present, is an int32_t wrapped in an NSNumber. */ +static NSString *const kFIRCDllAppsCountKey = @"FIRCDllAppsCountKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDGoogleAppIDKey = @"FIRCDGoogleAppIDKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDBundleIDKey = @"FIRCDBundleID"; + +/** If present, is a BOOL wrapped in an NSNumber. */ +static NSString *const kFIRCDUsingOptionsFromDefaultPlistKey = + @"FIRCDUsingOptionsFromDefaultPlistKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDLibraryVersionIDKey = @"FIRCDLibraryVersionIDKey"; + +/** If present, is an NSString. */ +static NSString *const kFIRCDFirebaseUserAgentKey = @"FIRCDFirebaseUserAgentKey"; + +/** Defines the interface of a data object needed to log diagnostics data. */ +@protocol FIRCoreDiagnosticsData + +@required + +/** A dictionary containing data (non-exhaustive) to be logged in diagnostics. */ +@property(nonatomic) NSDictionary *diagnosticObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h b/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h new file mode 100644 index 0000000000..2b0eb710cd --- /dev/null +++ b/Interop/CoreDiagnostics/Public/FIRCoreDiagnosticsInterop.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Google + * + * 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. + */ + +#import + +#import "FIRCoreDiagnosticsData.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Allows the interoperation of FirebaseCore and FirebaseCoreDiagnostics. */ +@protocol FIRCoreDiagnosticsInterop + +/** Sends the given diagnostics data. + * + * @param diagnosticsData The diagnostics data object to send. + */ ++ (void)sendDiagnosticsData:(id)diagnosticsData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/scripts/check_whitespace.sh b/scripts/check_whitespace.sh index 11e7f2cf96..b3d1a2491d 100755 --- a/scripts/check_whitespace.sh +++ b/scripts/check_whitespace.sh @@ -26,6 +26,8 @@ options=( ) git grep "${options[@]}" -- \ + ':(exclude)Firebase/CoreDiagnostics/FIRCDLibrary/Protogen/nanopb' \ + ':(exclude)Firebase/CoreDiagnostics/ProtoSupport' \ ':(exclude)Firestore/Protos/nanopb' \ ':(exclude)Firestore/Protos/cpp' \ ':(exclude)Firestore/Protos/objc' \ diff --git a/scripts/if_changed.sh b/scripts/if_changed.sh index c3e2440565..f92e51c08c 100755 --- a/scripts/if_changed.sh +++ b/scripts/if_changed.sh @@ -49,10 +49,10 @@ else check_changes '^(Firebase/Auth|Firebase/Database|Firebase/DynamicLinks|'\ 'Firebase/Messaging|Firebase/Storage|GoogleUtilities|Interop|Example|'\ 'FirebaseAnalyticsIntop.podspec|FirebaseAuth.podspec|FirebaseAuthInterop.podspec|'\ -'FirebaseDatabase.podspec|FirebaseDynamicLinks.podspec|'\ -'FirebaseMessaging.podspec|FirebaseStorage.podspec|'\ -'FirebaseStorage.podspec|Firebase/InAppMessagingDisplay|InAppMessagingDisplay|'\ -'InAppMessaging|Firebase/InAppMessaging|'\ +'FirebaseCoreDiagnostics.podspec|FirebaseCoreDiagnosticsInterop.podspec|'\ +'FirebaseDatabase.podspec|FirebaseDynamicLinks.podspec|FirebaseMessaging.podspec|'\ +'FirebaseStorage.podspec|FirebaseStorage.podspec|Firebase/InAppMessagingDisplay|'\ +'InAppMessagingDisplay|InAppMessaging|Firebase/InAppMessaging|'\ 'FirebaseInAppMessaging.podspec|FirebaseInAppMessagingDisplay.podspec|'\ 'Firebase/InstanceID|FirebaseInstanceID.podspec)' ;; @@ -61,9 +61,9 @@ else check_changes '^(Firebase/Auth|Firebase/Core|Firebase/Database|Firebase/DynamicLinks|'\ 'Firebase/Messaging|Firebase/Storage|GoogleUtilities|Interop|Example|'\ 'FirebaseAnalyticsIntop.podspec|FirebaseAuth.podspec|FirebaseAuthInterop.podspec|'\ -'FirebaseCore.podspec|FirebaseDatabase.podspec|FirebaseDynamicLinks.podspec|'\ -'FirebaseMessaging.podspec|FirebaseStorage.podspec|'\ -'FirebaseStorage.podspec|Firebase/InstanceID|FirebaseInstanceID.podspec)' +'FirebaseCore.podspec|FirebaseCoreDiagnostics.podspec|FirebaseCoreDiagnosticsInterop.podspec|'\ +'FirebaseDatabase.podspec|FirebaseDynamicLinks.podspec|FirebaseMessaging.podspec|'\ +'FirebaseStorage.podspec|FirebaseStorage.podspec|Firebase/InstanceID|FirebaseInstanceID.podspec)' ;; Core-*) @@ -109,6 +109,11 @@ else check_changes '^(Firestore/(core|third_party)|cmake|GoogleUtilities)' ;; + FirebaseCoreDiagnostics-*) + check_changes '^(Firebase/CoreDiagnostics|FirebaseCoreDiagnosticsInterop|'\ +'FirebaseCoreDiagnostics.podspec|FirebaseCoreDiagnosticsInterop.podspec)' + ;; + GoogleDataTransport-*) check_changes '^(GoogleDataTransport|GoogleDataTransport.podspec)' ;; diff --git a/scripts/install_prereqs.sh b/scripts/install_prereqs.sh index 3adbd6d48c..1c23af11c3 100755 --- a/scripts/install_prereqs.sh +++ b/scripts/install_prereqs.sh @@ -125,6 +125,11 @@ case "$PROJECT-$PLATFORM-$METHOD" in bundle exec pod install --project-directory=SymbolCollisionTest --repo-update ;; + FirebaseCoreDiagnostics-*-xcodebuild) + gem install xcpretty + pod_gen FirebaseCoreDiagnostics.podspec + ;; + GoogleDataTransport-*-xcodebuild) gem install xcpretty pod_gen GoogleDataTransport.podspec diff --git a/scripts/pod_lib_lint.rb b/scripts/pod_lib_lint.rb index e82cd7c83f..9fed67610a 100755 --- a/scripts/pod_lib_lint.rb +++ b/scripts/pod_lib_lint.rb @@ -38,6 +38,8 @@ def main(args) exit(1) end + STDOUT.sync = true + command = %w(bundle exec pod lib lint --sources=https://cdn.cocoapods.org/) # Figure out which dependencies are local @@ -48,7 +50,21 @@ def main(args) command.push(*args) puts command.join(' ') - exec(*command) + + # Run the lib lint command in a thread. + t = Thread.new do + system(*command) + end + + # Print every minute since linting can run for >10m without output. + number_of_times_checked = 0 + while t.alive? do + sleep 1.0 + number_of_times_checked += 1 + if (number_of_times_checked % 60) == 0 then + puts "Still working, running for #{number_of_times_checked / 60}min." + end + end end # Loads all the specs (inclusing subspecs) from the given podspec file.