From 0ec0394fa3c5ea9d8b9fe917021870dffb9d1e8c Mon Sep 17 00:00:00 2001 From: Andrey Dorofeev Date: Fri, 25 Dec 2020 09:10:37 +0700 Subject: [PATCH 1/3] #504 added test setupUnhandledExceptionsHandler for ios --- .../crashreporting/core/ExceptionLogger.kt | 1 + .../core/setupUnhandledExcaptionsHandler.kt | 36 +++++++++++++++++++ .../crashlytics/CrashlyticsLogger.kt | 11 ++++++ sample/ios-app/Podfile.lock | 2 +- sample/ios-app/src/TestViewController.swift | 7 +++- .../kotlin/com/icerockdev/library/Testing.kt | 8 ++--- 6 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 crash-reporting-core/src/iosMain/kotlin/dev/icerock/moko/crashreporting/core/setupUnhandledExcaptionsHandler.kt 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..137c8e9 --- /dev/null +++ b/crash-reporting-core/src/iosMain/kotlin/dev/icerock/moko/crashreporting/core/setupUnhandledExcaptionsHandler.kt @@ -0,0 +1,36 @@ +/* + * 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.AtomicReference +import kotlin.native.concurrent.freeze +import kotlinx.cinterop.staticCFunction +import platform.Foundation.NSThread +import platform.darwin.* +import kotlin.native.concurrent.DetachedObjectGraph +import kotlin.native.concurrent.TransferMode +import kotlin.native.concurrent.attach + +fun CrashReportingCore.setupUnhandledExceptionsHandler(logger: ExceptionLogger) { + val atomicReference = AtomicReference(logger).freeze() + val hook: ReportUnhandledExceptionHook = { exc: Throwable -> + val freezeExc = exc.freeze() + dispatch_async_f( + dispatch_get_main_queue(), + DetachedObjectGraph(TransferMode.UNSAFE) { + Pair( + atomicReference, + freezeExc + ) + }.asCPointer(), + staticCFunction { pointer -> + val pair = + DetachedObjectGraph, Throwable>>(pointer).attach() + pair.first.value.logFatal(throwable = pair.second) + } + ) + } + setUnhandledExceptionHook(hook.freeze()) +} \ No newline at end of file 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..4191698 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,10 +3,17 @@ 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 actual class CrashlyticsLogger actual constructor() : ExceptionLogger { + + init { + val crashReportingCore = CrashReportingCore + crashReportingCore.setupUnhandledExceptionsHandler(this) + } + private val reporter: FirebaseCrashlyticsReporterProtocol = FirebaseDynamicProxy.reporter() ?: throw IllegalStateException("MokoFirebaseCrashlytics.setup() should be called in swift before creating CrashlyticsLogger") @@ -34,6 +41,10 @@ actual class CrashlyticsLogger actual constructor() : ExceptionLogger { ) } + override fun logFatal(throwable: Throwable) { + println("TODO: log fatal $throwable") + } + override fun setUserId(userId: String) { reporter.setUserIdWithUserId(userId) } diff --git a/sample/ios-app/Podfile.lock b/sample/ios-app/Podfile.lock index 6e454d0..33f309a 100644 --- a/sample/ios-app/Podfile.lock +++ b/sample/ios-app/Podfile.lock @@ -78,4 +78,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9c08445bae18c42fcf489e55c88ebb7626bc02b8 -COCOAPODS: 1.10.0 +COCOAPODS: 1.9.3 diff --git a/sample/ios-app/src/TestViewController.swift b/sample/ios-app/src/TestViewController.swift index a111ec5..a1274a4 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() { 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..06a1b1e 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 @@ -39,10 +39,10 @@ class Testing { } fun logException() { - try { + //try { "test".toInt() - } catch (e: NumberFormatException) { - Napier.e(message = "test is not a number", tag = "Non fatal", throwable = e) - } + //} catch (e: NumberFormatException) { + // Napier.e(message = "test is not a number", tag = "Non fatal", throwable = e) + // } } } From 0d95c02b867fec576e939d67b54dbc8bdf0ea816 Mon Sep 17 00:00:00 2001 From: Aleksey Mikhailov Date: Mon, 28 Dec 2020 13:56:21 +0700 Subject: [PATCH 2/3] #504 use freezed CrashlyticsLogger --- .../core/setupUnhandledExcaptionsHandler.kt | 28 ++------------- .../DynamicProxy/FirebaseDynamicProxy.swift | 1 + .../FirebaseStaticReporter.swift | 8 +++++ .../crashlytics/CrashlyticsLogger.kt | 26 +++++++++----- sample/ios-app/Podfile.lock | 2 +- sample/ios-app/src/GoogleService-Info.plist | 36 +++++++++++++++++++ .../src/Resources/Base.lproj/Main.storyboard | 21 +++++++---- sample/ios-app/src/TestViewController.swift | 5 +++ .../kotlin/com/icerockdev/library/Testing.kt | 12 ++++--- 9 files changed, 93 insertions(+), 46 deletions(-) create mode 100644 sample/ios-app/src/GoogleService-Info.plist 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 index 137c8e9..0aab517 100644 --- 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 @@ -4,33 +4,11 @@ package dev.icerock.moko.crashreporting.core -import kotlin.native.concurrent.AtomicReference import kotlin.native.concurrent.freeze -import kotlinx.cinterop.staticCFunction -import platform.Foundation.NSThread -import platform.darwin.* -import kotlin.native.concurrent.DetachedObjectGraph -import kotlin.native.concurrent.TransferMode -import kotlin.native.concurrent.attach -fun CrashReportingCore.setupUnhandledExceptionsHandler(logger: ExceptionLogger) { - val atomicReference = AtomicReference(logger).freeze() +fun setupUnhandledExceptionsHandler(logger: ExceptionLogger) { val hook: ReportUnhandledExceptionHook = { exc: Throwable -> - val freezeExc = exc.freeze() - dispatch_async_f( - dispatch_get_main_queue(), - DetachedObjectGraph(TransferMode.UNSAFE) { - Pair( - atomicReference, - freezeExc - ) - }.asCPointer(), - staticCFunction { pointer -> - val pair = - DetachedObjectGraph, Throwable>>(pointer).attach() - pair.first.value.logFatal(throwable = pair.second) - } - ) + logger.logFatal(throwable = exc) } setUnhandledExceptionHook(hook.freeze()) -} \ No newline at end of file +} 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 4191698..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 @@ -6,26 +6,27 @@ 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 + init { - val crashReportingCore = CrashReportingCore - crashReportingCore.setupUnhandledExceptionsHandler(this) + reporter = FirebaseDynamicProxy.reporter() + ?: throw IllegalStateException("MokoFirebaseCrashlytics.setup() should be called in swift before creating CrashlyticsLogger") + freeze() + setupUnhandledExceptionsHandler(this) } - private val reporter: FirebaseCrashlyticsReporterProtocol = FirebaseDynamicProxy.reporter() - ?: throw IllegalStateException("MokoFirebaseCrashlytics.setup() should be called in swift before creating CrashlyticsLogger") - override fun log(message: String) { reporter.logWithMessage(message) } @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, @@ -42,7 +43,14 @@ actual class CrashlyticsLogger actual constructor() : ExceptionLogger { } override fun logFatal(throwable: Throwable) { - println("TODO: log fatal $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) { diff --git a/sample/ios-app/Podfile.lock b/sample/ios-app/Podfile.lock index 33f309a..6e454d0 100644 --- a/sample/ios-app/Podfile.lock +++ b/sample/ios-app/Podfile.lock @@ -78,4 +78,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9c08445bae18c42fcf489e55c88ebb7626bc02b8 -COCOAPODS: 1.9.3 +COCOAPODS: 1.10.0 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 a1274a4..3ac3348 100755 --- a/sample/ios-app/src/TestViewController.swift +++ b/sample/ios-app/src/TestViewController.swift @@ -33,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 06a1b1e..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 @@ -39,10 +39,14 @@ class Testing { } fun logException() { - //try { + try { "test".toInt() - //} catch (e: NumberFormatException) { - // Napier.e(message = "test is not a number", tag = "Non fatal", throwable = e) - // } + } catch (e: NumberFormatException) { + Napier.e(message = "test is not a number", tag = "Non fatal", throwable = e) + } + } + + fun logFatalException() { + "test".toInt() } } From 202b598ba00cf62035a8501c05d64598479e58b7 Mon Sep 17 00:00:00 2001 From: Aleksey Mikhailov Date: Mon, 28 Dec 2020 18:14:25 +0700 Subject: [PATCH 3/3] #504 rework firebase dSYMs submit --- .../TestProj.xcodeproj/project.pbxproj | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) 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;