diff --git a/crash-reporting-core/src/commonMain/kotlin/dev/icerock/moko/crashreporting/core/ExceptionLogger.kt b/crash-reporting-core/src/commonMain/kotlin/dev/icerock/moko/crashreporting/core/ExceptionLogger.kt index 606a096..a95740f 100644 --- a/crash-reporting-core/src/commonMain/kotlin/dev/icerock/moko/crashreporting/core/ExceptionLogger.kt +++ b/crash-reporting-core/src/commonMain/kotlin/dev/icerock/moko/crashreporting/core/ExceptionLogger.kt @@ -9,4 +9,5 @@ interface ExceptionLogger { fun setCustomValue(value: String, forKey: String) fun recordException(throwable: Throwable) fun log(message: String) + fun logFatal(throwable: Throwable) } diff --git a/crash-reporting-core/src/iosMain/kotlin/dev/icerock/moko/crashreporting/core/setupUnhandledExcaptionsHandler.kt b/crash-reporting-core/src/iosMain/kotlin/dev/icerock/moko/crashreporting/core/setupUnhandledExcaptionsHandler.kt new file mode 100644 index 0000000..0aab517 --- /dev/null +++ b/crash-reporting-core/src/iosMain/kotlin/dev/icerock/moko/crashreporting/core/setupUnhandledExcaptionsHandler.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.moko.crashreporting.core + +import kotlin.native.concurrent.freeze + +fun setupUnhandledExceptionsHandler(logger: ExceptionLogger) { + val hook: ReportUnhandledExceptionHook = { exc: Throwable -> + logger.logFatal(throwable = exc) + } + setUnhandledExceptionHook(hook.freeze()) +} diff --git a/crash-reporting-crashlytics/src/iosMain/swift/DynamicProxy/FirebaseDynamicProxy.swift b/crash-reporting-crashlytics/src/iosMain/swift/DynamicProxy/FirebaseDynamicProxy.swift index 69510e2..6df2553 100644 --- a/crash-reporting-crashlytics/src/iosMain/swift/DynamicProxy/FirebaseDynamicProxy.swift +++ b/crash-reporting-crashlytics/src/iosMain/swift/DynamicProxy/FirebaseDynamicProxy.swift @@ -15,5 +15,6 @@ public protocol FirebaseCrashlyticsReporter { func setUserId(userId: String) func setCustomValue(value: String, forKey: String) func recordException(name: String, reason: String, stackTrace: [UInt]) + func recordFatalException(name: String, reason: String, stackTrace: [UInt]) func log(message: String) } diff --git a/crash-reporting-crashlytics/src/iosMain/swift/StaticReporter/FirebaseStaticReporter.swift b/crash-reporting-crashlytics/src/iosMain/swift/StaticReporter/FirebaseStaticReporter.swift index bd7a88d..75478a4 100644 --- a/crash-reporting-crashlytics/src/iosMain/swift/StaticReporter/FirebaseStaticReporter.swift +++ b/crash-reporting-crashlytics/src/iosMain/swift/StaticReporter/FirebaseStaticReporter.swift @@ -28,6 +28,14 @@ public class MokoFirebaseCrashlytics: FirebaseCrashlyticsReporter { Crashlytics.crashlytics().record(exceptionModel: exceptionModel) } + public func recordFatalException( + name: String, + reason: String, + stackTrace: [UInt] + ) { + recordException(name: name, reason: reason, stackTrace: stackTrace) + } + public func log(message: String) { Crashlytics.crashlytics().log(message) } diff --git a/crash-reporting-crashlytics/src/iosX64Main/kotlin/dev/icerock/moko/crashreporting/crashlytics/CrashlyticsLogger.kt b/crash-reporting-crashlytics/src/iosX64Main/kotlin/dev/icerock/moko/crashreporting/crashlytics/CrashlyticsLogger.kt index 3610f4a..79baa48 100644 --- a/crash-reporting-crashlytics/src/iosX64Main/kotlin/dev/icerock/moko/crashreporting/crashlytics/CrashlyticsLogger.kt +++ b/crash-reporting-crashlytics/src/iosX64Main/kotlin/dev/icerock/moko/crashreporting/crashlytics/CrashlyticsLogger.kt @@ -3,12 +3,21 @@ package dev.icerock.moko.crashreporting.crashlytics import cocoapods.MCRCDynamicProxy.FirebaseCrashlyticsReporterProtocol import cocoapods.MCRCDynamicProxy.FirebaseDynamicProxy import dev.icerock.moko.crashreporting.core.CrashReportingCore +import dev.icerock.moko.crashreporting.core.setupUnhandledExceptionsHandler import dev.icerock.moko.crashreporting.core.ExceptionLogger import dev.icerock.moko.crashreporting.core.getStackTrace +import kotlin.native.concurrent.freeze actual class CrashlyticsLogger actual constructor() : ExceptionLogger { - private val reporter: FirebaseCrashlyticsReporterProtocol = FirebaseDynamicProxy.reporter() - ?: throw IllegalStateException("MokoFirebaseCrashlytics.setup() should be called in swift before creating CrashlyticsLogger") + + private val reporter: FirebaseCrashlyticsReporterProtocol + + init { + reporter = FirebaseDynamicProxy.reporter() + ?: throw IllegalStateException("MokoFirebaseCrashlytics.setup() should be called in swift before creating CrashlyticsLogger") + freeze() + setupUnhandledExceptionsHandler(this) + } override fun log(message: String) { reporter.logWithMessage(message) @@ -16,9 +25,8 @@ actual class CrashlyticsLogger actual constructor() : ExceptionLogger { @ExperimentalUnsignedTypes override fun recordException(throwable: Throwable) { - val crashReportingCore = CrashReportingCore - val name = crashReportingCore.getExceptionName(throwable) - val stackTrace = crashReportingCore.getStackTrace(throwable) + val name = CrashReportingCore.getExceptionName(throwable) + val stackTrace = CrashReportingCore.getStackTrace(throwable) reporter.recordExceptionWithName( name = name, @@ -34,6 +42,17 @@ actual class CrashlyticsLogger actual constructor() : ExceptionLogger { ) } + override fun logFatal(throwable: Throwable) { + val name = CrashReportingCore.getExceptionName(throwable) + val stackTrace = CrashReportingCore.getStackTrace(throwable) + + reporter.recordFatalExceptionWithName( + name = name, + reason = throwable.message.orEmpty(), + stackTrace = stackTrace + ) + } + override fun setUserId(userId: String) { reporter.setUserIdWithUserId(userId) } diff --git a/sample/ios-app/TestProj.xcodeproj/project.pbxproj b/sample/ios-app/TestProj.xcodeproj/project.pbxproj index 5fbea82..8640dee 100644 --- a/sample/ios-app/TestProj.xcodeproj/project.pbxproj +++ b/sample/ios-app/TestProj.xcodeproj/project.pbxproj @@ -116,7 +116,8 @@ 287627FC1F319065007FA12B /* Frameworks */, 287627FD1F319065007FA12B /* Resources */, 3002F1129AFDA8934843C420 /* [CP] Embed Pods Frameworks */, - 49EA9D27252EE521005FC8CC /* Firebase */, + 49EA9D27252EE521005FC8CC /* Firebase Application submit */, + 45A70C682599BD3F005CF12F /* Firebase MultiPlatformLibrary submit */, ); buildRules = ( ); @@ -193,7 +194,25 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TestProj/Pods-TestProj-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 49EA9D27252EE521005FC8CC /* Firebase */ = { + 45A70C682599BD3F005CF12F /* Firebase MultiPlatformLibrary submit */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Firebase MultiPlatformLibrary submit"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/FirebaseCrashlytics/upload-symbols\" -gsp \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/GoogleService-Info.plist\" -p ios \"${DWARF_DSYM_FOLDER_PATH}/MultiPlatformLibrary/MultiPlatformLibrary.framework.dSYM\" --debug\n"; + }; + 49EA9D27252EE521005FC8CC /* Firebase Application submit */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -204,14 +223,14 @@ "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); - name = Firebase; + name = "Firebase Application submit"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/FirebaseCrashlytics/run\"\n\"${PODS_ROOT}/FirebaseCrashlytics/upload-symbols\" -gsp \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/GoogleService-Info.plist\" -p ios \"${DWARF_DSYM_FOLDER_PATH}/MultiPlatformLibrary.framework.dSYM\" \n"; + shellScript = "\"${PODS_ROOT}/FirebaseCrashlytics/run\" --debug\n"; }; B8C78C58767A89D2A1A202F0 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; diff --git a/sample/ios-app/src/GoogleService-Info.plist b/sample/ios-app/src/GoogleService-Info.plist new file mode 100644 index 0000000..303cae0 --- /dev/null +++ b/sample/ios-app/src/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 149963383979-cdc8ptbcfqdofkk5jfdm4ln8m7ngv6p8.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.149963383979-cdc8ptbcfqdofkk5jfdm4ln8m7ngv6p8 + API_KEY + AIzaSyBnehCN7AvIrtno7WGpCjyHfY3LQZ6f-3w + GCM_SENDER_ID + 149963383979 + PLIST_VERSION + 1 + BUNDLE_ID + dev.icerock.moko.sample.crashReporting-test + PROJECT_ID + moko-crash-report + STORAGE_BUCKET + moko-crash-report.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:149963383979:ios:70426b87b87dee8ae543ee + DATABASE_URL + https://moko-crash-report.firebaseio.com + + \ No newline at end of file diff --git a/sample/ios-app/src/Resources/Base.lproj/Main.storyboard b/sample/ios-app/src/Resources/Base.lproj/Main.storyboard index 68c2f4f..9f7f7b4 100755 --- a/sample/ios-app/src/Resources/Base.lproj/Main.storyboard +++ b/sample/ios-app/src/Resources/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -20,36 +20,43 @@ - + - - - - + diff --git a/sample/ios-app/src/TestViewController.swift b/sample/ios-app/src/TestViewController.swift index a111ec5..3ac3348 100755 --- a/sample/ios-app/src/TestViewController.swift +++ b/sample/ios-app/src/TestViewController.swift @@ -7,7 +7,12 @@ import MultiPlatformLibrary class TestViewController: UIViewController { - let testing = Testing() + var testing: Testing! + + override func viewDidLoad() { + super.viewDidLoad() + testing = Testing() + } @IBAction func onSetUserId() { @@ -28,4 +33,9 @@ class TestViewController: UIViewController { func onSendException() { testing.logException() } + + @IBAction + func onSendFatal() { + testing.logFatalException() + } } diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/Testing.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/Testing.kt index ae3f70b..a3bbab2 100644 --- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/Testing.kt +++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/Testing.kt @@ -45,4 +45,8 @@ class Testing { Napier.e(message = "test is not a number", tag = "Non fatal", throwable = e) } } + + fun logFatalException() { + "test".toInt() + } }