diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index cb96742c0..e4eb68725 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -655,6 +655,7 @@ 00AD1F302486A17900A27979 /* BugsnagSessionTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1F012486A17900A27979 /* BugsnagSessionTracker.m */; }; 00AD1F312486A17900A27979 /* BugsnagSessionTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1F012486A17900A27979 /* BugsnagSessionTracker.m */; }; 00E636C224878D84006CBF1A /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969142486DAD000DC48C2 /* BSG_RFC3339DateTool.m */; }; + 012482A325627B51003F7243 /* UIKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 012482A225627B51003F7243 /* UIKitTests.m */; }; 014475FD2566844F0018AB94 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; }; 01447605256684500018AB94 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; }; 01B14C56251CE55F00118748 /* report-react-native-promise-rejection.json in Resources */ = {isa = PBXBuildFile; fileRef = 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */; }; @@ -1273,8 +1274,10 @@ 00E636C02487031D006CBF1A /* Bugsnag.podspec.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = Bugsnag.podspec.json; sourceTree = SOURCE_ROOT; }; 00E636C12487031D006CBF1A /* docker-compose.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = "docker-compose.yml"; sourceTree = SOURCE_ROOT; }; 00E636C324878FFC006CBF1A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 012482A225627B51003F7243 /* UIKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIKitTests.m; sourceTree = ""; }; 0134524A256BCF7C0088C548 /* BugsnagError+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagError+Private.h"; sourceTree = ""; }; 0134524B256BD00A0088C548 /* BugsnagThread+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagThread+Private.h"; sourceTree = ""; }; + 0140D24725765F8F00FD0306 /* BSGUIKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGUIKit.h; sourceTree = ""; }; 0195FC3B256BC81400DE6646 /* BugsnagEvent+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagEvent+Private.h"; sourceTree = ""; }; 0198762E2567D5AB000A7AF3 /* BugsnagStackframe+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagStackframe+Private.h"; sourceTree = ""; }; 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "report-react-native-promise-rejection.json"; sourceTree = ""; }; @@ -1700,6 +1703,7 @@ CBA2249A251E429C00B87416 /* TestSupport.m */, 01E8765C256684E700F4B70A /* URLSessionMock.h */, 01E8765D256684E700F4B70A /* URLSessionMock.m */, + 012482A225627B51003F7243 /* UIKitTests.m */, ); path = Tests; sourceTree = ""; @@ -1761,6 +1765,7 @@ CBCF77A225010648004AF22A /* BSGJSONSerialization.m */, 008968112486DA5600DC48C2 /* BSGSerialization.h */, 008968162486DA5600DC48C2 /* BSGSerialization.m */, + 0140D24725765F8F00FD0306 /* BSGUIKit.h */, 008968102486DA5600DC48C2 /* BugsnagCollections.h */, 008968172486DA5600DC48C2 /* BugsnagCollections.m */, 008968152486DA5600DC48C2 /* BugsnagKeys.h */, @@ -2551,6 +2556,7 @@ 0089678A2486D43700DC48C2 /* KSCrashReportStore_Tests.m in Sources */, E701FAAB2490EFD9008D842F /* EventApiValidationTest.m in Sources */, 0089677E2486D43700DC48C2 /* KSLogger_Tests.m in Sources */, + 012482A325627B51003F7243 /* UIKitTests.m in Sources */, 008967482486D43700DC48C2 /* BugsnagUserTest.m in Sources */, 008967962486D43700DC48C2 /* KSCrashState_Tests.m in Sources */, 0089675D2486D43700DC48C2 /* BugsnagSessionTrackingPayloadTest.m in Sources */, @@ -3182,6 +3188,7 @@ 00AD1C8724869B0E00A27979 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_MODULES_AUTOLINK = NO; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -3204,6 +3211,7 @@ 00AD1C8824869B0E00A27979 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_MODULES_AUTOLINK = NO; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/Bugsnag/BugsnagSystemState.m b/Bugsnag/BugsnagSystemState.m index 022e6c4b6..81828df40 100644 --- a/Bugsnag/BugsnagSystemState.m +++ b/Bugsnag/BugsnagSystemState.m @@ -10,7 +10,7 @@ #if TARGET_OS_OSX #import #else -#import +#import "BSGUIKit.h" #endif #import "BugsnagSystemState.h" @@ -132,10 +132,10 @@ id blankIfNil(id value) { #endif device[@"totalMemory"] = systemInfo[@BSG_KSSystemField_Memory][@"usable"]; #if BSG_PLATFORM_IOS - device[BSGKeyBatteryLevel] = @([UIDevice currentDevice].batteryLevel); - UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState; + device[BSGKeyBatteryLevel] = @([UIDEVICE currentDevice].batteryLevel); + UIDeviceBatteryState batteryState = [UIDEVICE currentDevice].batteryState; device[BSGKeyCharging] = @(batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull); - device[BSGKeyOrientation] = BSGOrientationNameFromEnum([UIDevice currentDevice].orientation); + device[BSGKeyOrientation] = BSGOrientationNameFromEnum([UIDEVICE currentDevice].orientation); #endif NSMutableDictionary *state = [NSMutableDictionary new]; diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 8d7d41719..aa50f732b 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -67,7 +67,7 @@ #endif #if BSG_PLATFORM_IOS -#import +#import "BSGUIKit.h" #elif BSG_PLATFORM_OSX #import #endif @@ -390,7 +390,7 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)initConfiguration client:self]; #if BSG_PLATFORM_IOS - _lastOrientation = BSGOrientationNameFromEnum([UIDevice currentDevice].orientation); + _lastOrientation = BSGOrientationNameFromEnum([UIDEVICE currentDevice].orientation); #endif _user = self.configuration.user; @@ -538,8 +538,8 @@ - (void)start { name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; - [UIDevice currentDevice].batteryMonitoringEnabled = YES; - [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [UIDEVICE currentDevice].batteryMonitoringEnabled = YES; + [[UIDEVICE currentDevice] beginGeneratingDeviceOrientationNotifications]; [self batteryChanged:nil]; [self orientationChanged:nil]; @@ -709,8 +709,8 @@ - (void)unsubscribeFromNotifications:(id)sender { [BSGConnectivity stopMonitoring]; #if BSG_PLATFORM_IOS - [UIDevice currentDevice].batteryMonitoringEnabled = NO; - [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; + [UIDEVICE currentDevice].batteryMonitoringEnabled = NO; + [[UIDEVICE currentDevice] endGeneratingDeviceOrientationNotifications]; #endif } @@ -1146,9 +1146,9 @@ - (void)metadataChanged:(BugsnagMetadata *)metadata { */ #if BSG_PLATFORM_IOS - (void)batteryChanged:(NSNotification *)notification { - NSNumber *batteryLevel = @([UIDevice currentDevice].batteryLevel); - BOOL charging = [UIDevice currentDevice].batteryState == UIDeviceBatteryStateCharging || - [UIDevice currentDevice].batteryState == UIDeviceBatteryStateFull; + NSNumber *batteryLevel = @([UIDEVICE currentDevice].batteryLevel); + BOOL charging = [UIDEVICE currentDevice].batteryState == UIDeviceBatteryStateCharging || + [UIDEVICE currentDevice].batteryState == UIDeviceBatteryStateFull; [self.state addMetadata:batteryLevel withKey:BSGKeyBatteryLevel @@ -1170,7 +1170,7 @@ - (void)batteryChanged:(NSNotification *)notification { * @param notification The orientation-change notification */ - (void)orientationChanged:(NSNotification *)notification { - UIDeviceOrientation currentDeviceOrientation = [UIDevice currentDevice].orientation; + UIDeviceOrientation currentDeviceOrientation = [UIDEVICE currentDevice].orientation; NSString *orientation = BSGOrientationNameFromEnum(currentDeviceOrientation); // No orientation, nothing to be done diff --git a/Bugsnag/Helpers/BSGUIKit.h b/Bugsnag/Helpers/BSGUIKit.h new file mode 100644 index 000000000..bbe3eae93 --- /dev/null +++ b/Bugsnag/Helpers/BSGUIKit.h @@ -0,0 +1,40 @@ +// +// BSGUIKit.h +// Bugsnag +// +// Created by Nick Dowell on 01/12/2020. +// Copyright © 2020 Bugsnag Inc. All rights reserved. +// + +#import + +// When used in some memory constrained contexts such as a file provider extension, linking to UIKit is problematic. +// These macros exist to allow the use of UIKit without adding a link-time dependency on it. + +#define UIAPPLICATION NSClassFromString(@"UIApplication") +#define UIDEVICE NSClassFromString(@"UIDevice") + +#define UIApplicationDidBecomeActiveNotification @"UIApplicationDidBecomeActiveNotification" +#define UIApplicationDidEnterBackgroundNotification @"UIApplicationDidEnterBackgroundNotification" +#define UIApplicationDidReceiveMemoryWarningNotification @"UIApplicationDidReceiveMemoryWarningNotification" +#define UIApplicationUserDidTakeScreenshotNotification @"UIApplicationUserDidTakeScreenshotNotification" +#define UIApplicationWillEnterForegroundNotification @"UIApplicationWillEnterForegroundNotification" +#define UIApplicationWillResignActiveNotification @"UIApplicationWillResignActiveNotification" +#define UIApplicationWillTerminateNotification @"UIApplicationWillTerminateNotification" +#define UIDeviceBatteryLevelDidChangeNotification @"UIDeviceBatteryLevelDidChangeNotification" +#define UIDeviceBatteryStateDidChangeNotification @"UIDeviceBatteryStateDidChangeNotification" +#define UIDeviceOrientationDidChangeNotification @"UIDeviceOrientationDidChangeNotification" +#define UIKeyboardDidHideNotification @"UIKeyboardDidHideNotification" +#define UIKeyboardDidShowNotification @"UIKeyboardDidShowNotification" +#define UIMenuControllerDidHideMenuNotification @"UIMenuControllerDidHideMenuNotification" +#define UIMenuControllerDidShowMenuNotification @"UIMenuControllerDidShowMenuNotification" +#define UIScreenBrightnessDidChangeNotification @"UIScreenBrightnessDidChangeNotification" +#define UITableViewSelectionDidChangeNotification @"UITableViewSelectionDidChangeNotification" +#define UITextFieldTextDidBeginEditingNotification @"UITextFieldTextDidBeginEditingNotification" +#define UITextFieldTextDidEndEditingNotification @"UITextFieldTextDidEndEditingNotification" +#define UITextViewTextDidBeginEditingNotification @"UITextViewTextDidBeginEditingNotification" +#define UITextViewTextDidEndEditingNotification @"UITextViewTextDidEndEditingNotification" +#define UIWindowDidBecomeHiddenNotification @"UIWindowDidBecomeHiddenNotification" +#define UIWindowDidBecomeKeyNotification @"UIWindowDidBecomeKeyNotification" +#define UIWindowDidBecomeVisibleNotification @"UIWindowDidBecomeVisibleNotification" +#define UIWindowDidResignKeyNotification @"UIWindowDidResignKeyNotification" diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index ce96ed611..009802fc0 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -43,7 +43,7 @@ #import "BSG_KSCrashReportFields.h" #if BSG_HAS_UIKIT -#import +#import "BSGUIKit.h" #endif #if TARGET_OS_OSX #import diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m index 2c74c4429..c7cd921e3 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m @@ -36,7 +36,7 @@ #include "BSG_KSLogger.h" #if (TARGET_OS_TV || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR) -#import +#import "BSGUIKit.h" #endif #include #include diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.h index 24381821a..f0e8ef10f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.h @@ -60,7 +60,7 @@ #import "BugsnagPlatformConditional.h" #if BSG_PLATFORM_IOS || BSG_PLATFORM_TVOS -#import +#import "BSGUIKit.h" #endif /** diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m index af11e3e0c..00b9cc8a6 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m @@ -42,7 +42,7 @@ #import #if BSG_PLATFORM_IOS || BSG_PLATFORM_TVOS -#import +#import "BSGUIKit.h" #endif @implementation BSG_KSSystemInfo @@ -176,10 +176,10 @@ + (NSString *)deviceAndAppHash { NSMutableData *data = nil; #if BSG_HAS_UIDEVICE - if ([[UIDevice currentDevice] + if ([[UIDEVICE currentDevice] respondsToSelector:@selector(identifierForVendor)]) { data = [NSMutableData dataWithLength:16]; - [[UIDevice currentDevice].identifierForVendor + [[UIDEVICE currentDevice].identifierForVendor getUUIDBytes:data.mutableBytes]; } else #endif @@ -354,8 +354,8 @@ + (NSDictionary *)systemInfo { BSGDictSetSafeObject(sysInfo, @__clang_version__, @BSG_KSSystemField_ClangVersion); #endif #if BSG_HAS_UIDEVICE - BSGDictSetSafeObject(sysInfo, [UIDevice currentDevice].systemName, @BSG_KSSystemField_SystemName); - BSGDictSetSafeObject(sysInfo, [UIDevice currentDevice].systemVersion, @BSG_KSSystemField_SystemVersion); + BSGDictSetSafeObject(sysInfo, [UIDEVICE currentDevice].systemName, @BSG_KSSystemField_SystemName); + BSGDictSetSafeObject(sysInfo, [UIDEVICE currentDevice].systemVersion, @BSG_KSSystemField_SystemVersion); #else BSGDictSetSafeObject(sysInfo, @"Mac OS", @BSG_KSSystemField_SystemName); NSOperatingSystemVersion version = @@ -458,7 +458,7 @@ + (UIApplicationState)currentAppState { // Calling this API indirectly to avoid a compile-time check that // [UIApplication sharedApplication] is not called from app extensions // (which is handled above) - UIApplication *app = [UIApplication performSelector:@selector(sharedApplication)]; + UIApplication *app = [UIAPPLICATION performSelector:@selector(sharedApplication)]; return [app applicationState]; }; diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index f27ca4841..211086ad2 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -9,7 +9,7 @@ #import "BugsnagPlatformConditional.h" #if BSG_PLATFORM_IOS -#import +#import "BSGUIKit.h" #include #endif diff --git a/Tests/UIKitTests.m b/Tests/UIKitTests.m new file mode 100644 index 000000000..740dddf48 --- /dev/null +++ b/Tests/UIKitTests.m @@ -0,0 +1,48 @@ +// +// UIKitTests.m +// Bugsnag-iOSTests +// +// Created by Nick Dowell on 16/11/2020. +// Copyright © 2020 Bugsnag Inc. All rights reserved. +// + +#import +#import + +@interface UIKitTests : XCTestCase + +@end + +@implementation UIKitTests + +- (void)testNotificationNames { + // The notifier uses hard-coded notification names so that it can avoid linking + // to UIKit. These tests ensure that the hard-coded names match the SDK. + #define ASSERT_NOTIFICATION_NAME(name) XCTAssertEqualObjects(name, @#name) + ASSERT_NOTIFICATION_NAME(UIApplicationDidBecomeActiveNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationDidEnterBackgroundNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationDidReceiveMemoryWarningNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationUserDidTakeScreenshotNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationWillEnterForegroundNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationWillResignActiveNotification); + ASSERT_NOTIFICATION_NAME(UIApplicationWillTerminateNotification); + ASSERT_NOTIFICATION_NAME(UIDeviceBatteryLevelDidChangeNotification); + ASSERT_NOTIFICATION_NAME(UIDeviceBatteryStateDidChangeNotification); + ASSERT_NOTIFICATION_NAME(UIDeviceOrientationDidChangeNotification); + ASSERT_NOTIFICATION_NAME(UIKeyboardDidHideNotification); + ASSERT_NOTIFICATION_NAME(UIKeyboardDidShowNotification); + ASSERT_NOTIFICATION_NAME(UIMenuControllerDidHideMenuNotification); + ASSERT_NOTIFICATION_NAME(UIMenuControllerDidShowMenuNotification); + ASSERT_NOTIFICATION_NAME(UIScreenBrightnessDidChangeNotification); + ASSERT_NOTIFICATION_NAME(UITableViewSelectionDidChangeNotification); + ASSERT_NOTIFICATION_NAME(UITextFieldTextDidBeginEditingNotification); + ASSERT_NOTIFICATION_NAME(UITextFieldTextDidEndEditingNotification); + ASSERT_NOTIFICATION_NAME(UITextViewTextDidBeginEditingNotification); + ASSERT_NOTIFICATION_NAME(UITextViewTextDidEndEditingNotification); + ASSERT_NOTIFICATION_NAME(UIWindowDidBecomeHiddenNotification); + ASSERT_NOTIFICATION_NAME(UIWindowDidBecomeKeyNotification); + ASSERT_NOTIFICATION_NAME(UIWindowDidBecomeVisibleNotification); + ASSERT_NOTIFICATION_NAME(UIWindowDidResignKeyNotification); +} + +@end