From 21eac0e66c6cf7ffa20f9112cde50329559e049c Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 9 Aug 2021 14:10:07 +0100 Subject: [PATCH 1/6] Add examples/swiftui --- .buildkite/pipeline.full.yml | 19 + examples/swiftui/Shared/AnObjCClass.h | 30 + examples/swiftui/Shared/AnObjCClass.mm | 67 ++ examples/swiftui/Shared/AppMain.swift | 108 +++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 172 +++++ .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 800 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1790 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 2963 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1266 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 2963 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 4673 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1790 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 4310 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 6617 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 6617 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 10566 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 4065 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 8885 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 9784 bytes .../AppIcon.appiconset/ItunesArtwork@2x.png | Bin 0 -> 35373 bytes .../Shared/Assets.xcassets/Contents.json | 6 + examples/swiftui/Shared/Bridging-Header.h | 25 + examples/swiftui/Shared/ContentView.swift | 41 ++ examples/swiftui/Shared/Examples.swift | 185 +++++ examples/swiftui/iOS/Info.plist | 55 ++ examples/swiftui/iOS/OutOfMemoryController.h | 25 + examples/swiftui/iOS/OutOfMemoryController.m | 131 ++++ .../swiftui/iOS/OutOfMemoryPresenter.swift | 32 + examples/swiftui/macOS/Info.plist | 31 + examples/swiftui/macOS/macOS.entitlements | 12 + .../swiftui/swiftui.xcodeproj/project.pbxproj | 661 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcschemes/swiftui (iOS).xcscheme | 78 +++ .../xcschemes/swiftui (macOS).xcscheme | 78 +++ .../xcschemes/swiftui (tvOS).xcscheme | 78 +++ examples/swiftui/tvOS/Info.plist | 37 + 37 files changed, 1889 insertions(+) create mode 100644 examples/swiftui/Shared/AnObjCClass.h create mode 100644 examples/swiftui/Shared/AnObjCClass.mm create mode 100644 examples/swiftui/Shared/AppMain.swift create mode 100644 examples/swiftui/Shared/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png create mode 100644 examples/swiftui/Shared/Assets.xcassets/Contents.json create mode 100644 examples/swiftui/Shared/Bridging-Header.h create mode 100644 examples/swiftui/Shared/ContentView.swift create mode 100644 examples/swiftui/Shared/Examples.swift create mode 100644 examples/swiftui/iOS/Info.plist create mode 100644 examples/swiftui/iOS/OutOfMemoryController.h create mode 100644 examples/swiftui/iOS/OutOfMemoryController.m create mode 100644 examples/swiftui/iOS/OutOfMemoryPresenter.swift create mode 100644 examples/swiftui/macOS/Info.plist create mode 100644 examples/swiftui/macOS/macOS.entitlements create mode 100644 examples/swiftui/swiftui.xcodeproj/project.pbxproj create mode 100644 examples/swiftui/swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (iOS).xcscheme create mode 100644 examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (macOS).xcscheme create mode 100644 examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (tvOS).xcscheme create mode 100644 examples/swiftui/tvOS/Info.plist diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index f344f80ee..4ba9bbf33 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -311,3 +311,22 @@ steps: - xcodebuild -scheme swift-package-manager -configuration Release -destination generic/platform=iOS -derivedDataPath DerivedData -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES - echo "+++ Build Debug iOS Simulator" - xcodebuild -scheme swift-package-manager -configuration Debug -destination generic/platform=iOS\ Simulator -derivedDataPath DerivedData -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES + + - label: 'examples/swiftui' + agents: + queue: opensource-mac-cocoa-11 + commands: + - cd examples/swiftui + - echo "--- Resolve Swift Package Dependencies" + - sed -i '' -e 's/kind = branch/kind = revision/' -e "s/branch = master/revision = ${BUILDKITE_COMMIT}/" swiftui.xcodeproj/project.pbxproj + - xcodebuild -scheme "swiftui (iOS)" -derivedDataPath DerivedData -resolvePackageDependencies + - echo "+++ Build Release iOS" + - xcodebuild -scheme "swiftui (iOS)" -configuration Release -destination generic/platform=iOS -derivedDataPath DerivedData -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES + - echo "+++ Build Debug iOS Simulator" + - xcodebuild -scheme "swiftui (iOS)" -configuration Debug -destination generic/platform=iOS\ Simulator -derivedDataPath DerivedData -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES + - echo "+++ Build Release macOS" + - xcodebuild -scheme "swiftui (macOS)" -configuration Release -derivedDataPath DerivedData -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES + - echo "+++ Build Release tvOS" + - xcodebuild -scheme "swiftui (tvOS)" -configuration Release -destination generic/platform=tvOS -derivedDataPath DerivedData -allowProvisioningUpdates -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES + - echo "+++ Build Debug tvOS Simulator" + - xcodebuild -scheme "swiftui (tvOS)" -configuration Debug -destination generic/platform=tvOS\ Simulator -derivedDataPath DerivedData -allowProvisioningUpdates -quiet build GCC_TREAT_WARNINGS_AS_ERRORS=YES diff --git a/examples/swiftui/Shared/AnObjCClass.h b/examples/swiftui/Shared/AnObjCClass.h new file mode 100644 index 000000000..2c7c8dc7b --- /dev/null +++ b/examples/swiftui/Shared/AnObjCClass.h @@ -0,0 +1,30 @@ +// Copyright (c) 2016 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface AnObjCClass : NSObject + +- (void)trap; +- (void)corruptSomeMemory; +- (void)accessInvalidMemoryAddress; +- (void)throwCxxException; + +@end diff --git a/examples/swiftui/Shared/AnObjCClass.mm b/examples/swiftui/Shared/AnObjCClass.mm new file mode 100644 index 000000000..153dd3356 --- /dev/null +++ b/examples/swiftui/Shared/AnObjCClass.mm @@ -0,0 +1,67 @@ +// Copyright (c) 2016 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AnObjCClass.h" + +#import + +@implementation AnObjCClass + +- (void)trap { + __builtin_trap(); +} + +- (void)corruptSomeMemory { + /* Some random data */ + void *cache[] = { + NULL, NULL, NULL + }; + + void *displayStrings[6] = { + (void *)"This little piggy went to the meerket", + (void *)"This little piggy stayed at home", + cache, + (void *)"This little piggy had roast beef.", + (void *)"This little piggy had none.", + (void *)"And this little piggy went 'Wee! Wee! Wee!' all the way home", + }; + + /* A corrupted/under-retained/re-used piece of memory */ + struct { + void *isa; + } corruptObj; + corruptObj.isa = displayStrings; + + /* Message an invalid/corrupt object. This will deadlock crash reporters + * using Objective-C. */ + [(__bridge id)&corruptObj class]; +} + +- (void)accessInvalidMemoryAddress { + // This should result in an EXC_BAD_ACCESS mach exception with code = KERN_INVALID_ADDRESS and subcode = 0xDEADBEEF + void (* ptr)(void) = (void (*)(void))0xDEADBEEF; + ptr(); +} + +- (void)throwCxxException { + throw std::runtime_error("This is a C++ exception"); +} + +@end diff --git a/examples/swiftui/Shared/AppMain.swift b/examples/swiftui/Shared/AppMain.swift new file mode 100644 index 000000000..82f3958ff --- /dev/null +++ b/examples/swiftui/Shared/AppMain.swift @@ -0,0 +1,108 @@ +// Copyright (c) 2021 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Bugsnag +import SwiftUI + +@main +struct AppMain: App { + + init() { + /** + This is the minimum amount of setup required for Bugsnag to work. Simply add your API key to the app's .plist (Supporting Files/Info.plist) and the application will deliver all error and session notifications to the appropriate dashboard. + + You can find your API key in your Bugsnag dashboard under the settings menu. + */ + Bugsnag.start() + + /** + Bugsnag behavior can be configured through the plist and/or further extended in code by creating a BugsnagConfiguration object and passing it to [Bugsnag startWithConfiguration]. + + All subsequent setup is optional, and will configure your Bugsnag setup in different ways. A few common examples are included here, for more detailed explanations please look at the documented configuration options at https://docs.bugsnag.com/platforms/ios/configuration-options/ + */ + + // Create config object from the application plist +// let config = BugsnagConfiguration.loadConfig() + + // ... or construct an empty object +// let config = BugsnagConfiguration("YOUR-API-KEY") + + /** + This sets some user information that will be attached to each error. + */ +// config.setUser("DefaultUser", withEmail:"Not@real.fake", andName:"Default User") + + /** + The appVersion will let you see what release an error is present in. This will be picked up automatically from your build settings, but can be manually overwritten as well. + */ +// config.appVersion = "1.5.0" + + /** + When persisting a user you won't need to set the user information everytime the app opens, instead it will be persisted between each app session. + */ +// config.persistUser = true + + /** + This option allows you to send more or less detail about errors to Bugsnag. Setting it to Always or Unhandled means you'll have detailed stacktraces of all app threads available when debugging unexpected errors. + */ +// config.sendThreads = .always + + /** + Enabled error types allow you to customize exactly what errors are automatically captured and delivered to your Bugsnag dashboard. A detailed breakdown of each error type can be found in the configuration option documentation. + */ +// config.enabledErrorTypes.ooms = false +// config.enabledErrorTypes.unhandledExceptions = true +// config.enabledErrorTypes.machExceptions = true + + /** + If there's information that you do not wish sent to your Bugsnag dashboard, such as passwords or user information, you can set the keys as redacted. When a notification is sent to Bugsnag all keys matching your set filters will be redacted before they leave your application. + All automatically captured data can be found here: https://docs.bugsnag.com/platforms/ios/automatically-captured-data/. + */ +// config.redactedKeys = ["password", "credit_card_number"] + + /** + Finally, start Bugsnag with the specified configuration: + */ +// Bugsnag.start(with: config) + + #if os(macOS) + /** + Mac exceptions on the main thread are caught by Cocoa and don’t reach Bugsnag by default. + To report these exceptions from a SwiftUI app, it is necessary to override `-[NSApplication reportException:]` + */ + let selector = #selector(NSApplication.reportException(_:)) + if let method = class_getInstanceMethod(NSApplication.self, selector) { + typealias FunctionType = @convention(c) (NSApplication, Selector, NSException) -> Void + let originalFunc = unsafeBitCast(method_getImplementation(method), to: FunctionType.self) + let replacementBlock: @convention(block) (NSApplication, NSException) -> Void = { + Bugsnag.notify($1) + originalFunc($0, selector, $1) + } + method_setImplementation(method, imp_implementationWithBlock(replacementBlock)) + } + #endif + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/examples/swiftui/Shared/Assets.xcassets/AccentColor.colorset/Contents.json b/examples/swiftui/Shared/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/examples/swiftui/Shared/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..045f085ff --- /dev/null +++ b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,172 @@ +{ + "images" : [ + { + "filename" : "Icon-App-20x20@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@1x.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-60x60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-60x60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Icon-App-20x20@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-20x20@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Icon-App-29x29@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-29x29@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Icon-App-40x40@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-40x40@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Icon-App-76x76@1x.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-76x76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Icon-App-83.5x83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "ItunesArtwork@2x.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..5efca42d80d4cc1dec86f348166315649844f0e7 GIT binary patch literal 800 zcmV+*1K<3KP)CAnIfnJr7AvDd~PXdTMCtmLUlyZ3W}hiLL(6~sh3u3 zUTPk!Xi2P6@dj2)k$OP{wXLAWsADpX!C^8vdv71c%iJO<{ol?y@bUBSe=Q;LzGW1N z2-c4JyQWmlp(>8;NC+bT4=747L(f2K#!aY)P{V&L1AqQ?0=dCze>oEeYWhB(a%&a9A^J(cwF|o0M zyZ1Bf|KS)nF5kqdPolM{0!n2MMFh`rC}f|~b!ZEpE^Ea_2;vcD&z#D-^`Ee7_Yr>V zJcg>T!&Eq}awx#2ua+=*(s*Xgn96}&Yj`%4Bd-ky_V+MBDm!a2&!=A z6kmMS0>F2j8##CW8p%YQNW^3C@c=3k!IT`3iq%utLY^bt7ie!?!S=5^c=9+)_lY)o zPPEaV`Ipv~G&{dp&e5KW*x@{)%2TVVjS|7+a_rl;flzB!uH1q65fHHXVRp8!#`7GO ze!dMAkC(Zt2^0abU~+lZu3OCfdGGS*;Q#=QZ;#{5*(+>sJ&1}$u{G{x74Rih0Q+k_mrezNKN9If6#_Q-Tj)}7_S{5!x7;JW(r1vHT^c9gGR)rum@%Kt?6=$RaP=Y6D< zp!*IEz>3#EYYn!|lsj|T`^PsaU9=9c2_`3TBPx7cKmd#(8jTT+IVc%K8-vy^0-%qp zjXyxVP)jLruY~kQ?T@|z|EG2Ho~6_^&srOd*4I4|-+-SO$Xxr|X=&;9Qh>4{IT2+k zwBvqeQ2!yu3-h(_yk{j~@neOg-#nN|SClhnFL1cJmYSM6-1ZQp^g~MNC0uUuIPx zgG>qb2vYbGtWrR08=%2T0;idZ7k|m5iMeDBe*m!YJge~*gS^^1)4nx<7b;d0i#bf3 zx|9>|H(v3izi`I|6hdHP4r6jgFd}0p27~VCVCCus0hT-rlnCQe<-$=WmMaEQ%Ymh))IbZ*Wr;(XJG$fN)|j$HGn zlZ-(rN%O@vs;g_LuCC$2g%+Ywhw4K|s6KdK)v(N0fn#IYU;Ioq~SDu_}+Y+E6uKqUuJsmX|7BDfl~#vV9` zrrJh|OMXty=uGat{|>a{(A02_hQ{+uyXQ7Q`dWiM0yM_px*FHj=qsITW6+LEf+Z>2 z{zJBIUyfxoGMLIgUaO|PJ?sG)4Us5EkA1*bvW9_W#|^K4K;yx6-${%yC@C>ll4y9w zP)Z)UpT!IABR%uW=x7W#=FryO$-sdrcsXw92uDavu)${*$1T)S3bfk8DN?L4Dn6lx>le7G%iaH0tWld9xIXA%pwV(%Jzr z2bmb(i*Y^Zspc5(9jRyB*juqul0jMQsjR}X6hHXhgSg>KU|E!Jsbt%;`@phr!$qwgH2{I{>Le)T*S zloaB&hCsWZUEJ0X#Y+mScjI9SnFk$ES=4iiMcFWxs6Cm8!}+^&Q^ETl$5w_A$IOs zLvi6f6fb^?=eJivVlqTyASHHcG9ZYxb$F+}fDMr_b03~gMfnOUcE85FIqOg<{r-D& z=ruqg1X62+*6gbI5wm7Y;@8i=!n!ASa=QK;o|5UNsF9>+4P(vfViwMy#!LIEm^1fD zjFf2UuSoX@5I{%)j>bfzJielcjq4Wz@Rz^7&8r9Ax1F&-K z4mNJug|IEK6s8B)B|QR!k7d7UYa=6j1SN~|nLYC^ZXGf7ns%oe|IO|_2Y9ahWj;93 zh)7NKzVqq1&kT6gl%;SxA`tC_gd_$J8^oZS(g0|_*vf@-7ojT*fh1Hg(U-L9RY34| z87ZZAR*5=rRmv*`0n57$)7sab`)PJv=VGnB8wLQ8U?W5T@WS}?%}m g+ZXqa`bOD*0OJ4NPVg7fdjJ3c07*qoM6N<$g3T;?*8l(j literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f0a59cd8e383a35c81d05c0bf745af741db3339 GIT binary patch literal 2963 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 literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..18943e04d9793ad1dcdd7f00ac7bb402e4289ca6 GIT binary patch literal 2963 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 JPDHLkV1n%d#?Al$ literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..c39ee6b13686c28aa7e8d1fe94e4af75db77bafd GIT binary patch literal 4673 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 literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc9ada0e730d874d8b5ceb979c02decc2bc232d GIT binary patch literal 4310 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 literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..bd4e92180f9db554e5fe921604dd6f005a38b537 GIT binary patch literal 6617 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 VF+XLP5&4lwigGHlmC`0b{|Ceg-xB}; literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..5c499e6d673221ec6deeac8a02d2fca66acc27b6 GIT binary patch literal 4065 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 TNpV4k00000NkvXXu0mjfP*}C@ literal 0 HcmV?d00001 diff --git a/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/examples/swiftui/Shared/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..97b4556a67c4c4ca37e0a18e5af974dfea4177b0 GIT binary patch literal 8885 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 + + + + bugsnag + + apiKey + YOUR-API-KEY + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UIApplicationSupportsIndirectInputEvents + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/swiftui/iOS/OutOfMemoryController.h b/examples/swiftui/iOS/OutOfMemoryController.h new file mode 100644 index 000000000..44161c8a7 --- /dev/null +++ b/examples/swiftui/iOS/OutOfMemoryController.h @@ -0,0 +1,25 @@ +// Copyright (c) 2016 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface OutOfMemoryController : UIViewController + +@end diff --git a/examples/swiftui/iOS/OutOfMemoryController.m b/examples/swiftui/iOS/OutOfMemoryController.m new file mode 100644 index 000000000..4e68af9bb --- /dev/null +++ b/examples/swiftui/iOS/OutOfMemoryController.m @@ -0,0 +1,131 @@ +// Copyright (c) 2016 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OutOfMemoryController.h" + +#include +#include +#include +#include +#include + +#define PRINT_STATS 1 + +#define MEGABYTE 0x100000 + +@implementation OutOfMemoryController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; +} + +- (void)didReceiveMemoryWarning { + NSLog(@"--> Received a low memory warning"); +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + struct utsname system = {0}; + uname(&system); + NSLog(@"*** Device = %s", system.machine); + + NSUInteger physicalMemory = (NSUInteger)NSProcessInfo.processInfo.physicalMemory; + NSUInteger megabytes = physicalMemory / MEGABYTE; + NSLog(@"*** Physical memory = %lu MB", (unsigned long)megabytes); + + // + // The ActiveHard limit and point at which a memory warning is sent varies by device + // Some data from http://www.chenxiyao.com/article/10/read + // + // Device Total Warn Limit + // ======================================================= + // iPad3,1 iPad 3rd gen 987 560 700 (70%) + // iPhone5,1 iPhone 5 650 + // iPhone6,2 iPhone 5s 1000 600 650 (65%) + // iPhone7,1 iPhone 6 Plus 650 + // iPhone7,2 iPhone 6 650 + // iPhone8,1 iPhone 6s 1380 + // iPhone8,2 iPhone 6s Plus 1380 + // iPhone8,4 iPhone SE 1380 + // iPhone9,1 iPhone 7 1380 + // iPhone9,2 iPhone 7 Plus 2050 + // iPhone10,1 iPhone 8 1380 + // iPhone10,2 iPhone 8 Plus 2050 + // iPhone10,3 iPhone X 1400 + // iPhone11,2 iPhone XS 2050 + // iPhone11,4 iPhone XS Max 2050 + // iPhone11,8 iPhone XR 1400 + // iPhone12,1 iPhone 11 3859 2098 (54%) + // iPhone12,8 iPhone SE (2) 2965 1994 2098 (70%) + // iPhone13,1 iPhone 12 mini 3718 1546 2098 (57%) + // + NSUInteger limit = 0; + task_vm_info_data_t vm_info = {0}; + mach_msg_type_number_t count = TASK_VM_INFO_COUNT; + kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &count); + if (result == KERN_SUCCESS && count >= TASK_VM_INFO_REV4_COUNT) { + limit = (NSUInteger)(vm_info.phys_footprint + vm_info.limit_bytes_remaining) / MEGABYTE; + NSLog(@"*** Memory limit = %lu MB", (unsigned long)limit); + } else if (!strcmp(system.machine, "iPhone6,2")) { + limit = 650; + NSLog(@"*** Memory limit = %lu MB", (unsigned long)limit); + } else { + limit = MIN(2098, megabytes * 70 / 100); + NSLog(@"*** Memory limit = %lu MB (estimated)", (unsigned long)limit); + } + + // The size of the initial block needs to be under the memory warning limit in order for one to be reliably sent. + NSUInteger initial = limit * 70 / 100; + NSLog(@"*** Dirtying an initial block of %lu MB", (unsigned long)initial); + [self consumeMegabytes:initial]; + + NSLog(@"*** Dirtying remaining memory in ~2 seconds"); + NSTimeInterval timeInterval = 2.0 / (limit - initial); + [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(timerFired) userInfo:nil repeats:YES]; +} + +- (void)timerFired { + [self consumeMegabytes:1]; +} + +- (void)consumeMegabytes:(NSUInteger)megabytes { + for (NSUInteger i = 0; i < megabytes; i++) { + volatile char *ptr = malloc(MEGABYTE); + // Originally used NSPageSize() but on iPhone 5s iOS 12 that didn't result in dirtying all the memory allocated. + const int pagesize = 4096; + const int npages = MEGABYTE / pagesize; + for (int page = 0; page < npages; page++) { + ptr[page * pagesize] = 42; // Dirty each page + } + } +#if PRINT_STATS + task_vm_info_data_t info; + mach_msg_type_number_t count = TASK_VM_INFO_COUNT; + kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &info, &count); + assert(result == KERN_SUCCESS); + unsigned long long physicalMemory = NSProcessInfo.processInfo.physicalMemory; + NSLog(@"%4llu / %4llu MB (%llu%%)", info.phys_footprint / MEGABYTE, physicalMemory / MEGABYTE, info.phys_footprint * 100 / physicalMemory); +#endif +} + +@end diff --git a/examples/swiftui/iOS/OutOfMemoryPresenter.swift b/examples/swiftui/iOS/OutOfMemoryPresenter.swift new file mode 100644 index 000000000..e2749d41a --- /dev/null +++ b/examples/swiftui/iOS/OutOfMemoryPresenter.swift @@ -0,0 +1,32 @@ +// Copyright (c) 2021 Bugsnag, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall remain in place +// in this source code. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import SwiftUI + +struct OutOfMemoryPresenter: UIViewControllerRepresentable { + typealias UIViewControllerType = OutOfMemoryController + + func makeUIViewController(context: Context) -> OutOfMemoryController { + OutOfMemoryController() + } + + func updateUIViewController(_ uiViewController: OutOfMemoryController, context: Context) { + } +} diff --git a/examples/swiftui/macOS/Info.plist b/examples/swiftui/macOS/Info.plist new file mode 100644 index 000000000..d6344bbc1 --- /dev/null +++ b/examples/swiftui/macOS/Info.plist @@ -0,0 +1,31 @@ + + + + + bugsnag + + apiKey + YOUR-API-KEY + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + + diff --git a/examples/swiftui/macOS/macOS.entitlements b/examples/swiftui/macOS/macOS.entitlements new file mode 100644 index 000000000..625af03d9 --- /dev/null +++ b/examples/swiftui/macOS/macOS.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.network.client + + + diff --git a/examples/swiftui/swiftui.xcodeproj/project.pbxproj b/examples/swiftui/swiftui.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d071da248 --- /dev/null +++ b/examples/swiftui/swiftui.xcodeproj/project.pbxproj @@ -0,0 +1,661 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 0158BE3626C16E6E002BD41A /* AppMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8126C13133003AD7BB /* AppMain.swift */; }; + 0158BE3726C16E6E002BD41A /* AnObjCClass.mm in Sources */ = {isa = PBXBuildFile; fileRef = 01E53FAA26C13D77003AD7BB /* AnObjCClass.mm */; }; + 0158BE3826C16E6E002BD41A /* Examples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018AB2B826C15AA2009CCDC2 /* Examples.swift */; }; + 0158BE3926C16E6E002BD41A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8226C13133003AD7BB /* ContentView.swift */; }; + 0158BE3B26C16ED3002BD41A /* Bugsnag in Frameworks */ = {isa = PBXBuildFile; productRef = 0158BE3A26C16ED3002BD41A /* Bugsnag */; }; + 018AB2B926C15AA2009CCDC2 /* Examples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018AB2B826C15AA2009CCDC2 /* Examples.swift */; }; + 018AB2BA26C15AA6009CCDC2 /* Examples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018AB2B826C15AA2009CCDC2 /* Examples.swift */; }; + 01E53F9426C13135003AD7BB /* AppMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8126C13133003AD7BB /* AppMain.swift */; }; + 01E53F9526C13135003AD7BB /* AppMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8126C13133003AD7BB /* AppMain.swift */; }; + 01E53F9626C13135003AD7BB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8226C13133003AD7BB /* ContentView.swift */; }; + 01E53F9726C13135003AD7BB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53F8226C13133003AD7BB /* ContentView.swift */; }; + 01E53F9826C13135003AD7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01E53F8326C13135003AD7BB /* Assets.xcassets */; }; + 01E53F9926C13135003AD7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01E53F8326C13135003AD7BB /* Assets.xcassets */; }; + 01E53FA426C13C20003AD7BB /* Bugsnag in Frameworks */ = {isa = PBXBuildFile; productRef = 01E53FA326C13C20003AD7BB /* Bugsnag */; }; + 01E53FA726C13C35003AD7BB /* Bugsnag in Frameworks */ = {isa = PBXBuildFile; productRef = 01E53FA626C13C35003AD7BB /* Bugsnag */; }; + 01E53FAE26C13D77003AD7BB /* AnObjCClass.mm in Sources */ = {isa = PBXBuildFile; fileRef = 01E53FAA26C13D77003AD7BB /* AnObjCClass.mm */; }; + 01E53FAF26C13D77003AD7BB /* AnObjCClass.mm in Sources */ = {isa = PBXBuildFile; fileRef = 01E53FAA26C13D77003AD7BB /* AnObjCClass.mm */; }; + 01E53FB026C13D77003AD7BB /* OutOfMemoryController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E53FAC26C13D77003AD7BB /* OutOfMemoryController.m */; }; + 01E53FB626C1419E003AD7BB /* OutOfMemoryPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E53FB526C1419E003AD7BB /* OutOfMemoryPresenter.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0158BE2726C16E12002BD41A /* swiftui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = swiftui.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0158BE3226C16E14002BD41A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 018AB2B826C15AA2009CCDC2 /* Examples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Examples.swift; sourceTree = ""; }; + 01E53F8126C13133003AD7BB /* AppMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMain.swift; sourceTree = ""; }; + 01E53F8226C13133003AD7BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 01E53F8326C13135003AD7BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 01E53F8826C13135003AD7BB /* swiftui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = swiftui.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 01E53F8B26C13135003AD7BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 01E53F9026C13135003AD7BB /* swiftui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = swiftui.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 01E53F9226C13135003AD7BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 01E53F9326C13135003AD7BB /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; + 01E53FA826C13D77003AD7BB /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; + 01E53FAA26C13D77003AD7BB /* AnObjCClass.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AnObjCClass.mm; sourceTree = ""; }; + 01E53FAB26C13D77003AD7BB /* OutOfMemoryController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutOfMemoryController.h; sourceTree = ""; }; + 01E53FAC26C13D77003AD7BB /* OutOfMemoryController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutOfMemoryController.m; sourceTree = ""; }; + 01E53FAD26C13D77003AD7BB /* AnObjCClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnObjCClass.h; sourceTree = ""; }; + 01E53FB526C1419E003AD7BB /* OutOfMemoryPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutOfMemoryPresenter.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0158BE2426C16E12002BD41A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0158BE3B26C16ED3002BD41A /* Bugsnag in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8526C13135003AD7BB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 01E53FA426C13C20003AD7BB /* Bugsnag in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8D26C13135003AD7BB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 01E53FA726C13C35003AD7BB /* Bugsnag in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0158BE2826C16E12002BD41A /* tvOS */ = { + isa = PBXGroup; + children = ( + 0158BE3226C16E14002BD41A /* Info.plist */, + ); + path = tvOS; + sourceTree = ""; + }; + 01E53F7B26C13133003AD7BB = { + isa = PBXGroup; + children = ( + 01E53F8026C13133003AD7BB /* Shared */, + 01E53F8A26C13135003AD7BB /* iOS */, + 01E53F9126C13135003AD7BB /* macOS */, + 0158BE2826C16E12002BD41A /* tvOS */, + 01E53F8926C13135003AD7BB /* Products */, + 01E53FA526C13C35003AD7BB /* Frameworks */, + ); + sourceTree = ""; + }; + 01E53F8026C13133003AD7BB /* Shared */ = { + isa = PBXGroup; + children = ( + 01E53F8126C13133003AD7BB /* AppMain.swift */, + 01E53F8226C13133003AD7BB /* ContentView.swift */, + 018AB2B826C15AA2009CCDC2 /* Examples.swift */, + 01E53FAD26C13D77003AD7BB /* AnObjCClass.h */, + 01E53FAA26C13D77003AD7BB /* AnObjCClass.mm */, + 01E53F8326C13135003AD7BB /* Assets.xcassets */, + 01E53FA826C13D77003AD7BB /* Bridging-Header.h */, + ); + path = Shared; + sourceTree = ""; + }; + 01E53F8926C13135003AD7BB /* Products */ = { + isa = PBXGroup; + children = ( + 01E53F8826C13135003AD7BB /* swiftui.app */, + 01E53F9026C13135003AD7BB /* swiftui.app */, + 0158BE2726C16E12002BD41A /* swiftui.app */, + ); + name = Products; + sourceTree = ""; + }; + 01E53F8A26C13135003AD7BB /* iOS */ = { + isa = PBXGroup; + children = ( + 01E53F8B26C13135003AD7BB /* Info.plist */, + 01E53FAB26C13D77003AD7BB /* OutOfMemoryController.h */, + 01E53FAC26C13D77003AD7BB /* OutOfMemoryController.m */, + 01E53FB526C1419E003AD7BB /* OutOfMemoryPresenter.swift */, + ); + path = iOS; + sourceTree = ""; + }; + 01E53F9126C13135003AD7BB /* macOS */ = { + isa = PBXGroup; + children = ( + 01E53F9226C13135003AD7BB /* Info.plist */, + 01E53F9326C13135003AD7BB /* macOS.entitlements */, + ); + path = macOS; + sourceTree = ""; + }; + 01E53FA526C13C35003AD7BB /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0158BE2626C16E12002BD41A /* swiftui (tvOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0158BE3526C16E14002BD41A /* Build configuration list for PBXNativeTarget "swiftui (tvOS)" */; + buildPhases = ( + 0158BE2326C16E12002BD41A /* Sources */, + 0158BE2426C16E12002BD41A /* Frameworks */, + 0158BE2526C16E12002BD41A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "swiftui (tvOS)"; + packageProductDependencies = ( + 0158BE3A26C16ED3002BD41A /* Bugsnag */, + ); + productName = tvOS; + productReference = 0158BE2726C16E12002BD41A /* swiftui.app */; + productType = "com.apple.product-type.application"; + }; + 01E53F8726C13135003AD7BB /* swiftui (iOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 01E53F9C26C13135003AD7BB /* Build configuration list for PBXNativeTarget "swiftui (iOS)" */; + buildPhases = ( + 01E53F8426C13135003AD7BB /* Sources */, + 01E53F8526C13135003AD7BB /* Frameworks */, + 01E53F8626C13135003AD7BB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "swiftui (iOS)"; + packageProductDependencies = ( + 01E53FA326C13C20003AD7BB /* Bugsnag */, + ); + productName = "swiftui-multiplatform (iOS)"; + productReference = 01E53F8826C13135003AD7BB /* swiftui.app */; + productType = "com.apple.product-type.application"; + }; + 01E53F8F26C13135003AD7BB /* swiftui (macOS) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 01E53F9F26C13135003AD7BB /* Build configuration list for PBXNativeTarget "swiftui (macOS)" */; + buildPhases = ( + 01E53F8C26C13135003AD7BB /* Sources */, + 01E53F8D26C13135003AD7BB /* Frameworks */, + 01E53F8E26C13135003AD7BB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "swiftui (macOS)"; + packageProductDependencies = ( + 01E53FA626C13C35003AD7BB /* Bugsnag */, + ); + productName = "swiftui-multiplatform (macOS)"; + productReference = 01E53F9026C13135003AD7BB /* swiftui.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 01E53F7C26C13133003AD7BB /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1250; + LastUpgradeCheck = 1250; + TargetAttributes = { + 0158BE2626C16E12002BD41A = { + CreatedOnToolsVersion = 12.5.1; + }; + 01E53F8726C13135003AD7BB = { + CreatedOnToolsVersion = 12.5.1; + LastSwiftMigration = 1250; + }; + 01E53F8F26C13135003AD7BB = { + CreatedOnToolsVersion = 12.5.1; + LastSwiftMigration = 1250; + }; + }; + }; + buildConfigurationList = 01E53F7F26C13133003AD7BB /* Build configuration list for PBXProject "swiftui" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 01E53F7B26C13133003AD7BB; + packageReferences = ( + 01E53FA226C13C20003AD7BB /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */, + ); + productRefGroup = 01E53F8926C13135003AD7BB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 01E53F8726C13135003AD7BB /* swiftui (iOS) */, + 01E53F8F26C13135003AD7BB /* swiftui (macOS) */, + 0158BE2626C16E12002BD41A /* swiftui (tvOS) */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0158BE2526C16E12002BD41A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8626C13135003AD7BB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 01E53F9826C13135003AD7BB /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8E26C13135003AD7BB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 01E53F9926C13135003AD7BB /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0158BE2326C16E12002BD41A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0158BE3626C16E6E002BD41A /* AppMain.swift in Sources */, + 0158BE3826C16E6E002BD41A /* Examples.swift in Sources */, + 0158BE3926C16E6E002BD41A /* ContentView.swift in Sources */, + 0158BE3726C16E6E002BD41A /* AnObjCClass.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8426C13135003AD7BB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 01E53FB026C13D77003AD7BB /* OutOfMemoryController.m in Sources */, + 01E53FAE26C13D77003AD7BB /* AnObjCClass.mm in Sources */, + 01E53F9626C13135003AD7BB /* ContentView.swift in Sources */, + 01E53F9426C13135003AD7BB /* AppMain.swift in Sources */, + 018AB2B926C15AA2009CCDC2 /* Examples.swift in Sources */, + 01E53FB626C1419E003AD7BB /* OutOfMemoryPresenter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01E53F8C26C13135003AD7BB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 018AB2BA26C15AA6009CCDC2 /* Examples.swift in Sources */, + 01E53FAF26C13D77003AD7BB /* AnObjCClass.mm in Sources */, + 01E53F9726C13135003AD7BB /* ContentView.swift in Sources */, + 01E53F9526C13135003AD7BB /* AppMain.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0158BE3326C16E14002BD41A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = tvOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = appletvos; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 14.5; + }; + name = Debug; + }; + 0158BE3426C16E14002BD41A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = tvOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = appletvos; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 14.5; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 01E53F9A26C13135003AD7BB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 01E53F9B26C13135003AD7BB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 01E53F9D26C13135003AD7BB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iOS/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 01E53F9E26C13135003AD7BB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iOS/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 01E53FA026C13135003AD7BB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = macOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 01E53FA126C13135003AD7BB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 372ZUL2ZB7; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = macOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.examples.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_MODULE_NAME = swiftuiapp; + PRODUCT_NAME = swiftui; + SDKROOT = macosx; + SWIFT_OBJC_BRIDGING_HEADER = "Shared/Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0158BE3526C16E14002BD41A /* Build configuration list for PBXNativeTarget "swiftui (tvOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0158BE3326C16E14002BD41A /* Debug */, + 0158BE3426C16E14002BD41A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 01E53F7F26C13133003AD7BB /* Build configuration list for PBXProject "swiftui" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 01E53F9A26C13135003AD7BB /* Debug */, + 01E53F9B26C13135003AD7BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 01E53F9C26C13135003AD7BB /* Build configuration list for PBXNativeTarget "swiftui (iOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 01E53F9D26C13135003AD7BB /* Debug */, + 01E53F9E26C13135003AD7BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 01E53F9F26C13135003AD7BB /* Build configuration list for PBXNativeTarget "swiftui (macOS)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 01E53FA026C13135003AD7BB /* Debug */, + 01E53FA126C13135003AD7BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 01E53FA226C13C20003AD7BB /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/bugsnag/bugsnag-cocoa.git"; + requirement = { + branch = master; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 0158BE3A26C16ED3002BD41A /* Bugsnag */ = { + isa = XCSwiftPackageProductDependency; + package = 01E53FA226C13C20003AD7BB /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */; + productName = Bugsnag; + }; + 01E53FA326C13C20003AD7BB /* Bugsnag */ = { + isa = XCSwiftPackageProductDependency; + package = 01E53FA226C13C20003AD7BB /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */; + productName = Bugsnag; + }; + 01E53FA626C13C35003AD7BB /* Bugsnag */ = { + isa = XCSwiftPackageProductDependency; + package = 01E53FA226C13C20003AD7BB /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */; + productName = Bugsnag; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 01E53F7C26C13133003AD7BB /* Project object */; +} diff --git a/examples/swiftui/swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/swiftui/swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/examples/swiftui/swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (iOS).xcscheme b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (iOS).xcscheme new file mode 100644 index 000000000..8cd155159 --- /dev/null +++ b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (iOS).xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (macOS).xcscheme b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (macOS).xcscheme new file mode 100644 index 000000000..89b105065 --- /dev/null +++ b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (macOS).xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (tvOS).xcscheme b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (tvOS).xcscheme new file mode 100644 index 000000000..03a2557a1 --- /dev/null +++ b/examples/swiftui/swiftui.xcodeproj/xcshareddata/xcschemes/swiftui (tvOS).xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/swiftui/tvOS/Info.plist b/examples/swiftui/tvOS/Info.plist new file mode 100644 index 000000000..d04480dfa --- /dev/null +++ b/examples/swiftui/tvOS/Info.plist @@ -0,0 +1,37 @@ + + + + + bugsnag + + apiKey + YOUR-API-KEY + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchScreen + + UIRequiredDeviceCapabilities + + arm64 + + UIUserInterfaceStyle + Automatic + + From bb514712c5227621211c122ed3ec4d14ce883dfd Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 12 Aug 2021 11:30:04 +0100 Subject: [PATCH 2/6] Add breadcrumbs for UIScene notifications --- Bugsnag.xcodeproj/project.pbxproj | 30 ++++++--- .../Breadcrumbs/BSGNotificationBreadcrumbs.m | 64 ++++++++++++------- Bugsnag/Helpers/BSGUIKit.h | 7 ++ CHANGELOG.md | 7 ++ ...ts.m => BSGNotificationBreadcrumbsTests.m} | 48 +++++++++++--- Tests/UIKitTests.m | 10 +++ Tests/UISceneStub.h | 29 +++++++++ Tests/UISceneStub.m | 59 +++++++++++++++++ features/breadcrumbs.feature | 15 +++++ features/support/env.rb | 5 ++ 10 files changed, 235 insertions(+), 39 deletions(-) rename Tests/{NotificationBreadcrumbTests.m => BSGNotificationBreadcrumbsTests.m} (79%) create mode 100644 Tests/UISceneStub.h create mode 100644 Tests/UISceneStub.m diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index 0f3db2043..438751c6c 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -633,6 +633,11 @@ 0126F7BF25DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0126F7BA25DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m */; }; 0126F7C025DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0126F7BA25DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m */; }; 0126F7C125DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0126F7BA25DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m */; }; + 013D9CD126C5262F0077F0AD /* UISceneStub.h in Headers */ = {isa = PBXBuildFile; fileRef = 013D9CCF26C5262F0077F0AD /* UISceneStub.h */; }; + 013D9CD226C5262F0077F0AD /* UISceneStub.h in Headers */ = {isa = PBXBuildFile; fileRef = 013D9CCF26C5262F0077F0AD /* UISceneStub.h */; }; + 013D9CD326C5262F0077F0AD /* UISceneStub.h in Headers */ = {isa = PBXBuildFile; fileRef = 013D9CCF26C5262F0077F0AD /* UISceneStub.h */; }; + 013D9CD426C5262F0077F0AD /* UISceneStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 013D9CD026C5262F0077F0AD /* UISceneStub.m */; }; + 013D9CD626C5262F0077F0AD /* UISceneStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 013D9CD026C5262F0077F0AD /* UISceneStub.m */; }; 0140D29A25767C9A00FD0306 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; }; 01447605256684500018AB94 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; }; 01468F5225876DC1002B0519 /* BSGNotificationBreadcrumbs.h in Headers */ = {isa = PBXBuildFile; fileRef = 01468F5025876DC1002B0519 /* BSGNotificationBreadcrumbs.h */; }; @@ -646,9 +651,9 @@ 015F528525C15BB7000D1915 /* MRCCanary.m in Sources */ = {isa = PBXBuildFile; fileRef = 015F528325C15BB7000D1915 /* MRCCanary.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 015F528625C15BB7000D1915 /* MRCCanary.m in Sources */ = {isa = PBXBuildFile; fileRef = 015F528325C15BB7000D1915 /* MRCCanary.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 015F528725C15BB7000D1915 /* MRCCanary.m in Sources */ = {isa = PBXBuildFile; fileRef = 015F528325C15BB7000D1915 /* MRCCanary.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 0163BF5925823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */; }; - 0163BF5A25823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */; }; - 0163BF5B25823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */; }; + 0163BF5925823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m */; }; + 0163BF5A25823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m */; }; + 0163BF5B25823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0163BF5825823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m */; }; 016875C6258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */; }; 016875C7258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */; }; 016875C8258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */ = {isa = PBXBuildFile; fileRef = 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */; }; @@ -1301,11 +1306,13 @@ 0126F7BA25DD512B008483C2 /* BSGEventUploadKSCrashReportOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGEventUploadKSCrashReportOperation.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 = ""; }; + 013D9CCF26C5262F0077F0AD /* UISceneStub.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UISceneStub.h; sourceTree = ""; }; + 013D9CD026C5262F0077F0AD /* UISceneStub.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UISceneStub.m; sourceTree = ""; }; 0140D24725765F8F00FD0306 /* BSGUIKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGUIKit.h; sourceTree = ""; }; 01468F5025876DC1002B0519 /* BSGNotificationBreadcrumbs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSGNotificationBreadcrumbs.h; sourceTree = ""; }; 01468F5125876DC1002B0519 /* BSGNotificationBreadcrumbs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSGNotificationBreadcrumbs.m; sourceTree = ""; }; 015F528325C15BB7000D1915 /* MRCCanary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MRCCanary.m; sourceTree = ""; }; - 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationBreadcrumbTests.m; sourceTree = ""; }; + 0163BF5825823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGNotificationBreadcrumbsTests.m; sourceTree = ""; }; 016875C4258D003200DFFF69 /* NSUserDefaultsStub.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSUserDefaultsStub.h; sourceTree = ""; }; 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSUserDefaultsStub.m; sourceTree = ""; }; 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Bugsnag.xcconfig; sourceTree = ""; }; @@ -1704,6 +1711,7 @@ 01BDB1CE25DEBF4600A91FAF /* BSGEventUploadKSCrashReportOperationTests.m */, 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */, CBCF77AA250142E0004AF22A /* BSGJSONSerializationTests.m */, + 0163BF5825823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m */, 008966C82486D43600DC48C2 /* BSGOutOfMemoryTests.m */, CB6419AA25A73E8C00613D25 /* BSGStorageMigratorTests.m */, CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */, @@ -1751,13 +1759,14 @@ 008966D32486D43700DC48C2 /* KSCrash */, 016875C4258D003200DFFF69 /* NSUserDefaultsStub.h */, 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */, - 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */, 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */, 008966B72486D43500DC48C2 /* report.json */, CB6419B325A7419400613D25 /* v0_files */, 008966AE2486D43500DC48C2 /* Swift Tests */, CBA22499251E429C00B87416 /* TestSupport.h */, CBA2249A251E429C00B87416 /* TestSupport.m */, + 013D9CCF26C5262F0077F0AD /* UISceneStub.h */, + 013D9CD026C5262F0077F0AD /* UISceneStub.m */, 01E8765C256684E700F4B70A /* URLSessionMock.h */, 01E8765D256684E700F4B70A /* URLSessionMock.m */, 012482A225627B51003F7243 /* UIKitTests.m */, @@ -2056,6 +2065,7 @@ 008968F42486DAB800DC48C2 /* BugsnagSessionFileStore.h in Headers */, 008968882486DA9600DC48C2 /* BugsnagHandledState.h in Headers */, CBCF77A325010648004AF22A /* BSGJSONSerialization.h in Headers */, + 013D9CD126C5262F0077F0AD /* UISceneStub.h in Headers */, 00896A082486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */, 008969722486DAD000DC48C2 /* BSG_KSSignalInfo.h in Headers */, 008967C22486DA1900DC48C2 /* BugsnagClient+Private.h in Headers */, @@ -2159,6 +2169,7 @@ 0126F79C25DD510E008483C2 /* BSGEventUploadObjectOperation.h in Headers */, 008968892486DA9600DC48C2 /* BugsnagHandledState.h in Headers */, 00896A092486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */, + 013D9CD226C5262F0077F0AD /* UISceneStub.h in Headers */, CBCF77A425010648004AF22A /* BSGJSONSerialization.h in Headers */, 008969732486DAD000DC48C2 /* BSG_KSSignalInfo.h in Headers */, 008967C32486DA1900DC48C2 /* BugsnagClient+Private.h in Headers */, @@ -2262,6 +2273,7 @@ 0126F79D25DD510E008483C2 /* BSGEventUploadObjectOperation.h in Headers */, 0089688A2486DA9600DC48C2 /* BugsnagHandledState.h in Headers */, 00896A0A2486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */, + 013D9CD326C5262F0077F0AD /* UISceneStub.h in Headers */, CBCF77A525010648004AF22A /* BSGJSONSerialization.h in Headers */, 008969742486DAD100DC48C2 /* BSG_KSSignalInfo.h in Headers */, 008967C42486DA1900DC48C2 /* BugsnagClient+Private.h in Headers */, @@ -2624,6 +2636,7 @@ CBAB4DD82510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, 008968A72486DA9600DC48C2 /* BugsnagSession.m in Sources */, 0089683A2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, + 013D9CD426C5262F0077F0AD /* UISceneStub.m in Sources */, 008969F62486DAD100DC48C2 /* BSG_KSCrash.m in Sources */, 0089695D2486DAD000DC48C2 /* BSG_KSMach_x86_32.c in Sources */, 00896A1A2486DAD100DC48C2 /* BSG_KSCrashSentry_MachException.c in Sources */, @@ -2707,7 +2720,7 @@ 008967AB2486D43700DC48C2 /* BSG_KSMachTests.m in Sources */, 0089672A2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */, 01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, - 0163BF5925823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */, + 0163BF5925823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */, 008967392486D43700DC48C2 /* BugsnagEventFromKSCrashReportTest.m in Sources */, 008967182486D43700DC48C2 /* BugsnagErrorTest.m in Sources */, 004E35352487AFDC007FBAE4 /* BugsnagHandledStateTest.m in Sources */, @@ -2859,7 +2872,7 @@ 008967702486D43700DC48C2 /* NSError+SimpleConstructor_Tests.m in Sources */, 0089671C2486D43700DC48C2 /* BugsnagSessionTest.m in Sources */, 008967AC2486D43700DC48C2 /* BSG_KSMachTests.m in Sources */, - 0163BF5A25823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */, + 0163BF5A25823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */, 01BDB1FD25DEBFB300A91FAF /* BSGEventUploadKSCrashReportOperationTests.m in Sources */, 00896A452486DBF000DC48C2 /* BugsnagConfigurationTests.m in Sources */, 008967492486D43700DC48C2 /* BugsnagUserTest.m in Sources */, @@ -2961,6 +2974,7 @@ CBAB4DDA2510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, 008968A92486DA9600DC48C2 /* BugsnagSession.m in Sources */, 0089683C2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, + 013D9CD626C5262F0077F0AD /* UISceneStub.m in Sources */, 008969F82486DAD100DC48C2 /* BSG_KSCrash.m in Sources */, 0089695F2486DAD000DC48C2 /* BSG_KSMach_x86_32.c in Sources */, 00896A1C2486DAD100DC48C2 /* BSG_KSCrashSentry_MachException.c in Sources */, @@ -3039,7 +3053,7 @@ E701FAB12490EFE8008D842F /* ConfigurationApiValidationTest.m in Sources */, 0089677D2486D43700DC48C2 /* RFC3339DateTool_Tests.m in Sources */, CBCF77AD250142E0004AF22A /* BSGJSONSerializationTests.m in Sources */, - 0163BF5B25823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */, + 0163BF5B25823D8D008DC28B /* BSGNotificationBreadcrumbsTests.m in Sources */, 008967562486D43700DC48C2 /* BugsnagOnCrashTest.m in Sources */, 008967A12486D43700DC48C2 /* KSCrashSentry_Tests.m in Sources */, 008967442486D43700DC48C2 /* BugsnagSessionTrackerStopTest.m in Sources */, diff --git a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m index 57065f8ce..cb77faf61 100644 --- a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m +++ b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m @@ -41,18 +41,13 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration #endif _breadcrumbSink = breadcrumbSink; _notificationNameMap = @{ -#if TARGET_OS_TV NSUndoManagerDidRedoChangeNotification : @"Redo Operation", NSUndoManagerDidUndoChangeNotification : @"Undo Operation", +#if TARGET_OS_TV UIScreenBrightnessDidChangeNotification : @"Screen Brightness Changed", - UITableViewSelectionDidChangeNotification : @"TableView Select Change", - UIWindowDidBecomeHiddenNotification : @"Window Became Hidden", UIWindowDidBecomeKeyNotification : @"Window Became Key", - UIWindowDidBecomeVisibleNotification : @"Window Became Visible", UIWindowDidResignKeyNotification : @"Window Resigned Key", #elif TARGET_OS_IOS - NSUndoManagerDidRedoChangeNotification : @"Redo Operation", - NSUndoManagerDidUndoChangeNotification : @"Undo Operation", UIApplicationDidEnterBackgroundNotification : @"App Did Enter Background", UIApplicationDidReceiveMemoryWarningNotification : @"Memory Warning", UIApplicationUserDidTakeScreenshotNotification : @"Took Screenshot", @@ -65,16 +60,11 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration UIKeyboardDidShowNotification : @"Keyboard Became Visible", UIMenuControllerDidHideMenuNotification : @"Did Hide Menu", UIMenuControllerDidShowMenuNotification : @"Did Show Menu", - UITableViewSelectionDidChangeNotification : @"TableView Select Change", UITextFieldTextDidBeginEditingNotification : @"Began Editing Text", UITextFieldTextDidEndEditingNotification : @"Stopped Editing Text", UITextViewTextDidBeginEditingNotification : @"Began Editing Text", UITextViewTextDidEndEditingNotification : @"Stopped Editing Text", - UIWindowDidBecomeHiddenNotification : @"Window Became Hidden", - UIWindowDidBecomeVisibleNotification : @"Window Became Visible", #elif TARGET_OS_OSX - NSUndoManagerDidRedoChangeNotification : @"Redo Operation", - NSUndoManagerDidUndoChangeNotification : @"Undo Operation", NSApplicationDidBecomeActiveNotification : @"App Became Active", NSApplicationDidHideNotification : @"App Did Hide", NSApplicationDidResignActiveNotification : @"App Resigned Active", @@ -91,6 +81,17 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration NSWindowWillMiniaturizeNotification : @"Window Will Miniaturize", NSWorkspaceScreensDidSleepNotification : @"Workspace Screen Slept", NSWorkspaceScreensDidWakeNotification : @"Workspace Screen Awoke", +#endif +#if TARGET_OS_IOS || TARGET_OS_TV + UISceneWillConnectNotification : @"Scene Will Connect", + UISceneDidDisconnectNotification : @"Scene Disconnected", + UISceneDidActivateNotification : @"Scene Activated", + UISceneWillDeactivateNotification : @"Scene Will Deactivate", + UISceneWillEnterForegroundNotification : @"Scene Will Enter Foreground", + UISceneDidEnterBackgroundNotification : @"Scene Entered Background", + UITableViewSelectionDidChangeNotification : @"TableView Select Change", + UIWindowDidBecomeHiddenNotification : @"Window Became Hidden", + UIWindowDidBecomeVisibleNotification : @"Window Became Visible", #endif }; } @@ -107,20 +108,14 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration #endif - (NSArray *)automaticBreadcrumbStateEvents { -#if TARGET_OS_TV return @[ NSUndoManagerDidRedoChangeNotification, NSUndoManagerDidUndoChangeNotification, +#if TARGET_OS_TV UIScreenBrightnessDidChangeNotification, - UIWindowDidBecomeHiddenNotification, UIWindowDidBecomeKeyNotification, - UIWindowDidBecomeVisibleNotification, UIWindowDidResignKeyNotification, - ]; #elif TARGET_OS_IOS - return @[ - NSUndoManagerDidRedoChangeNotification, - NSUndoManagerDidUndoChangeNotification, UIApplicationDidEnterBackgroundNotification, UIApplicationDidReceiveMemoryWarningNotification, UIApplicationUserDidTakeScreenshotNotification, @@ -130,11 +125,7 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration UIKeyboardDidShowNotification, UIMenuControllerDidHideMenuNotification, UIMenuControllerDidShowMenuNotification, - UIWindowDidBecomeHiddenNotification, - UIWindowDidBecomeVisibleNotification, - ]; #elif TARGET_OS_OSX - return @[ NSApplicationDidBecomeActiveNotification, NSApplicationDidResignActiveNotification, NSApplicationDidHideNotification, @@ -146,8 +137,18 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration NSWindowDidExitFullScreenNotification, NSWindowWillCloseNotification, NSWindowWillMiniaturizeNotification, - ]; #endif +#if TARGET_OS_IOS || TARGET_OS_TV + UISceneWillConnectNotification, + UISceneDidDisconnectNotification, + UISceneDidActivateNotification, + UISceneWillDeactivateNotification, + UISceneWillEnterForegroundNotification, + UISceneDidEnterBackgroundNotification, + UIWindowDidBecomeHiddenNotification, + UIWindowDidBecomeVisibleNotification, +#endif + ]; } - (NSArray *)automaticBreadcrumbControlEvents { @@ -258,6 +259,23 @@ - (void)startListeningForStateChangeNotification:(NSNotificationName)notificatio } - (void)addBreadcrumbForNotification:(NSNotification *)notification { +#if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) + if (@available(iOS 13.0, tvOS 13.0, *)) { + if ([notification.name hasPrefix:@"UIScene"] && [notification.object isKindOfClass:UISCENE]) { +#define BSG_STRING_FROM_CLASS(__CLASS__) __CLASS__ ? NSStringFromClass((Class _Nonnull)__CLASS__) : nil + UIScene *scene = notification.object; + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; + metadata[@"configuration"] = scene.session.configuration.name; + metadata[@"delegateClass"] = BSG_STRING_FROM_CLASS(scene.session.configuration.delegateClass); + metadata[@"role"] = scene.session.role; + metadata[@"sceneClass"] = BSG_STRING_FROM_CLASS(scene.session.configuration.sceneClass); + metadata[@"title"] = scene.title.length ? scene.title : nil; + [self addBreadcrumbWithType:BSGBreadcrumbTypeState forNotificationName:notification.name metadata:metadata]; + return; + } + } +#endif [self addBreadcrumbWithType:BSGBreadcrumbTypeState forNotificationName:notification.name]; } diff --git a/Bugsnag/Helpers/BSGUIKit.h b/Bugsnag/Helpers/BSGUIKit.h index d05f39acb..6f72f72e9 100644 --- a/Bugsnag/Helpers/BSGUIKit.h +++ b/Bugsnag/Helpers/BSGUIKit.h @@ -14,6 +14,7 @@ // Calling code should be prepared for classes to not be found when UIKit is not linked. #define UIAPPLICATION NSClassFromString(@"UIApplication") #define UIDEVICE NSClassFromString(@"UIDevice") +#define UISCENE NSClassFromString(@"UIScene") #define UIApplicationDidBecomeActiveNotification @"UIApplicationDidBecomeActiveNotification" #define UIApplicationDidEnterBackgroundNotification @"UIApplicationDidEnterBackgroundNotification" @@ -29,6 +30,12 @@ #define UIKeyboardDidShowNotification @"UIKeyboardDidShowNotification" #define UIMenuControllerDidHideMenuNotification @"UIMenuControllerDidHideMenuNotification" #define UIMenuControllerDidShowMenuNotification @"UIMenuControllerDidShowMenuNotification" +#define UISceneWillConnectNotification @"UISceneWillConnectNotification" +#define UISceneDidDisconnectNotification @"UISceneDidDisconnectNotification" +#define UISceneDidActivateNotification @"UISceneDidActivateNotification" +#define UISceneWillDeactivateNotification @"UISceneWillDeactivateNotification" +#define UISceneWillEnterForegroundNotification @"UISceneWillEnterForegroundNotification" +#define UISceneDidEnterBackgroundNotification @"UISceneDidEnterBackgroundNotification" #define UIScreenBrightnessDidChangeNotification @"UIScreenBrightnessDidChangeNotification" #define UITableViewSelectionDidChangeNotification @"UITableViewSelectionDidChangeNotification" #define UITextFieldTextDidBeginEditingNotification @"UITextFieldTextDidBeginEditingNotification" diff --git a/CHANGELOG.md b/CHANGELOG.md index aeea0bdf3..e832cb4d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========= +## TBD + +### Enhancements + +* Add breadcrumbs for `UIScene` notifications. + [#1165](https://github.com/bugsnag/bugsnag-cocoa/pull/1165) + ## 6.10.4 (2021-08-11) ### Bug fixes diff --git a/Tests/NotificationBreadcrumbTests.m b/Tests/BSGNotificationBreadcrumbsTests.m similarity index 79% rename from Tests/NotificationBreadcrumbTests.m rename to Tests/BSGNotificationBreadcrumbsTests.m index 12cdcc6e9..534ec3c83 100644 --- a/Tests/NotificationBreadcrumbTests.m +++ b/Tests/BSGNotificationBreadcrumbsTests.m @@ -1,5 +1,5 @@ // -// NotificationBreadcrumbTests.m +// BSGNotificationBreadcrumbsTests.m // Bugsnag // // Created by Nick Dowell on 10/12/2020. @@ -13,8 +13,12 @@ #import "BSGNotificationBreadcrumbs.h" #import "BugsnagBreadcrumb+Private.h" +#if TARGET_OS_IOS || TARGET_OS_TV +#import "UISceneStub.h" +#endif -@interface NotificationBreadcrumbTests : XCTestCase + +@interface BSGNotificationBreadcrumbsTests : XCTestCase @property NSNotificationCenter *notificationCenter; @property id notificationObject; @@ -28,7 +32,7 @@ @interface NotificationBreadcrumbTests : XCTestCase #pragma mark - -@implementation NotificationBreadcrumbTests +@implementation BSGNotificationBreadcrumbsTests #pragma mark Setup @@ -61,7 +65,7 @@ - (void)leaveBreadcrumbWithMessage:(NSString *)message metadata:(NSDictionary *) #define TEST(__NAME__, __TYPE__, __MESSAGE__, __METADATA__) do { \ BugsnagBreadcrumb *breadcrumb = [self breadcrumbForNotificationWithName:__NAME__]; \ - XCTAssertNotNil(breadcrumb); \ + XCTAssert([NSJSONSerialization isValidJSONObject:breadcrumb.metadata]); \ if (breadcrumb) { \ XCTAssertEqual(breadcrumb.type, __TYPE__); \ XCTAssertEqualObjects(breadcrumb.message, __MESSAGE__); \ @@ -69,6 +73,13 @@ - (void)leaveBreadcrumbWithMessage:(NSString *)message metadata:(NSDictionary *) } \ } while (0) +#pragma mark Tests + +- (void)testNSUndoManagerNotifications { + TEST(NSUndoManagerDidRedoChangeNotification, BSGBreadcrumbTypeState, @"Redo Operation", @{}); + TEST(NSUndoManagerDidUndoChangeNotification, BSGBreadcrumbTypeState, @"Undo Operation", @{}); +} + #pragma mark iOS Tests #if TARGET_OS_IOS @@ -112,12 +123,33 @@ - (void)testUIWindowNotifications { #if TARGET_OS_IOS || TARGET_OS_TV -// This should be on macOS too! -- (void)testNSUndoManagerNotifications { - TEST(NSUndoManagerDidRedoChangeNotification, BSGBreadcrumbTypeState, @"Redo Operation", @{}); - TEST(NSUndoManagerDidUndoChangeNotification, BSGBreadcrumbTypeState, @"Undo Operation", @{}); +#if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) + +- (void)testUISceneNotifications API_AVAILABLE(ios(13.0), tvos(13.0)) { + self.notificationObject = [[UISceneStub alloc] initWithConfiguration:@"Default Configuration" + delegateClass:[BSGNotificationBreadcrumbsTests class] + role:UIWindowSceneSessionRoleApplication + sceneClass:[UISceneStub class] + title:@"Home"]; + + TEST(UISceneWillConnectNotification, BSGBreadcrumbTypeState, @"Scene Will Connect", + (@{@"configuration": @"Default Configuration", + @"delegateClass": @"BSGNotificationBreadcrumbsTests", + @"role": @"UIWindowSceneSessionRoleApplication", + @"sceneClass": @"UISceneStub", + @"title": @"Home"})); + + self.notificationObject = nil; + TEST(UISceneDidDisconnectNotification, BSGBreadcrumbTypeState, @"Scene Disconnected", @{}); + TEST(UISceneDidActivateNotification, BSGBreadcrumbTypeState, @"Scene Activated", @{}); + TEST(UISceneWillDeactivateNotification, BSGBreadcrumbTypeState, @"Scene Will Deactivate", @{}); + TEST(UISceneWillEnterForegroundNotification, BSGBreadcrumbTypeState, @"Scene Will Enter Foreground", @{}); + TEST(UISceneDidEnterBackgroundNotification, BSGBreadcrumbTypeState, @"Scene Entered Background", @{}); } +#endif + - (void)testUITableViewNotifications { TEST(UITableViewSelectionDidChangeNotification, BSGBreadcrumbTypeNavigation, @"TableView Select Change", @{}); } diff --git a/Tests/UIKitTests.m b/Tests/UIKitTests.m index 740dddf48..6cb2da7ca 100644 --- a/Tests/UIKitTests.m +++ b/Tests/UIKitTests.m @@ -43,6 +43,16 @@ - (void)testNotificationNames { ASSERT_NOTIFICATION_NAME(UIWindowDidBecomeKeyNotification); ASSERT_NOTIFICATION_NAME(UIWindowDidBecomeVisibleNotification); ASSERT_NOTIFICATION_NAME(UIWindowDidResignKeyNotification); + +#if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) + ASSERT_NOTIFICATION_NAME(UISceneWillConnectNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidDisconnectNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidActivateNotification); + ASSERT_NOTIFICATION_NAME(UISceneWillDeactivateNotification); + ASSERT_NOTIFICATION_NAME(UISceneWillEnterForegroundNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidEnterBackgroundNotification); +#endif } @end diff --git a/Tests/UISceneStub.h b/Tests/UISceneStub.h new file mode 100644 index 000000000..0b6854320 --- /dev/null +++ b/Tests/UISceneStub.h @@ -0,0 +1,29 @@ +// +// UISceneStub.h +// BugsnagTests +// +// Created by Nick Dowell on 12/08/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import + +#if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) + +NS_ASSUME_NONNULL_BEGIN + +API_AVAILABLE(ios(13.0), tvos(13.0)) +@interface UISceneStub : NSObject + +- (instancetype)initWithConfiguration:(NSString *)configuration + delegateClass:(Class)delegateClass + role:(UISceneSessionRole)role + sceneClass:(Class)sceneClass + title:(NSString *)title; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Tests/UISceneStub.m b/Tests/UISceneStub.m new file mode 100644 index 000000000..9df8160ce --- /dev/null +++ b/Tests/UISceneStub.m @@ -0,0 +1,59 @@ +// +// UISceneStub.m +// BugsnagTests +// +// Created by Nick Dowell on 12/08/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import "UISceneStub.h" + +#if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ + (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) + +@interface UISceneStub () + +@property (nonatomic) NSString *configurationName; +@property (weak, nonatomic) Class delegateClass; +@property (nonatomic) UISceneSessionRole role; +@property (nonatomic) Class sceneClass; +@property (nonatomic) NSString *title; + +@end + +@implementation UISceneStub + +- (instancetype)initWithConfiguration:(NSString *)configuration + delegateClass:(Class)delegateClass + role:(UISceneSessionRole)role + sceneClass:(Class)sceneClass + title:(NSString *)title { + if ((self = [super init])) { + _configurationName = configuration; + _delegateClass = delegateClass; + _role = role; + _sceneClass = sceneClass; + _title = title; + } + return self; +} + +- (id)session { + return self; +} + +- (id)configuration { + return self; +} + +- (NSString *)name { + return self.configurationName; +} + +- (BOOL)isKindOfClass:(Class)aClass { + return [NSStringFromClass(aClass) isEqualToString:@"UIScene"] || [super isKindOfClass:aClass]; +} + +@end + +#endif diff --git a/features/breadcrumbs.feature b/features/breadcrumbs.feature index 1474a6d88..13d01c0fd 100644 --- a/features/breadcrumbs.feature +++ b/features/breadcrumbs.feature @@ -39,3 +39,18 @@ Feature: Attaching a series of notable events leading up to errors When I run "ModifyBreadcrumbInNotify" And I wait to receive an error Then the event has a "manual" breadcrumb named "Cache locked" + + @skip_below_os_version_13 + @skip_macos + Scenario: State breadcrumbs + When I configure Bugsnag for "HandledErrorScenario" + And I background the app for 2 seconds + And I click the element "run_scenario" + And I wait to receive an error + Then the event has a "state" breadcrumb named "Bugsnag loaded" + # Bugsnag has been started too late to capture some early notifications + And the event has a "state" breadcrumb named "App Did Enter Background" + And the event has a "state" breadcrumb named "App Will Enter Foreground" + And the event has a "state" breadcrumb named "Scene Entered Background" + And the event has a "state" breadcrumb named "Scene Will Enter Foreground" + And the event has a "state" breadcrumb named "Scene Activated" diff --git a/features/support/env.rb b/features/support/env.rb index 0b3d6a965..8d0ff546e 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -10,6 +10,11 @@ Maze.config.receive_requests_wait = 180 unless ENV['STRESS_TEST'].nil? end +# Maze.config.os is not set when running on BrowserStack so cannot implement @skip_below_ios_13 :-( +Before('@skip_below_os_version_13') do |scenario| + skip_this_scenario("Skipping scenario") if Maze.config.os_version < 13 +end + # Skip stress tests unless STRESS_TEST env var is set Before('@stress_test') do |_scenario| skip_this_scenario('Skipping: Run is not configured for stress tests') if ENV['STRESS_TEST'].nil? From b4acb1b28eb18f4e715874f6127d51d1ba00e0dd Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 12 Aug 2021 16:04:07 +0100 Subject: [PATCH 3/6] Add verbose logging to mac test fixture --- .../macos/macOSTestApp/MainWindowController.m | 4 ++++ features/fixtures/macos/macOSTestApp/main.m | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/features/fixtures/macos/macOSTestApp/MainWindowController.m b/features/fixtures/macos/macOSTestApp/MainWindowController.m index a3aa4eb57..5a04b6239 100644 --- a/features/fixtures/macos/macOSTestApp/MainWindowController.m +++ b/features/fixtures/macos/macOSTestApp/MainWindowController.m @@ -51,6 +51,8 @@ - (BugsnagConfiguration *)configuration { } - (IBAction)runScenario:(id)sender { + NSLog(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); + if (!self.scenario) { self.scenario = [Scenario createScenarioNamed:self.scenarioName withConfig:[self configuration]]; self.scenario.eventMode = self.scenarioMetadata; @@ -70,6 +72,8 @@ - (IBAction)runScenario:(id)sender { } - (IBAction)startBugsnag:(id)sender { + NSLog(@"%s %@", __PRETTY_FUNCTION__, self.scenarioName); + self.scenario = [Scenario createScenarioNamed:self.scenarioName withConfig:[self configuration]]; self.scenario.eventMode = self.scenarioMetadata; diff --git a/features/fixtures/macos/macOSTestApp/main.m b/features/fixtures/macos/macOSTestApp/main.m index 413f1121e..c1d48142f 100644 --- a/features/fixtures/macos/macOSTestApp/main.m +++ b/features/fixtures/macos/macOSTestApp/main.m @@ -8,6 +8,20 @@ #import +void NotificationCallback(CFNotificationCenterRef center, void *observer, CFNotificationName cfName, const void *object, CFDictionaryRef userInfo) { + NSString *name = (__bridge NSString *)cfName; + // Ignore high-frequency notifications + if (name == NSMenuDidAddItemNotification || + name == NSMenuDidChangeItemNotification || + name == NSViewDidUpdateTrackingAreasNotification || + name == NSViewFrameDidChangeNotification || + [name hasSuffix:@"UpdateNotification"] || + false) { + return; + } + NSLog(@"%@", name); +} + int main(int argc, const char * argv[]) { [[NSUserDefaults standardUserDefaults] registerDefaults:@{ // Disable state restoration to prevent the following dialog being shown after crashes @@ -19,5 +33,10 @@ int main(int argc, const char * argv[]) { @"NSApplicationCrashOnExceptions": @YES, }]; + // Log (almost) all notifications to aid in diagnosing Appium test flakes + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), + NULL, NotificationCallback, NULL, NULL, + CFNotificationSuspensionBehaviorDeliverImmediately); + return NSApplicationMain(argc, argv); } From 032efea35036915e8a0bd9daf47640296c258498 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 4 Aug 2021 09:40:00 +0100 Subject: [PATCH 4/6] Attach JSON data if testCrashReportWriterConcurrency fails --- Tests/BugsnagBreadcrumbsTest.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Tests/BugsnagBreadcrumbsTest.m b/Tests/BugsnagBreadcrumbsTest.m index 52abe2ca8..8a828e592 100644 --- a/Tests/BugsnagBreadcrumbsTest.m +++ b/Tests/BugsnagBreadcrumbsTest.m @@ -503,7 +503,14 @@ - (void)testCrashReportWriterConcurrency { NSError *error = nil; NSData *data = [NSData dataWithBytesNoCopy:buffer.buffer length:buffer.length freeWhenDone:NO]; - XCTAssert([NSJSONSerialization JSONObjectWithData:data options:0 error:&error], @"%@", error); + if (![NSJSONSerialization JSONObjectWithData:data options:0 error:&error]) { + [self addAttachment:[XCTAttachment attachmentWithUniformTypeIdentifier:@"public.plain-text" + name:@"breadcrumbs.json" + payload:data + userInfo:nil]]; + XCTFail(@"Breadcrumbs JSON could not be parsed: %@", error); + break; + } } free(buffer.buffer); From 17c9c48e4019586e60c790babcd8d200d9061da7 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 16 Aug 2021 12:21:44 +0100 Subject: [PATCH 5/6] Skip UIScene unit tests on older OS versions --- Tests/BSGNotificationBreadcrumbsTests.m | 42 +++++++++++++------------ Tests/UIKitTests.m | 14 +++++---- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/Tests/BSGNotificationBreadcrumbsTests.m b/Tests/BSGNotificationBreadcrumbsTests.m index 534ec3c83..62481d3ea 100644 --- a/Tests/BSGNotificationBreadcrumbsTests.m +++ b/Tests/BSGNotificationBreadcrumbsTests.m @@ -126,26 +126,28 @@ - (void)testUIWindowNotifications { #if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) -- (void)testUISceneNotifications API_AVAILABLE(ios(13.0), tvos(13.0)) { - self.notificationObject = [[UISceneStub alloc] initWithConfiguration:@"Default Configuration" - delegateClass:[BSGNotificationBreadcrumbsTests class] - role:UIWindowSceneSessionRoleApplication - sceneClass:[UISceneStub class] - title:@"Home"]; - - TEST(UISceneWillConnectNotification, BSGBreadcrumbTypeState, @"Scene Will Connect", - (@{@"configuration": @"Default Configuration", - @"delegateClass": @"BSGNotificationBreadcrumbsTests", - @"role": @"UIWindowSceneSessionRoleApplication", - @"sceneClass": @"UISceneStub", - @"title": @"Home"})); - - self.notificationObject = nil; - TEST(UISceneDidDisconnectNotification, BSGBreadcrumbTypeState, @"Scene Disconnected", @{}); - TEST(UISceneDidActivateNotification, BSGBreadcrumbTypeState, @"Scene Activated", @{}); - TEST(UISceneWillDeactivateNotification, BSGBreadcrumbTypeState, @"Scene Will Deactivate", @{}); - TEST(UISceneWillEnterForegroundNotification, BSGBreadcrumbTypeState, @"Scene Will Enter Foreground", @{}); - TEST(UISceneDidEnterBackgroundNotification, BSGBreadcrumbTypeState, @"Scene Entered Background", @{}); +- (void)testUISceneNotifications { + if (@available(iOS 13.0, tvOS 13.0, *)) { + self.notificationObject = [[UISceneStub alloc] initWithConfiguration:@"Default Configuration" + delegateClass:[BSGNotificationBreadcrumbsTests class] + role:UIWindowSceneSessionRoleApplication + sceneClass:[UISceneStub class] + title:@"Home"]; + + TEST(UISceneWillConnectNotification, BSGBreadcrumbTypeState, @"Scene Will Connect", + (@{@"configuration": @"Default Configuration", + @"delegateClass": @"BSGNotificationBreadcrumbsTests", + @"role": @"UIWindowSceneSessionRoleApplication", + @"sceneClass": @"UISceneStub", + @"title": @"Home"})); + + self.notificationObject = nil; + TEST(UISceneDidDisconnectNotification, BSGBreadcrumbTypeState, @"Scene Disconnected", @{}); + TEST(UISceneDidActivateNotification, BSGBreadcrumbTypeState, @"Scene Activated", @{}); + TEST(UISceneWillDeactivateNotification, BSGBreadcrumbTypeState, @"Scene Will Deactivate", @{}); + TEST(UISceneWillEnterForegroundNotification, BSGBreadcrumbTypeState, @"Scene Will Enter Foreground", @{}); + TEST(UISceneDidEnterBackgroundNotification, BSGBreadcrumbTypeState, @"Scene Entered Background", @{}); + } } #endif diff --git a/Tests/UIKitTests.m b/Tests/UIKitTests.m index 6cb2da7ca..43f27ffcf 100644 --- a/Tests/UIKitTests.m +++ b/Tests/UIKitTests.m @@ -46,12 +46,14 @@ - (void)testNotificationNames { #if (defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) || \ (defined(__TVOS_13_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_13_0) - ASSERT_NOTIFICATION_NAME(UISceneWillConnectNotification); - ASSERT_NOTIFICATION_NAME(UISceneDidDisconnectNotification); - ASSERT_NOTIFICATION_NAME(UISceneDidActivateNotification); - ASSERT_NOTIFICATION_NAME(UISceneWillDeactivateNotification); - ASSERT_NOTIFICATION_NAME(UISceneWillEnterForegroundNotification); - ASSERT_NOTIFICATION_NAME(UISceneDidEnterBackgroundNotification); + if (@available(iOS 13.0, tvOS 13.0, *)) { + ASSERT_NOTIFICATION_NAME(UISceneWillConnectNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidDisconnectNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidActivateNotification); + ASSERT_NOTIFICATION_NAME(UISceneWillDeactivateNotification); + ASSERT_NOTIFICATION_NAME(UISceneWillEnterForegroundNotification); + ASSERT_NOTIFICATION_NAME(UISceneDidEnterBackgroundNotification); + } #endif } From b150123c37728599d63935a6c419a231a5b4bf4c Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 18 Aug 2021 11:22:23 +0100 Subject: [PATCH 6/6] Release v6.11.0 --- .jazzy.yaml | 4 ++-- Bugsnag.podspec.json | 4 ++-- Bugsnag/Payload/BugsnagNotifier.m | 2 +- CHANGELOG.md | 2 +- Framework/Info.plist | 2 +- Tests/Info.plist | 2 +- VERSION | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 62b6556f0..a1aed84c9 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -2,11 +2,11 @@ author_url: "https://www.bugsnag.com" author: "Bugsnag Inc" clean: false # avoid deleting docs/.git framework_root: "Bugsnag" -github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.10.4/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.11.0/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.10.4" +module_version: "6.11.0" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index 40389587d..47909655f 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.10.4", + "version": "6.11.0", "summary": "The Bugsnag crash reporting framework for Apple platforms.", "homepage": "https://bugsnag.com", "license": "MIT", @@ -9,7 +9,7 @@ }, "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.10.4" + "tag": "v6.11.0" }, "frameworks": [ "Foundation", diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index 4eabeb72b..a45a8a743 100644 --- a/Bugsnag/Payload/BugsnagNotifier.m +++ b/Bugsnag/Payload/BugsnagNotifier.m @@ -23,7 +23,7 @@ - (instancetype)init { #else self.name = @"Bugsnag Objective-C"; #endif - self.version = @"6.10.4"; + self.version = @"6.11.0"; self.url = @"https://github.com/bugsnag/bugsnag-cocoa"; self.dependencies = [NSMutableArray new]; } diff --git a/CHANGELOG.md b/CHANGELOG.md index e832cb4d9..9fe8bca02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Changelog ========= -## TBD +## 6.11.0 (2021-08-18) ### Enhancements diff --git a/Framework/Info.plist b/Framework/Info.plist index b19f8f469..f02eb3959 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.10.4 + 6.11.0 CFBundleVersion 1 diff --git a/Tests/Info.plist b/Tests/Info.plist index ddfc429f7..a8b4e3342 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.10.4 + 6.11.0 CFBundleVersion 1 diff --git a/VERSION b/VERSION index 1678f3d43..1de66e5ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.10.4 +6.11.0