diff --git a/.github/workflows/build-sample.yml b/.github/workflows/build-sample.yml new file mode 100644 index 000000000..4537214db --- /dev/null +++ b/.github/workflows/build-sample.yml @@ -0,0 +1,69 @@ +name: Build Sample + +on: + pull_request: + paths: + - 'Sources/**/include/**' + - 'Package.swift' + - 'Samples/**' + - '.github/workflows/build-sample.yml' + + push: + branches: + - master + + schedule: + - cron: '0 0 1 * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + sample: + runs-on: macos-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - platform: iOS + - platform: macOS + - platform: tvOS + - platform: watchOS + - platform: visionOS + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Use Latest Stable Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Install visionOS Platform + if: matrix.platform == 'visionOS' + shell: bash + run: | + # See https://github.com/actions/runner-images/issues/8144#issuecomment-1902072070 + defaults write com.apple.dt.Xcode AllowUnsupportedVisionOSHost -bool YES + defaults write com.apple.CoreSimulator AllowUnsupportedVisionOSHost -bool YES + xcodebuild -downloadPlatform visionOS + + - name: Install Tuist + run: | + brew tap tuist/tuist + brew install tuist@4.18.0 + + - name: Generate Project + working-directory: ./Samples + run: tuist generate --verbose --no-open + + - name: Run Build + uses: bamx23/xcodebuild@os-version + timeout-minutes: 10 + with: + action: build + workspace: "Samples/KSCrashSamples.xcworkspace" + scheme: "Sample" + platform: ${{ matrix.platform }} diff --git a/.gitignore b/.gitignore index 9ac66659f..ec9ee0b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,8 @@ Carthage/Build .build .swiftpm/xcode/xcuserdata .swiftpm/package.xcworkspace/xcuserdata +### Samples ### +/Samples/Common/.swiftpm +/Samples/**/Derived +/Samples/**/*.xcodeproj +/Samples/**/*.xcworkspace diff --git a/Samples/Common/Package.swift b/Samples/Common/Package.swift new file mode 100644 index 000000000..7a5c0712b --- /dev/null +++ b/Samples/Common/Package.swift @@ -0,0 +1,49 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "KSCrashSamplesCommon", + platforms: [ + .iOS(.v14), + .tvOS(.v14), + .watchOS(.v7), + .macOS(.v11), + ], + products: [ + .library( + name: "LibraryBridge", + targets: ["LibraryBridge"] + ), + .library( + name: "CrashTriggers", + targets: ["CrashTriggers"] + ), + .library( + name: "SampleUI", + targets: ["SampleUI"] + ), + ], + dependencies: [ + .package(path: "../.."), + ], + targets: [ + .target( + name: "LibraryBridge", + dependencies: [ + .product(name: "Recording", package: "KSCrash"), + .product(name: "Reporting", package: "KSCrash"), + ] + ), + .target( + name: "CrashTriggers" + ), + .target( + name: "SampleUI", + dependencies: [ + .target(name: "LibraryBridge"), + .target(name: "CrashTriggers"), + ] + ) + ] +) diff --git a/Samples/Common/Sources/CrashTriggers/CrashTriggers.mm b/Samples/Common/Sources/CrashTriggers/CrashTriggers.mm new file mode 100644 index 000000000..d0e8dd2fe --- /dev/null +++ b/Samples/Common/Sources/CrashTriggers/CrashTriggers.mm @@ -0,0 +1,39 @@ +// +// CrashTriggers.mm +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 "CrashTriggers.h" + +@implementation CrashTriggers + ++ (void)nsexception +{ + NSException *exc = [NSException exceptionWithName:NSGenericException + reason:@"Test" + userInfo:@{ @"a": @"b"}]; + [exc raise]; +} + +@end diff --git a/Samples/Common/Sources/CrashTriggers/include/CrashTriggers.h b/Samples/Common/Sources/CrashTriggers/include/CrashTriggers.h new file mode 100644 index 000000000..3b6aa6887 --- /dev/null +++ b/Samples/Common/Sources/CrashTriggers/include/CrashTriggers.h @@ -0,0 +1,33 @@ +// +// CrashTriggers.h +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 CrashTriggers : NSObject + ++ (void)nsexception; + +@end diff --git a/Samples/Common/Sources/LibraryBridge/RecordingSample.swift b/Samples/Common/Sources/LibraryBridge/RecordingSample.swift new file mode 100644 index 000000000..00762e65f --- /dev/null +++ b/Samples/Common/Sources/LibraryBridge/RecordingSample.swift @@ -0,0 +1,35 @@ +// +// RecordingSample.swift +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 Foundation +import KSCrashRecording + +public class RecordingSample { + public static func simpleInstall() { + let config = KSCrashConfiguration() + KSCrash.shared().install(with: config) + } +} diff --git a/Samples/Common/Sources/LibraryBridge/ReportingSample.swift b/Samples/Common/Sources/LibraryBridge/ReportingSample.swift new file mode 100644 index 000000000..e213ca2aa --- /dev/null +++ b/Samples/Common/Sources/LibraryBridge/ReportingSample.swift @@ -0,0 +1,37 @@ +// +// ReportingSample.swift +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 Foundation +import KSCrashRecording +import KSCrashFilters +import KSCrashSinks + +public class ReportingSample { + public static func logToConsole() { + KSCrash.shared().sink = CrashReportSinkConsole.filter().defaultCrashReportFilterSet() + KSCrash.shared().sendAllReports() + } +} diff --git a/Samples/Common/Sources/SampleUI/SampleView.swift b/Samples/Common/Sources/SampleUI/SampleView.swift new file mode 100644 index 000000000..bb5ebb6cd --- /dev/null +++ b/Samples/Common/Sources/SampleUI/SampleView.swift @@ -0,0 +1,54 @@ +// +// SampleView.swift +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 +import LibraryBridge +import CrashTriggers + +public struct SampleView: View { + public init() { } + + public var body: some View { + NavigationView { + List { + Section(header: Text("Crashes")) { + Button("NSException") { + CrashTriggers.nsexception() + } + } + Section(header: Text("Reporting")) { + Button("Log To Console") { + ReportingSample.logToConsole() + } + } + } + .navigationTitle("KSCrash Sample") + } + .onAppear { + RecordingSample.simpleInstall() + } + } +} diff --git a/Samples/Project.swift b/Samples/Project.swift new file mode 100644 index 000000000..b761b2bc9 --- /dev/null +++ b/Samples/Project.swift @@ -0,0 +1,43 @@ +import ProjectDescription + +let project = Project( + name: "KSCrashSamples", + packages: [ + .local(path: "Common"), + ], + targets: [ + .target( + name: "Sample", + destinations: .allForSample, + product: .app, + bundleId: "com.github.kstenerud.KSCrash.Sample", + infoPlist: InfoPlist.extendingDefault(with: [ + "UILaunchScreen": [ + "UIImageName": "LaunchImage", + "UIBackgroundColor": "LaunchScreenColor", + ], + "UISupportedInterfaceOrientations": ["UIInterfaceOrientationPortrait"], + "CFBundleDisplayName": "KSCrashSample", + "WKApplication": true, + "WKWatchOnly": true, + ]), + sources: ["Sources/**"], + dependencies: [ + .package(product: "SampleUI", type: .runtime), + ] + ), + ] +) + +extension Set where Element == ProjectDescription.Destination { + static var allForSample: Self { + let sets: [Set] = [ + .iOS, + .macOS, + .tvOS, + .watchOS, + .visionOS, + ] + return sets.reduce(.init()) { $0.union($1) } + } +} diff --git a/Samples/Sources/App.swift b/Samples/Sources/App.swift new file mode 100644 index 000000000..44e044d91 --- /dev/null +++ b/Samples/Sources/App.swift @@ -0,0 +1,41 @@ +// +// App.swift +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 +import SampleUI + +@main +struct SampleApp: App { +#if os(macOS) + @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate +#endif + + var body: some Scene { + WindowGroup { + SampleView() + } + } +} diff --git a/Samples/Sources/AppDelegate.swift b/Samples/Sources/AppDelegate.swift new file mode 100644 index 000000000..43970ded9 --- /dev/null +++ b/Samples/Sources/AppDelegate.swift @@ -0,0 +1,39 @@ +// +// AppDelegate.swift +// +// Created by Nikolay Volosatov on 2024-06-23. +// +// Copyright (c) 2012 Karl Stenerud. 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 Foundation + +#if os(macOS) + +import AppKit + +class AppDelegate: NSObject, NSApplicationDelegate { + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} + +#endif