From 354464e26187b0fef86b1968ee0b4be9e4c9d53e Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Thu, 9 Nov 2023 22:28:43 +0100 Subject: [PATCH 01/31] intial poc --- build.gradle.kts | 3 +- buildSrc/src/main/java/Config.kt | 2 +- gradle.properties | 5 +- sentry-kotlin-multiplatform/build.gradle.kts | 209 ++++++++---------- .../sentry_kotlin_multiplatform.podspec | 11 + .../kotlin/multiplatform/Attachment.apple.kt | 53 +++++ .../multiplatform/CocoaScopeProvider.kt | 131 +++++++++++ .../kotlin/multiplatform/SentryApple.kt | 12 + .../multiplatform/SentryBridge.apple.kt | 96 ++++++++ .../kotlin/multiplatform/SentryEvent.apple.kt | 61 +++++ .../kotlin/multiplatform/TypeAliases.apple.kt | 29 +++ .../extensions/BreadcrumbExtensions.apple.kt | 29 +++ .../extensions/FoundationExtensions.kt | 38 ++++ .../extensions/MessageExtensions.apple.kt | 22 ++ .../extensions/SentryEventExtensions.apple.kt | 25 +++ .../SentryExceptionExtensions.apple.kt | 14 ++ .../extensions/SentryLevelExtensions.apple.kt | 13 ++ .../SentryOptionsExtensions.apple.kt | 97 ++++++++ .../extensions/UserExtensions.apple.kt | 23 ++ .../UserFeedbackExtensions.apple.kt | 17 ++ .../multiplatform/nsexception/NSException.kt | 78 +++++++ .../nsexception/SentryUnhandledExceptions.kt | 132 +++++++++++ .../multiplatform/nsexception/Throwable.kt | 86 +++++++ .../nsexception/UnhandledExceptionHook.kt | 36 +++ .../multiplatform/protocol/SentryId.apple.kt | 26 +++ .../kotlin/multiplatform/AppleSentryIdTest.kt | 16 ++ .../multiplatform/BaseSentryScopeTest.kt | 13 ++ .../kotlin/multiplatform/BaseSentryTest.kt | 9 + .../multiplatform/BreadcrumbConfigurator.kt | 26 +++ .../multiplatform/BreadcrumbTestConverter.kt | 32 +++ .../kotlin/multiplatform/FoundationTest.kt | 51 +++++ .../multiplatform/SentryEventConfigurator.kt | 28 +++ .../multiplatform/SentryExceptionTest.kt | 69 ++++++ .../multiplatform/SentryLevelTestConverter.kt | 13 ++ .../nsexception/CommonAddressesTests.kt | 44 ++++ .../nsexception/InitAddressesTests.kt | 56 +++++ .../nsexception/ThrowableCausesTests.kt | 56 +++++ .../nsexception/ThrowableNameTests.kt | 48 ++++ .../nsexception/ThrowableReasonTests.kt | 104 +++++++++ .../multiplatform/SentryInit.tvwatchmacos.kt | 3 + .../kotlin/multiplatform/SentryInit.ios.kt | 2 + .../extensions/SentryOptionsExtensions.ios.kt | 2 + settings.gradle.kts | 54 ++--- 43 files changed, 1719 insertions(+), 155 deletions(-) create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt create mode 100644 sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt create mode 100644 sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt rename sentry-kotlin-multiplatform/src/{commonIosMain => iosMain}/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt (80%) rename sentry-kotlin-multiplatform/src/{commonIosMain => iosMain}/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt (85%) diff --git a/build.gradle.kts b/build.gradle.kts index 9dd2ac97..1746297d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,6 +16,7 @@ plugins { kotlin(Config.kotlinSerializationPlugin).version(Config.kotlinVersion).apply(false) id(Config.QualityPlugins.kover).version(Config.QualityPlugins.koverVersion).apply(false) id(Config.QualityPlugins.binaryCompatibility).version(Config.QualityPlugins.binaryCompatibilityVersion).apply(false) + id("org.jetbrains.kotlin.android") version "1.9.20" apply false } allprojects { @@ -30,7 +31,7 @@ subprojects { val sep = File.separator configure { - this.configureForMultiplatform(this@subprojects) +// this.configureForMultiplatform(this@subprojects) } tasks.named("distZip").configure { diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index d3cdd78b..623baafb 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,6 +1,6 @@ object Config { val agpVersion = "7.4.2" - val kotlinVersion = "1.8.0" + val kotlinVersion = "1.9.20" val composeVersion = "1.3.1-rc01" val gradleMavenPublishPluginVersion = "0.18.0" diff --git a/gradle.properties b/gradle.properties index e8b7df48..5cab9166 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,13 +14,10 @@ jvm.version=1.8 versionName=0.2.1 # Increase memory for in-process compiler execution. -org.gradle.jvmargs=-Xmx3g +org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" # https://kotlinlang.org/docs/migrating-multiplatform-project-to-14.html#migrate-to-the-hierarchical-project-structure -kotlin.mpp.enableCompatibilityMetadataVariant=true kotlin.mpp.enableCInteropCommonization=true -kotlin.mpp.enableHierarchicalCommonization=true -kotlin.mpp.androidSourceSetLayoutVersion=2 # Publication pom properties POM_NAME=Sentry Kotlin Multiplatform SDK diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index 9167f82c..906802e5 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -15,7 +15,7 @@ plugins { koverReport { defaults { // adds the contents of the reports of `release` Android build variant to default reports - mergeWith("release") +// mergeWith("release") } } @@ -31,46 +31,55 @@ android { } } } +dependencies { + implementation("androidx.core:core-ktx:+") +} kotlin { explicitApi() + applyDefaultHierarchyTemplate() - android { + androidTarget { publishLibraryVariants("release") } jvm() - ios() + iosArm64() iosSimulatorArm64() - watchos() + iosX64() watchosSimulatorArm64() - tvos() + watchosArm32() + watchosArm64() + watchosX64() tvosSimulatorArm64() + tvosArm64() + tvosX64() macosX64() macosArm64() sourceSets { - val commonMain by getting { - dependencies { - implementation(Config.Libs.kotlinStd) - } + commonMain.dependencies { + implementation(Config.Libs.kotlinStd) } - val commonTest by getting { - dependencies { - implementation(Config.TestLibs.kotlinCoroutinesCore) - implementation(Config.TestLibs.kotlinCoroutinesTest) - implementation(Config.TestLibs.ktorClientCore) - implementation(Config.TestLibs.ktorClientSerialization) - implementation(Config.TestLibs.kotlinxSerializationJson) - implementation(Config.TestLibs.kotlinCommon) - implementation(Config.TestLibs.kotlinCommonAnnotation) - } + + commonTest.dependencies { + implementation(Config.TestLibs.kotlinCoroutinesCore) + implementation(Config.TestLibs.kotlinCoroutinesTest) + implementation(Config.TestLibs.ktorClientCore) + implementation(Config.TestLibs.ktorClientSerialization) + implementation(Config.TestLibs.kotlinxSerializationJson) + implementation(Config.TestLibs.kotlinCommon) + implementation(Config.TestLibs.kotlinCommonAnnotation) } - val androidMain by getting { - dependencies { - implementation(Config.Libs.sentryAndroid) - } + commonTest.languageSettings { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } + + androidMain.dependencies { + implementation(Config.Libs.sentryAndroid) } + + // androidUnitTest.dependencies doesn't exist val androidUnitTest by getting { dependencies { implementation(Config.TestLibs.roboelectric) @@ -78,27 +87,43 @@ kotlin { implementation(Config.TestLibs.mockitoCore) } } - val jvmMain by getting - val jvmTest by getting val commonJvmMain by creating { - dependsOn(commonMain) - jvmMain.dependsOn(this) - androidMain.dependsOn(this) + dependsOn(commonMain.get()) dependencies { implementation(Config.Libs.sentryJava) } } + + androidMain.get().dependsOn(commonJvmMain) + jvmMain.get().dependsOn(commonJvmMain) + val commonJvmTest by creating { - dependsOn(commonTest) - jvmTest.dependsOn(this) - androidUnitTest.dependsOn(this) + dependsOn(commonTest.get()) dependencies { implementation(Config.TestLibs.kotlinJunit) implementation(Config.TestLibs.ktorClientOkHttp) } } + androidUnitTest.dependsOn(commonJvmTest) + jvmTest.get().dependsOn(commonJvmTest) + + appleTest.languageSettings { + optIn("kotlinx.cinterop.ExperimentalForeignApi::class") + } + appleTest.dependencies { + implementation(Config.TestLibs.ktorClientDarwin) + } + + val commonTvWatchMacOsMain by creating { + dependsOn(appleMain.get()) + } + + tvosMain.get().dependsOn(commonTvWatchMacOsMain) + macosMain.get().dependsOn(commonTvWatchMacOsMain) + watchosMain.get().dependsOn(commonTvWatchMacOsMain) + cocoapods { summary = "Official Sentry SDK Kotlin Multiplatform" homepage = "https://github.com/getsentry/sentry-kotlin-multiplatform" @@ -112,102 +137,42 @@ kotlin { watchos.deploymentTarget = Config.Cocoa.watchosDeploymentTarget } - val iosMain by getting - val iosSimulatorArm64Main by getting - val iosTest by getting - val iosSimulatorArm64Test by getting - - val commonIosMain by creating { - iosMain.dependsOn(this) - iosSimulatorArm64Main.dependsOn(this) - } - val commonIosTest by creating { - iosTest.dependsOn(this) - iosSimulatorArm64Test.dependsOn(this) - } - - val tvosMain by getting - val tvosSimulatorArm64Main by getting - val tvosTest by getting - val tvosSimulatorArm64Test by getting - - val watchosMain by getting - val watchosSimulatorArm64Main by getting - val watchosTest by getting - val watchosSimulatorArm64Test by getting - - val macosX64Main by getting - val macosArm64Main by getting - val macosX64Test by getting - val macosArm64Test by getting - - val commonTvWatchMacOsMain by creating { - tvosMain.dependsOn(this) - tvosSimulatorArm64Main.dependsOn(this) - watchosMain.dependsOn(this) - watchosSimulatorArm64Main.dependsOn(this) - macosArm64Main.dependsOn(this) - macosX64Main.dependsOn(this) - } - val commonTvWatchMacOsTest by creating { - tvosTest.dependsOn(this) - tvosSimulatorArm64Test.dependsOn(this) - watchosTest.dependsOn(this) - watchosSimulatorArm64Test.dependsOn(this) - macosX64Test.dependsOn(this) - macosArm64Test.dependsOn(this) - } - - val commonAppleMain by creating { - dependsOn(commonMain) - commonIosMain.dependsOn(this) - commonTvWatchMacOsMain.dependsOn(this) - } - val commonAppleTest by creating { - dependsOn(commonTest) - commonIosTest.dependsOn(this) - commonTvWatchMacOsTest.dependsOn(this) - dependencies { - implementation(Config.TestLibs.ktorClientDarwin) + listOf( + iosArm64(), + iosX64(), + iosSimulatorArm64(), + watchosArm32(), + watchosArm64(), + watchosX64(), + watchosSimulatorArm64(), + tvosArm64(), + tvosX64(), + tvosSimulatorArm64(), + macosX64(), + macosArm64() + ).forEach { + it.compilations.getByName("main") { + cinterops.create("Sentry.NSException") { + includeDirs("$projectDir/src/nativeInterop/cinterop/SentryNSException") + } + cinterops.create("Sentry.Scope") { + includeDirs("$projectDir/src/nativeInterop/cinterop/SentryScope") + } + cinterops.create("Sentry.PrivateSentrySDKOnly") { + includeDirs("$projectDir/src/nativeInterop/cinterop/SentryPrivateSentrySDKOnly") + } } } - } - listOf( - iosArm64(), - iosX64(), - iosSimulatorArm64(), - watchosArm32(), - watchosArm64(), - watchosX64(), - watchosSimulatorArm64(), - tvosArm64(), - tvosX64(), - tvosSimulatorArm64(), - macosX64(), - macosArm64() - ).forEach { - it.compilations.getByName("main") { - cinterops.create("Sentry.NSException") { - includeDirs("$projectDir/src/nativeInterop/cinterop/SentryNSException") - } - cinterops.create("Sentry.Scope") { - includeDirs("$projectDir/src/nativeInterop/cinterop/SentryScope") - } - cinterops.create("Sentry.PrivateSentrySDKOnly") { - includeDirs("$projectDir/src/nativeInterop/cinterop/SentryPrivateSentrySDKOnly") - } + // workaround for https://youtrack.jetbrains.com/issue/KT-41709 due to having "Meta" in the class name + // if we need to use this class, we'd need to find a better way to work it out + targets.withType().all { + compilations["main"].cinterops["Sentry"].extraOpts( + "-compiler-option", + "-DSentryMechanismMeta=SentryMechanismMetaUnavailable" + ) } } - - // workaround for https://youtrack.jetbrains.com/issue/KT-41709 due to having "Meta" in the class name - // if we need to use this class, we'd need to find a better way to work it out - targets.withType().all { - compilations["main"].cinterops["Sentry"].extraOpts( - "-compiler-option", - "-DSentryMechanismMeta=SentryMechanismMetaUnavailable" - ) - } } buildkonfig { diff --git a/sentry-kotlin-multiplatform/sentry_kotlin_multiplatform.podspec b/sentry-kotlin-multiplatform/sentry_kotlin_multiplatform.podspec index f4458eaa..cb68c988 100644 --- a/sentry-kotlin-multiplatform/sentry_kotlin_multiplatform.podspec +++ b/sentry-kotlin-multiplatform/sentry_kotlin_multiplatform.podspec @@ -14,6 +14,17 @@ Pod::Spec.new do |spec| spec.watchos.deployment_target = '4.0' spec.dependency 'Sentry', '8.4.0' + if !Dir.exist?('build/cocoapods/framework/sentry_kotlin_multiplatform.framework') || Dir.empty?('build/cocoapods/framework/sentry_kotlin_multiplatform.framework') + raise " + + Kotlin framework 'sentry_kotlin_multiplatform' doesn't exist yet, so a proper Xcode project can't be generated. + 'pod install' should be executed after running ':generateDummyFramework' Gradle task: + + ./gradlew :sentry-kotlin-multiplatform:generateDummyFramework + + Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + end + spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':sentry-kotlin-multiplatform', 'PRODUCT_MODULE_NAME' => 'sentry_kotlin_multiplatform', diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt new file mode 100644 index 00000000..dea218c5 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt @@ -0,0 +1,53 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toByteArray +import io.sentry.kotlin.multiplatform.extensions.toNSData +import kotlinx.cinterop.ExperimentalForeignApi + +@OptIn(ExperimentalForeignApi::class) +public actual class Attachment { + + internal lateinit var cocoaAttachment: CocoaAttachment + + public actual val filename: String + get() = cocoaAttachment.filename + + public actual val pathname: String? + get() = cocoaAttachment.path + + public actual val bytes: ByteArray? + get() = cocoaAttachment.data?.toByteArray() + + public actual val contentType: String? + get() = cocoaAttachment.contentType + + public actual companion object { + public actual fun fromScreenshot(screenshotBytes: ByteArray): Attachment { + return Attachment(screenshotBytes, "screenshot.png", "image/png") + } + } + + public actual constructor(pathname: String) { + cocoaAttachment = CocoaAttachment(pathname) + } + + public actual constructor(pathname: String, filename: String) { + cocoaAttachment = CocoaAttachment(pathname, filename) + } + + public actual constructor(pathname: String, filename: String, contentType: String?) { + contentType?.let { cocoaAttachment = CocoaAttachment(pathname, filename, it) } ?: run { + cocoaAttachment = CocoaAttachment(pathname, filename) + } + } + + public actual constructor(bytes: ByteArray, filename: String) { + cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename) + } + + public actual constructor(bytes: ByteArray, filename: String, contentType: String?) { + contentType?.let { cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename, it) } ?: run { + cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename) + } + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt new file mode 100644 index 00000000..6eecfa37 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt @@ -0,0 +1,131 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb +import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel +import io.sentry.kotlin.multiplatform.extensions.toCocoaUser +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel +import io.sentry.kotlin.multiplatform.extensions.toKmpUser +import io.sentry.kotlin.multiplatform.extensions.toMutableMap +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import io.sentry.kotlin.multiplatform.protocol.User +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import Scope.Sentry.SentryScope as PrivateCocoaScope + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal class CocoaScopeProvider(private val scope: CocoaScope) : Scope { + + /* + This bridge exposes private Cocoa SDK API to fetch internal properties such as user, level, etc. + We need this in order to return properties because the Cocoa SDK doesn't implement getters. + This is only used for get methods. + */ + private val privateScope = scope as? PrivateCocoaScope + + override var level: SentryLevel? + set(value) { + value?.let { scope.setLevel(it.toCocoaSentryLevel()) } + } + get() { + return privateScope?.levelEnum?.toKmpSentryLevel() + } + + override var user: User? + set(value) { + scope.setUser(value?.toCocoaUser()) + } + get() { + val privateUser = privateScope?.userObject as? CocoaUser + return privateUser?.let { it.toKmpUser() } + } + + override fun addAttachment(attachment: Attachment) { + scope.addAttachment(attachment.cocoaAttachment) + } + + override fun clearAttachments() { + scope.clearAttachments() + } + + override fun getContexts(): MutableMap { + val map = privateScope?.contextDictionary?.toMutableMap() + map?.let { return it } + return HashMap() + } + + override fun getTags(): MutableMap { + val map = privateScope?.tagDictionary?.toMutableMap() + map?.let { return it } + return HashMap() + } + + override fun addBreadcrumb(breadcrumb: Breadcrumb) { + scope.addBreadcrumb(breadcrumb.toCocoaBreadcrumb()) + } + + override fun clearBreadcrumbs() { + scope.clearBreadcrumbs() + } + + private fun setContextForPrimitiveValues(key: String, value: Any) { + scope.setContextValue(mapOf("value" to value), key) + } + + override fun setContext(key: String, value: Any) { + try { + (value as? Map)?.let { + scope.setContextValue(it, key) + } + } catch (e: Throwable) { + setContextForPrimitiveValues(key, value) + } + } + + override fun setContext(key: String, value: String) { + setContextForPrimitiveValues(key, value) + } + + override fun setContext(key: String, value: Boolean) { + setContextForPrimitiveValues(key, value) + } + + override fun setContext(key: String, value: Number) { + setContextForPrimitiveValues(key, value) + } + + override fun setContext(key: String, value: Char) { + setContextForPrimitiveValues(key, value) + } + + override fun setContext(key: String, value: Array<*>) { + setContextForPrimitiveValues(key, value) + } + + override fun setContext(key: String, value: Collection<*>) { + setContextForPrimitiveValues(key, value) + } + + override fun removeContext(key: String) { + scope.removeContextForKey(key) + } + + override fun setTag(key: String, value: String) { + scope.setTagValue(value, key) + } + + override fun removeTag(key: String) { + scope.removeTagForKey(key) + } + + override fun setExtra(key: String, value: String) { + scope.setExtraValue(value, key) + } + + override fun removeExtra(key: String) { + scope.removeExtraForKey(key) + } + + override fun clear() { + scope.clear() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt new file mode 100644 index 00000000..de81a7b1 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt @@ -0,0 +1,12 @@ +package io.sentry.kotlin.multiplatform + +import cocoapods.Sentry.SentrySDK +import io.sentry.kotlin.multiplatform.nsexception.setSentryUnhandledExceptionHook +import kotlinx.cinterop.ExperimentalForeignApi + +/** Convenience extension to setup unhandled exception hook */ +@OptIn(ExperimentalForeignApi::class) +internal fun SentrySDK.Companion.start(configuration: (CocoaSentryOptions?) -> Unit) { + this.startWithConfigureOptions(configuration) + setSentryUnhandledExceptionHook() +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt new file mode 100644 index 00000000..cad99df5 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt @@ -0,0 +1,96 @@ +package io.sentry.kotlin.multiplatform + +import cocoapods.Sentry.SentrySDK +import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb +import io.sentry.kotlin.multiplatform.extensions.toCocoaUser +import io.sentry.kotlin.multiplatform.extensions.toCocoaUserFeedback +import io.sentry.kotlin.multiplatform.nsexception.asNSException +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import io.sentry.kotlin.multiplatform.protocol.SentryId +import io.sentry.kotlin.multiplatform.protocol.User +import io.sentry.kotlin.multiplatform.protocol.UserFeedback +import kotlinx.cinterop.ExperimentalForeignApi +import platform.Foundation.NSError +import platform.Foundation.NSException + +public actual abstract class Context + +internal expect fun initSentry(configuration: OptionsConfiguration) + +@OptIn(ExperimentalForeignApi::class) +internal actual object SentryBridge { + + actual fun init(context: Context, configuration: OptionsConfiguration) { + initSentry(configuration) + } + + actual fun init(configuration: OptionsConfiguration) { + initSentry(configuration) + } + + actual fun captureMessage(message: String): SentryId { + val cocoaSentryId = SentrySDK.captureMessage(message) + return SentryId(cocoaSentryId.toString()) + } + + actual fun captureMessage(message: String, scopeCallback: ScopeCallback): SentryId { + val cocoaSentryId = SentrySDK.captureMessage(message, configureScopeCallback(scopeCallback)) + return SentryId(cocoaSentryId.toString()) + } + + actual fun captureException(throwable: Throwable): SentryId { + val cocoaSentryId = SentrySDK.captureException(throwable.asNSException(true)) + return SentryId(cocoaSentryId.toString()) + } + + actual fun captureException(throwable: Throwable, scopeCallback: ScopeCallback): SentryId { + val cocoaSentryId = SentrySDK.captureException( + throwable.asNSException(true), + configureScopeCallback(scopeCallback) + ) + return SentryId(cocoaSentryId.toString()) + } + + actual fun captureUserFeedback(userFeedback: UserFeedback) { + SentrySDK.captureUserFeedback(userFeedback.toCocoaUserFeedback()) + } + + actual fun configureScope(scopeCallback: ScopeCallback) { + SentrySDK.configureScope(configureScopeCallback(scopeCallback)) + } + + actual fun addBreadcrumb(breadcrumb: Breadcrumb) { + SentrySDK.addBreadcrumb(breadcrumb.toCocoaBreadcrumb()) + } + + actual fun setUser(user: User?) { + SentrySDK.setUser(user?.toCocoaUser()) + } + + actual fun close() { + SentrySDK.close() + } + + private fun configureScopeCallback(scopeCallback: ScopeCallback): (CocoaScope?) -> Unit { + return { cocoaScope -> + val cocoaScopeProvider = cocoaScope?.let { + CocoaScopeProvider(it) + } + cocoaScopeProvider?.let { + scopeCallback.invoke(it) + } + } + } +} + +@OptIn(ExperimentalForeignApi::class) +@Suppress("unused") +public fun Sentry.captureError(error: NSError) { + SentrySDK.captureError(error) +} + +@OptIn(ExperimentalForeignApi::class) +@Suppress("unused") +public fun Sentry.captureException(exception: NSException) { + SentrySDK.captureException(exception) +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt new file mode 100644 index 00000000..d57019ca --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt @@ -0,0 +1,61 @@ +@file:OptIn(UnsafeNumber::class, ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb +import io.sentry.kotlin.multiplatform.extensions.toKmpMessage +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryException +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel +import io.sentry.kotlin.multiplatform.extensions.toKmpUser +import io.sentry.kotlin.multiplatform.protocol.Message +import io.sentry.kotlin.multiplatform.protocol.SentryException +import io.sentry.kotlin.multiplatform.protocol.SentryId +import io.sentry.kotlin.multiplatform.protocol.User +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber + +public actual class SentryEvent actual constructor() : SentryBaseEvent() { + public actual var level: SentryLevel? = null + public actual var message: Message? = null + public actual var logger: String? = null + public actual var fingerprint: MutableList = mutableListOf() + public actual var exceptions: MutableList = mutableListOf() + public override var release: String? = null + public override var environment: String? = null + public override var platform: String? = null + public override var user: User? = null + public override var serverName: String? = null + public override var dist: String? = null + + public constructor(cocoaSentryEvent: CocoaSentryEvent) : this() { + eventId = SentryId(cocoaSentryEvent.eventId.toString()) + level = cocoaSentryEvent.level?.toKmpSentryLevel() + message = cocoaSentryEvent.message?.toKmpMessage() + logger = cocoaSentryEvent.logger + release = cocoaSentryEvent.releaseName + environment = cocoaSentryEvent.environment + platform = cocoaSentryEvent.platform + user = cocoaSentryEvent.user?.toKmpUser() + serverName = cocoaSentryEvent.serverName + dist = cocoaSentryEvent.dist + + val cocoaFingerprint = + cocoaSentryEvent.fingerprint()?.toMutableList() as? MutableList + val cocoaSentryExceptions = + cocoaSentryEvent.exceptions?.map { (it as CocoaSentryException).toKmpSentryException() } + ?.toMutableList() + val cocoaContexts = + cocoaSentryEvent.context?.mapKeys { it.key as String }?.mapValues { it.value as Any } + val cocoaBreadcrumbs = cocoaSentryEvent.breadcrumbs?.mapNotNull { it as? CocoaBreadcrumb } + ?.map { it.toKmpBreadcrumb() }?.toMutableList() + val cocoaTags = + cocoaSentryEvent.tags?.mapKeys { it.key as String }?.mapValues { it.value as String } + ?.toMutableMap() + + cocoaFingerprint?.let { fingerprint = it } + cocoaSentryExceptions?.let { exceptions = it } + cocoaContexts?.let { contexts = it } + cocoaBreadcrumbs?.let { breadcrumbs = it } + cocoaTags?.let { tags = it } + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt new file mode 100644 index 00000000..c193edd1 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt @@ -0,0 +1,29 @@ +@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform + +import cocoapods.Sentry.SentryAttachment +import cocoapods.Sentry.SentryBreadcrumb +import cocoapods.Sentry.SentryEvent +import cocoapods.Sentry.SentryException +import cocoapods.Sentry.SentryId +import cocoapods.Sentry.SentryLevel +import cocoapods.Sentry.SentryMessage +import cocoapods.Sentry.SentryOptions +import cocoapods.Sentry.SentryScope +import cocoapods.Sentry.SentryUser +import cocoapods.Sentry.SentryUserFeedback +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber + +internal typealias CocoaUser = SentryUser +internal typealias CocoaBreadcrumb = SentryBreadcrumb +internal typealias CocoaSentryOptions = SentryOptions +internal typealias CocoaScope = SentryScope +internal typealias CocoaSentryId = SentryId +internal typealias CocoaSentryLevel = SentryLevel +internal typealias CocoaAttachment = SentryAttachment +internal typealias CocoaUserFeedback = SentryUserFeedback +internal typealias CocoaSentryEvent = SentryEvent +internal typealias CocoaMessage = SentryMessage +internal typealias CocoaSentryException = SentryException diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt new file mode 100644 index 00000000..b7be6eac --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt @@ -0,0 +1,29 @@ +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.CocoaBreadcrumb +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun Breadcrumb.toCocoaBreadcrumb() = CocoaBreadcrumb().apply { + val scope = this@toCocoaBreadcrumb + setMessage(scope.message) + setType(scope.type) + scope.category?.let { setCategory(it) } + scope.level?.let { setLevel(it.toCocoaSentryLevel()) } + setData(scope.getData()?.toMap()) +} + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun CocoaBreadcrumb.toKmpBreadcrumb() = Breadcrumb().apply { + val scope = this@toKmpBreadcrumb + message = scope.message + type = scope.type + category = scope.category + val map = scope.data as? Map + map?.let { + this.setData(it.toMutableMap()) + } + level = scope.level.toKmpSentryLevel() +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt new file mode 100644 index 00000000..570fa621 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt @@ -0,0 +1,38 @@ +package io.sentry.kotlin.multiplatform.extensions + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.addressOf +import kotlinx.cinterop.allocArrayOf +import kotlinx.cinterop.convert +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.usePinned +import platform.Foundation.NSData +import platform.Foundation.NSMutableDictionary +import platform.Foundation.allKeys +import platform.Foundation.create +import platform.posix.memcpy + +internal fun NSMutableDictionary.toMutableMap(): MutableMap { + val keys = this.allKeys + val map = mutableMapOf() + for (key in keys) { + map.put(key as K, this.objectForKey(key) as V) + } + return map +} + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun NSData.toByteArray(): ByteArray = ByteArray(this@toByteArray.length.toInt()).apply { + usePinned { + memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length) + } +} + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun ByteArray.toNSData(): NSData = memScoped { + NSData.create( + bytes = allocArrayOf(this@toNSData), + length = this@toNSData.size.toULong().convert() + ) +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt new file mode 100644 index 00000000..cba2989f --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt @@ -0,0 +1,22 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.CocoaMessage +import io.sentry.kotlin.multiplatform.protocol.Message +import kotlinx.cinterop.ExperimentalForeignApi + +internal fun CocoaMessage.toKmpMessage() = Message( + message = message, + params = params as? List, + formatted = formatted +) + +internal fun Message.toCocoaMessage(): CocoaMessage { + val scope = this@toCocoaMessage + val cocoaMessage = scope.formatted?.let { CocoaMessage(it) } ?: CocoaMessage() + return cocoaMessage.apply { + message = scope.message + params = scope.params + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt new file mode 100644 index 00000000..b85cad3c --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt @@ -0,0 +1,25 @@ +package io.sentry.kotlin.multiplatform.extensions + +import cocoapods.Sentry.SentryId +import io.sentry.kotlin.multiplatform.CocoaSentryEvent +import io.sentry.kotlin.multiplatform.SentryEvent +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun CocoaSentryEvent.applyKmpEvent(kmpEvent: SentryEvent): CocoaSentryEvent { + kmpEvent.level?.let { level = it.toCocoaSentryLevel() } + kmpEvent.platform?.let { platform = it } + message = kmpEvent.message?.toCocoaMessage() + logger = kmpEvent.logger + fingerprint = kmpEvent.fingerprint + releaseName = kmpEvent.release + environment = kmpEvent.environment + user = kmpEvent.user?.toCocoaUser() + serverName = kmpEvent.serverName + dist = kmpEvent.dist + breadcrumbs = kmpEvent.breadcrumbs.map { it.toCocoaBreadcrumb() }.toMutableList() + tags = kmpEvent.tags.toMutableMap() + eventId = SentryId(kmpEvent.eventId.toString()) + return this +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt new file mode 100644 index 00000000..bbd56984 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt @@ -0,0 +1,14 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.CocoaSentryException +import io.sentry.kotlin.multiplatform.protocol.SentryException +import kotlinx.cinterop.ExperimentalForeignApi + +internal fun CocoaSentryException.toKmpSentryException() = SentryException( + type = type, + value = value, + module = module, + threadId = threadId?.longLongValue // longLong represents a 64-bit integer like Kotlin Long +) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt new file mode 100644 index 00000000..513ac21b --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt @@ -0,0 +1,13 @@ +@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.SentryLevel +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.convert +import cocoapods.Sentry.SentryLevel as CocoaSentryLevel + +internal fun SentryLevel.toCocoaSentryLevel() = this.toInt().convert() + +internal fun CocoaSentryLevel.toKmpSentryLevel() = SentryLevel.fromInt(this.toInt()) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt new file mode 100644 index 00000000..a1352516 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt @@ -0,0 +1,97 @@ +package io.sentry.kotlin.multiplatform.extensions + +import PrivateSentrySDKOnly.Sentry.PrivateSentrySDKOnly +import cocoapods.Sentry.SentryHttpStatusCodeRange +import io.sentry.kotlin.multiplatform.BuildKonfig +import io.sentry.kotlin.multiplatform.CocoaSentryEvent +import io.sentry.kotlin.multiplatform.CocoaSentryOptions +import io.sentry.kotlin.multiplatform.SentryEvent +import io.sentry.kotlin.multiplatform.SentryOptions +import io.sentry.kotlin.multiplatform.nsexception.dropKotlinCrashEvent +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.convert +import platform.Foundation.NSNumber +import NSException.Sentry.SentryEvent as NSExceptionSentryEvent + +@OptIn(ExperimentalForeignApi::class) +internal fun SentryOptions.toCocoaOptionsConfiguration(): (CocoaSentryOptions?) -> Unit = { + it?.applyCocoaBaseOptions(this) +} + +/** + * Applies the given options to this CocoaSentryOptions. + * This avoids code duplication for init on iOS. + */ +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +internal fun CocoaSentryOptions.applyCocoaBaseOptions(options: SentryOptions) { + dsn = options.dsn + attachStacktrace = options.attachStackTrace + dist = options.dist + options.environment?.let { + environment = it + } + releaseName = options.release + debug = options.debug + sessionTrackingIntervalMillis = options.sessionTrackingIntervalMillis.convert() + enableAutoSessionTracking = options.enableAutoSessionTracking + maxAttachmentSize = options.maxAttachmentSize.convert() + maxBreadcrumbs = options.maxBreadcrumbs.convert() + options.sampleRate?.let { + sampleRate = NSNumber(double = it) + } + options.tracesSampleRate?.let { + tracesSampleRate = NSNumber(double = it) + } + beforeSend = { event -> + val cocoaName = BuildKonfig.SENTRY_COCOA_PACKAGE_NAME + val cocoaVersion = BuildKonfig.SENTRY_COCOA_VERSION + + val sdk = event?.sdk?.toMutableMap() + + val packages = options.sdk?.packages?.map { + mapOf("name" to it.name, "version" to it.version) + }?.toMutableList() ?: mutableListOf() + + val names = packages.map { it["name"] } + if (!names.contains(cocoaName)) { + packages.add(mapOf("name" to cocoaName, "version" to cocoaVersion)) + } + + sdk?.set("packages", packages) + + event?.sdk = sdk + + if (options.beforeSend == null) { + dropKotlinCrashEvent(event as NSExceptionSentryEvent?) as CocoaSentryEvent? + } else { + val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent -> + val result = options.beforeSend?.invoke(unwrappedEvent) + result?.let { event.applyKmpEvent(it) } + } + dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent? + } + } + + val sdkName = options.sdk?.name ?: BuildKonfig.SENTRY_KMP_COCOA_SDK_NAME + val sdkVersion = options.sdk?.version ?: BuildKonfig.VERSION_NAME + PrivateSentrySDKOnly.setSdkName(sdkName, sdkVersion) + + beforeBreadcrumb = { cocoaBreadcrumb -> + if (options.beforeBreadcrumb == null) { + cocoaBreadcrumb + } else { + cocoaBreadcrumb?.toKmpBreadcrumb() + ?.let { options.beforeBreadcrumb?.invoke(it) }?.toCocoaBreadcrumb() + } + } + + enableCaptureFailedRequests = options.enableCaptureFailedRequests + failedRequestTargets = options.failedRequestTargets + failedRequestStatusCodes = options.failedRequestStatusCodes.map { + SentryHttpStatusCodeRange( + min = it.min.convert(), + max = it.max.convert() + ) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt new file mode 100644 index 00000000..29a66990 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt @@ -0,0 +1,23 @@ +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.CocoaUser +import io.sentry.kotlin.multiplatform.protocol.User +import kotlinx.cinterop.ExperimentalForeignApi + +@OptIn(ExperimentalForeignApi::class) +internal fun User.toCocoaUser() = CocoaUser().apply { + val scope = this@toCocoaUser + userId = scope.id + username = scope.username + email = scope.email + ipAddress = scope.ipAddress +} + +@OptIn(ExperimentalForeignApi::class) +internal fun CocoaUser.toKmpUser() = User().apply { + val scope = this@toKmpUser + id = scope.userId + username = scope.username + email = scope.email + ipAddress = scope.ipAddress +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt new file mode 100644 index 00000000..c187a3f3 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt @@ -0,0 +1,17 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform.extensions + +import io.sentry.kotlin.multiplatform.CocoaSentryId +import io.sentry.kotlin.multiplatform.CocoaUserFeedback +import io.sentry.kotlin.multiplatform.protocol.UserFeedback +import kotlinx.cinterop.ExperimentalForeignApi + +internal fun UserFeedback.toCocoaUserFeedback(): CocoaUserFeedback { + val sentryId = CocoaSentryId(sentryId.toString()) + return CocoaUserFeedback(sentryId).apply { + comments = this@toCocoaUserFeedback.comments.toString() + email = this@toCocoaUserFeedback.email.toString() + name = this@toCocoaUserFeedback.name.toString() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt new file mode 100644 index 00000000..629667ed --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt @@ -0,0 +1,78 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/NSException.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.convert +import platform.Foundation.NSException +import platform.Foundation.NSNumber +import platform.darwin.NSUInteger +import kotlin.reflect.KClass + +/** + * Returns a [NSException] representing `this` [Throwable]. + * If [appendCausedBy] is `true` then the name, message and stack trace + * of the [causes][Throwable.cause] will be appended, else causes are ignored. + */ +internal fun Throwable.asNSException(appendCausedBy: Boolean = false): NSException { + val returnAddresses = getFilteredStackTraceAddresses().let { addresses -> + if (!appendCausedBy) return@let addresses + addresses.toMutableList().apply { + for (cause in causes) { + addAll(cause.getFilteredStackTraceAddresses(true, addresses)) + } + } + }.map { + @Suppress("RemoveExplicitTypeArguments") + NSNumber(unsignedInteger = it.convert()) + } + return ThrowableNSException(name, getReason(appendCausedBy), returnAddresses) +} + +/** + * Returns the [qualifiedName][KClass.qualifiedName] or [simpleName][KClass.simpleName] of `this` throwable. + * If both are `null` then "Throwable" is returned. + */ +internal val Throwable.name: String + get() = this::class.qualifiedName ?: this::class.simpleName ?: "Throwable" + +/** + * Returns the [message][Throwable.message] of this throwable. + * If [appendCausedBy] is `true` then caused by lines with the format + * "Caused by: $[name]: $[message][Throwable.message]" will be appended. + */ +internal fun Throwable.getReason(appendCausedBy: Boolean = false): String? { + if (!appendCausedBy) return message + return buildString { + message?.let(::append) + for (cause in causes) { + if (isNotEmpty()) appendLine() + append("Caused by: ") + append(cause.name) + cause.message?.let { append(": $it") } + } + }.takeIf { it.isNotEmpty() } +} + +internal class ThrowableNSException( + name: String, + reason: String?, + private val returnAddresses: List +) : NSException(name, reason, null) { + override fun callStackReturnAddresses(): List = returnAddresses +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt new file mode 100644 index 00000000..96268ea2 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt @@ -0,0 +1,132 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-sentry/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/sentry/Sentry.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import NSException.Sentry.NSExceptionKt_SentryCrashStackCursorCleanup +import NSException.Sentry.NSExceptionKt_SentryCrashStackCursorFromNSException +import NSException.Sentry.NSExceptionKt_SentryMechanismSetNotHandled +import NSException.Sentry.NSExceptionKt_SentryThreadSetCrashed +import NSException.Sentry.SentryDependencyContainer +import NSException.Sentry.SentryEnvelope +import NSException.Sentry.SentryEnvelopeHeader +import NSException.Sentry.SentryEnvelopeItem +import NSException.Sentry.SentryEvent +import NSException.Sentry.SentryException +import NSException.Sentry.SentryMechanism +import NSException.Sentry.SentrySDK +import NSException.Sentry.SentryThread +import NSException.Sentry.SentryThreadInspector +import NSException.Sentry.currentHub +import NSException.Sentry.isCrashEvent +import NSException.Sentry.kSentryLevelFatal +import NSException.Sentry.prepareEvent +import NSException.Sentry.storeEnvelope +import NSException.Sentry.threadInspector +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import platform.Foundation.NSException +import platform.Foundation.NSNumber + +/** + * Drops the Kotlin crash that follows an unhandled Kotlin exception except our custom SentryEvent. + */ +@OptIn(ExperimentalForeignApi::class) +internal fun dropKotlinCrashEvent(event: SentryEvent?): SentryEvent? { + return event?.takeUnless { it.isCrashEvent && (it.tags?.containsKey(KOTLIN_CRASH_TAG) ?: false) } +} + +/** + * Sets the unhandled exception hook such that all unhandled exceptions are logged to Sentry as fatal exceptions. + * If an unhandled exception hook was already set, that hook will be invoked after the exception is logged. + * Note: once the exception is logged the program will be terminated. + * @see wrapUnhandledExceptionHook + */ +@OptIn(ExperimentalForeignApi::class) +internal fun setSentryUnhandledExceptionHook(): Unit = wrapUnhandledExceptionHook { throwable -> + val envelope = throwable.asSentryEnvelope() + // The envelope will be persisted, so we can safely terminate afterwards. + // https://github.com/getsentry/sentry-cocoa/blob/678172142ac1d10f5ed7978f69d16ab03e801057/Sources/Sentry/SentryClient.m#L409 + SentrySDK.storeEnvelope(envelope) + SentrySDK.configureScope { scope -> + scope?.setTagValue(KOTLIN_CRASH_TAG, KOTLIN_CRASH_TAG) + } +} + +/** + * Tag used to mark the Kotlin termination crash. + */ +internal const val KOTLIN_CRASH_TAG = "nsexceptionkt.kotlin_crashed" + +/** + * Converts `this` [Throwable] to a [SentryEnvelope]. + */ +@OptIn(ExperimentalForeignApi::class) +internal fun Throwable.asSentryEnvelope(): SentryEnvelope { + val event = asSentryEvent() + val preparedEvent = SentrySDK.currentHub().let { hub -> + hub.getClient()?.prepareEvent(event, hub.scope, alwaysAttachStacktrace = false, isCrashEvent = true) + } ?: event + val item = SentryEnvelopeItem(preparedEvent) + // TODO: pass traceState when enabling performance monitoring for KMP SDK + val header = SentryEnvelopeHeader(preparedEvent.eventId, null) + return SentryEnvelope(header, listOf(item)) +} + +/** + * Converts `this` [Throwable] to a [SentryEvent]. + */ +@Suppress("UnnecessaryOptInAnnotation") +@OptIn(UnsafeNumber::class, ExperimentalForeignApi::class) +private fun Throwable.asSentryEvent(): SentryEvent = SentryEvent(kSentryLevelFatal).apply { + isCrashEvent = true + @Suppress("UNCHECKED_CAST") + val threads = threadInspector?.getCurrentThreadsWithStackTrace() as List? + this.threads = threads + val currentThread = threads?.firstOrNull { it.current?.boolValue ?: false }?.apply { + NSExceptionKt_SentryThreadSetCrashed(this) + // Crashed threats shouldn't have a stacktrace, the thread_id should be set on the exception instead + // https://develop.sentry.dev/sdk/event-payloads/threads/ + stacktrace = null + } + debugMeta = threads?.let { + SentryDependencyContainer.sharedInstance().debugImageProvider.getDebugImagesForThreads(it) + } + exceptions = this@asSentryEvent + .let { throwable -> throwable.causes.asReversed() + throwable } + .map { it.asNSException().asSentryException(currentThread?.threadId) } +} + +/** + * Converts `this` [NSException] to a [SentryException]. + */ +@OptIn(ExperimentalForeignApi::class) +private fun NSException.asSentryException( + threadId: NSNumber? +): SentryException = SentryException(reason ?: "", name ?: "Throwable").apply { + this.threadId = threadId + mechanism = SentryMechanism("generic").apply { + NSExceptionKt_SentryMechanismSetNotHandled(this) + } + stacktrace = threadInspector?.stacktraceBuilder?.let { stacktraceBuilder -> + val cursor = NSExceptionKt_SentryCrashStackCursorFromNSException(this@asSentryException) + val stacktrace = stacktraceBuilder.retrieveStacktraceFromCursor(cursor) + NSExceptionKt_SentryCrashStackCursorCleanup(cursor) + stacktrace + } +} + +@OptIn(ExperimentalForeignApi::class) +private val threadInspector: SentryThreadInspector? + get() = SentrySDK.currentHub().getClient()?.threadInspector diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt new file mode 100644 index 00000000..f708743a --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt @@ -0,0 +1,86 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/Throwable.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.experimental.ExperimentalNativeApi + +/** + * Returns a list with all the [causes][Throwable.cause]. + * The first element will be the cause, the second the cause of the cause, etc. + * This function stops once a reference cycles is detected. + */ +internal val Throwable.causes: List get() = buildList { + val causes = mutableSetOf() + var cause = cause + while (cause != null && causes.add(cause)) { + add(cause) + cause = cause.cause + } +} + +/** + * Returns a list of stack trace addresses representing + * the stack trace of the constructor call to `this` [Throwable]. + * @param keepLastInit `true` to preserve the last constructor call, `false` to drop all constructor calls. + * @param commonAddresses a list of addresses used to drop the last common addresses. + * @see getStackTraceAddresses + */ +@OptIn(ExperimentalNativeApi::class) +internal fun Throwable.getFilteredStackTraceAddresses( + keepLastInit: Boolean = false, + commonAddresses: List = emptyList() +): List = getStackTraceAddresses().dropInitAddresses( + qualifiedClassName = this::class.qualifiedName ?: Throwable::class.qualifiedName!!, + stackTrace = getStackTrace(), + keepLast = keepLastInit +).dropCommonAddresses(commonAddresses) + +/** + * Returns a list containing all addresses expect for the first addresses + * matching the constructor call of the [qualifiedClassName]. + * If [keepLast] is `true` the last constructor call won't be dropped. + */ +internal fun List.dropInitAddresses( + qualifiedClassName: String, + stackTrace: Array, + keepLast: Boolean = false +): List { + val exceptionInit = "kfun:$qualifiedClassName#" + var dropCount = 0 + var foundInit = false + for (i in stackTrace.indices) { + if (stackTrace[i].contains(exceptionInit)) { + foundInit = true + } else if (foundInit) { + dropCount = i + break + } + } + if (keepLast) dropCount-- + return drop(kotlin.math.max(0, dropCount)) +} + +/** + * Returns a list containing all addresses expect for the last addresses that match with the [commonAddresses]. + */ +internal fun List.dropCommonAddresses( + commonAddresses: List +): List { + var i = commonAddresses.size + if (i == 0) return this + return dropLastWhile { + i-- >= 0 && commonAddresses[i] == it + } +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt new file mode 100644 index 00000000..ee10fd28 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt @@ -0,0 +1,36 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/UnhandledExceptionHook.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.experimental.ExperimentalNativeApi +import kotlin.native.concurrent.freeze + +/** + * Wraps the unhandled exception hook such that the provided [hook] is invoked + * before the currently set unhandled exception hook is invoked. + * Note: once the unhandled exception hook returns the program will be terminated. + * @see setUnhandledExceptionHook + * @see terminateWithUnhandledException + */ +@OptIn(ExperimentalNativeApi::class) +internal fun wrapUnhandledExceptionHook(hook: (Throwable) -> Unit) { + val prevHook = kotlin.concurrent.AtomicReference(null) + val wrappedHook: ReportUnhandledExceptionHook = { + hook(it) + prevHook.value?.invoke(it) + terminateWithUnhandledException(it) + } + prevHook.value = setUnhandledExceptionHook(wrappedHook.freeze()) +} diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt new file mode 100644 index 00000000..473c28cc --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt @@ -0,0 +1,26 @@ +package io.sentry.kotlin.multiplatform.protocol + +import io.sentry.kotlin.multiplatform.CocoaSentryId +import kotlinx.cinterop.ExperimentalForeignApi + +@OptIn(ExperimentalForeignApi::class) +public actual data class SentryId actual constructor(val sentryIdString: String) { + + public actual companion object { + public actual val EMPTY_ID: SentryId = SentryId("") + } + + private var cocoaSentryId: CocoaSentryId? = null + + init { + cocoaSentryId = if (sentryIdString.isEmpty()) { + CocoaSentryId.empty() + } else { + CocoaSentryId(sentryIdString) + } + } + + actual override fun toString(): String { + return cocoaSentryId.toString() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt new file mode 100644 index 00000000..9601553b --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt @@ -0,0 +1,16 @@ +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.protocol.SentryId +import kotlin.test.Test +import kotlin.test.assertEquals + +class AppleSentryIdTest { + + @Test + fun `Cocoa SentryId with invalid uuid string returns only zeroes`() { + val uuidString = "ec720-b6f6-4efc--5c1" + val expected = SentryId.EMPTY_ID.toString() + val actual = SentryId(uuidString).toString() + assertEquals(expected, actual) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt new file mode 100644 index 00000000..c493809a --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt @@ -0,0 +1,13 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform + +import kotlinx.cinterop.ExperimentalForeignApi +import cocoapods.Sentry.SentryScope as CocoaScope + +actual abstract class BaseSentryScopeTest { + actual fun initializeScope(): Scope { + val cocoaScope = CocoaScope() + return CocoaScopeProvider(cocoaScope) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt new file mode 100644 index 00000000..1ea225ae --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt @@ -0,0 +1,9 @@ +package io.sentry.kotlin.multiplatform + +actual abstract class BaseSentryTest { + actual val platform: String = "Apple" + actual val authToken: String? = "fake-auth-token" + actual fun sentryInit(optionsConfiguration: OptionsConfiguration) { + Sentry.init(optionsConfiguration) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt new file mode 100644 index 00000000..b93d0437 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt @@ -0,0 +1,26 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions +import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import kotlinx.cinterop.ExperimentalForeignApi + +actual class BreadcrumbConfigurator { + private val cocoaBreadcrumb = CocoaBreadcrumb() + actual val originalBreadcrumb: Breadcrumb = cocoaBreadcrumb.toKmpBreadcrumb() + + actual fun applyOptions(optionsConfiguration: OptionsConfiguration): Breadcrumb? { + val kmpOptions = SentryOptions() + optionsConfiguration.invoke(kmpOptions) + return applyOptions(kmpOptions) + } + + actual fun applyOptions(options: SentryOptions): Breadcrumb? { + val cocoaOptions = CocoaSentryOptions() + cocoaOptions.applyCocoaBaseOptions(options) + val cocoaModifiedBreadcrumb = cocoaOptions.beforeBreadcrumb?.invoke(cocoaBreadcrumb) + return cocoaModifiedBreadcrumb?.toKmpBreadcrumb() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt new file mode 100644 index 00000000..dea1b7df --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt @@ -0,0 +1,32 @@ +@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel +import io.sentry.kotlin.multiplatform.protocol.Breadcrumb +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber + +actual data class BreadcrumbTestConverter actual constructor(val breadcrumb: Breadcrumb) { + + actual fun getType(): String? { + return breadcrumb.toCocoaBreadcrumb().type + } + + actual fun getCategory(): String? { + return breadcrumb.toCocoaBreadcrumb().category + } + + actual fun getMessage(): String? { + return breadcrumb.toCocoaBreadcrumb().message + } + + actual fun getData(): MutableMap { + return breadcrumb.toCocoaBreadcrumb().data as MutableMap + } + + actual fun getLevel(): SentryLevel? { + return breadcrumb.toCocoaBreadcrumb().level.toKmpSentryLevel() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt new file mode 100644 index 00000000..5f210f6a --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt @@ -0,0 +1,51 @@ +@file:OptIn(UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toByteArray +import io.sentry.kotlin.multiplatform.extensions.toNSData +import kotlinx.cinterop.UnsafeNumber +import platform.Foundation.NSNumber +import platform.Foundation.NSString +import platform.Foundation.NSUTF8StringEncoding +import platform.Foundation.dataUsingEncoding +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals + +class FoundationTest { + @Test + fun `convert string to NSData and ByteArray is correct`() { + val text = "$!()I!(DKDASKDKSD(#(ldkiadjk91jd" + val nsString = "$!()I!(DKDASKDKSD(#(ldkiadjk91jd" as NSString + + val nsData = nsString.dataUsingEncoding(NSUTF8StringEncoding)!! + val byteArray = text.encodeToByteArray() + + assertContentEquals(byteArray, nsData.toByteArray()) + assertContentEquals(byteArray, byteArray.toNSData().toByteArray()) + assertEquals(nsData, byteArray.toNSData()) + assertEquals(nsData, nsData.toByteArray().toNSData()) + } + + @Test + fun `NSNumber longLong converts to Long correctly`() { + val longValue = 4937446359977427944L + val nsNumber = NSNumber(longLong = longValue) + assertEquals(longValue, nsNumber.longLongValue) + } + + @Test + fun `NSNumber int converts to Long correctly`() { + val intValue = 493744635 + val nsNumber = NSNumber(int = intValue) + assertEquals(intValue.toLong(), nsNumber.longLongValue) + } + + @Test + fun `NSNumber short converts to Long correctly`() { + val shortValue: Short = 4937 + val nsNumber = NSNumber(short = shortValue) + assertEquals(shortValue.toLong(), nsNumber.longLongValue) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt new file mode 100644 index 00000000..90be0f24 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt @@ -0,0 +1,28 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions +import kotlinx.cinterop.ExperimentalForeignApi + +actual class SentryEventConfigurator { + private val cocoaSentryEvent = CocoaSentryEvent() + actual val originalEvent: SentryEvent = SentryEvent(cocoaSentryEvent) + + actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? { + val kmpOptions = SentryOptions() + optionsConfiguration.invoke(kmpOptions) + return applyOptions(kmpOptions) + } + + actual fun applyOptions(options: SentryOptions): SentryEvent? { + val cocoaOptions = CocoaSentryOptions() + cocoaOptions.applyCocoaBaseOptions(options) + val cocoaModifiedSentryEvent = cocoaOptions.beforeSend?.invoke(cocoaSentryEvent) + return if (cocoaModifiedSentryEvent == null) { + null + } else { + SentryEvent(cocoaModifiedSentryEvent) + } + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt new file mode 100644 index 00000000..0601c8a4 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt @@ -0,0 +1,69 @@ +@file:OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class, UnsafeNumber::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryException +import io.sentry.kotlin.multiplatform.protocol.SentryException +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.convert +import platform.Foundation.NSNumber +import kotlin.experimental.ExperimentalNativeApi +import kotlin.test.Test + +class SentryExceptionTest { + private val value = "testValue" + private val type = "type" + private val threadId = 1 + + private fun getCocoaSentryException(): CocoaSentryException { + return CocoaSentryException(value = value, type = type) + } + + private fun getKmpSentryException(threadId: Long? = this.threadId.toLong()): SentryException { + return SentryException(value = value, type = type, threadId = threadId) + } + + @Test + fun `SentryException ThreadId NSNumber long conversion`() { + val cocoaSentryException = getCocoaSentryException().apply { + threadId = NSNumber(long = this@SentryExceptionTest.threadId.convert()) + } + val sentryException = getKmpSentryException() + assert(cocoaSentryException.toKmpSentryException() == sentryException) + } + + @Test + fun `SentryException ThreadId NSNumber longLong conversion`() { + val cocoaSentryException = getCocoaSentryException().apply { + threadId = NSNumber(longLong = this@SentryExceptionTest.threadId.convert()) + } + val sentryException = getKmpSentryException() + assert(cocoaSentryException.toKmpSentryException() == sentryException) + } + + @Test + fun `SentryException ThreadId NSNumber int conversion`() { + val cocoaSentryException = getCocoaSentryException().apply { + threadId = NSNumber(int = this@SentryExceptionTest.threadId.convert()) + } + val sentryException = getKmpSentryException() + assert(cocoaSentryException.toKmpSentryException() == sentryException) + } + + @Test + fun `SentryException ThreadId NSNumber short conversion`() { + val cocoaSentryException = getCocoaSentryException().apply { + threadId = NSNumber(short = this@SentryExceptionTest.threadId.convert()) + } + val sentryException = getKmpSentryException() + assert(cocoaSentryException.toKmpSentryException() == sentryException) + } + + @Test + fun `SentryException ThreadId NSNumber null conversion`() { + val cocoaSentryException = getCocoaSentryException() + val sentryException = getKmpSentryException(threadId = null) + assert(cocoaSentryException.toKmpSentryException() == sentryException) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt new file mode 100644 index 00000000..acb8c65e --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt @@ -0,0 +1,13 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package io.sentry.kotlin.multiplatform + +import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel +import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel +import kotlinx.cinterop.ExperimentalForeignApi + +actual class SentryLevelTestConverter actual constructor() { + actual fun convert(sentryLevel: SentryLevel?): SentryLevel? { + return sentryLevel?.toCocoaSentryLevel()?.toKmpSentryLevel() + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt new file mode 100644 index 00000000..c157eb30 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt @@ -0,0 +1,44 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/CommonAddressesTests.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame + +class CommonAddressesTests { + + @Test + fun testDropCommon() { + val commonAddresses = listOf(5, 4, 3, 2, 1, 0) + val addresses = listOf(8, 7, 6, 2, 1, 0) + val withoutCommonAddresses = addresses.dropCommonAddresses(commonAddresses) + assertEquals(listOf(8, 7, 6), withoutCommonAddresses) + } + + @Test + fun testDropCommonEmptyCommon() { + val addresses = listOf(0, 1, 2) + val withoutCommonAddresses = addresses.dropCommonAddresses(emptyList()) + assertSame(addresses, withoutCommonAddresses) + } + + @Test + fun testDropCommonSameAddresses() { + val addresses = listOf(0, 1, 2) + val withoutCommonAddresses = addresses.dropCommonAddresses(addresses) + assertEquals(emptyList(), withoutCommonAddresses) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt new file mode 100644 index 00000000..a5a81db2 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt @@ -0,0 +1,56 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/InitAddressesTests.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.test.Test +import kotlin.test.assertEquals + +class InitAddressesTests { + + private val qualifiedClassName = "my.app.CustomException" + private val addresses = listOf(0, 1, 2, 3, 4, 5) + private val stackTrace = arrayOf( + "123 kfun:kotlin.Throwable#(kotlin.String?){} + 24 abc", + "456 kfun:kotlin.Exception#(kotlin.String?){} + 5 def", + "789 kfun:my.app.CustomException#(kotlin.String?){} + 10 hij", + "012 kfun:my.app.CustomException#(){} + 12 klm", + "345 kfun:my.app.class#function1(){} + 50 nop", + "678 kfun:my.app.class#function2(){} + 60 qrs" + ) + + @Test + fun testDropInit() { + val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, false) + assertEquals(listOf(4, 5), withoutInitAddresses) + } + + @Test + fun testDropInitKeepLast() { + val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, true) + assertEquals(listOf(3, 4, 5), withoutInitAddresses) + } + + private fun testDropInitUnknownClassName(keepLast: Boolean) { + val qualifiedClassName = "my.app.SomeOtherException" + val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, keepLast) + assertEquals(addresses, withoutInitAddresses) + } + + @Test + fun testDropInitUnknownClassNameDropLast() = testDropInitUnknownClassName(false) + + @Test + fun testDropInitUnknownClassNameKeepLast() = testDropInitUnknownClassName(true) +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt new file mode 100644 index 00000000..e46f5426 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt @@ -0,0 +1,56 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableCausesTests.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +@file:OptIn(ExperimentalNativeApi::class) + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.experimental.ExperimentalNativeApi +import kotlin.test.Test +import kotlin.test.assertEquals + +class ThrowableCausesTests { + + @Test + fun testNoCauses() { + assert(Throwable().causes.isEmpty()) + } + + @Test + fun testSingleCause() { + val cause = Throwable("Cause throwable") + val throwable = Throwable("Test throwable", cause) + assertEquals(listOf(cause), throwable.causes) + } + + @Test + fun testMultipleCauses() { + val cause1 = Throwable("Cause 1 throwable") + val cause2 = Throwable("Cause 2 throwable", cause1) + val throwable = Throwable("Test throwable", cause2) + assertEquals(listOf(cause2, cause1), throwable.causes) + } + + private class MyThrowable(override val message: String?) : Throwable() { + override var cause: Throwable? = null + } + + @Test + fun testReferenceCycle() { + val cause = MyThrowable("Cause throwable") + val throwable = Throwable("Test throwable", cause) + cause.cause = throwable + assertEquals(listOf(cause, throwable), throwable.causes) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt new file mode 100644 index 00000000..2caeda5c --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt @@ -0,0 +1,48 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableNameTests.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.test.Test +import kotlin.test.assertEquals + +class ThrowableNameTests { + + private class MyThrowable : Throwable() + + @Test + fun testMyThrowableName() { + val exception = MyThrowable() + assertEquals("io.sentry.kotlin.multiplatform.nsexception.ThrowableNameTests.MyThrowable", exception.name) + } + + @Test + fun testIllegalArgumentExceptionName() { + val exception = IllegalArgumentException() + assertEquals("kotlin.IllegalArgumentException", exception.name) + } + + @Test + fun testLocalThrowableName() { + class MyLocalThrowable : Throwable() + val throwable = MyLocalThrowable() + assertEquals("MyLocalThrowable", throwable.name) + } + + @Test + fun testAnonymousThrowableName() { + val throwable = object : Throwable() { } + assertEquals("Throwable", throwable.name) + } +} diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt new file mode 100644 index 00000000..d7cb9f90 --- /dev/null +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt @@ -0,0 +1,104 @@ +// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableReasonTests.kt +// +// Copyright (c) 2022 Rick Clephas +// +// 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 be included in all +// copies or substantial portions of the Software. + +package io.sentry.kotlin.multiplatform.nsexception + +import kotlin.test.Test +import kotlin.test.assertEquals + +class ThrowableReasonTests { + + private fun testReasonNoCause(message: String?, appendCausedBy: Boolean) { + val exception = Exception(message) + val reason = exception.getReason(appendCausedBy) + assertEquals(message, reason) + } + + @Test + fun testReasonNoCauseDontAppend() = testReasonNoCause("Test message", false) + + @Test + fun testReasonNoCauseAppend() = testReasonNoCause("Test message", true) + + @Test + fun testReasonNoMessageNoCauseDontAppend() = testReasonNoCause(null, false) + + @Test + fun testReasonNoMessageNoCauseAppend() = testReasonNoCause(null, true) + + @Test + fun testReasonWithCauseDontAppend() { + val cause = Exception("Cause message") + val message = "Test message" + val exception = Exception(message, cause) + val reason = exception.getReason(false) + assertEquals(message, reason) + } + + @Test + fun testReasonWithCause() { + val cause = Exception("Cause message") + val exception = Exception("Test message", cause) + val reason = exception.getReason(true) + assertEquals( + """ + Test message + Caused by: kotlin.Exception: Cause message + """.trimIndent(), + reason + ) + } + + @Test + fun testReasonNoMessageWithCause() { + val cause = Exception("Cause message") + val exception = Exception(null, cause) + val reason = exception.getReason(true) + assertEquals( + """ + Caused by: kotlin.Exception: Cause message + """.trimIndent(), + reason + ) + } + + @Test + fun testReasonNoCauseMessage() { + val exception = Exception("Test message", Exception()) + val reason = exception.getReason(true) + assertEquals( + """ + Test message + Caused by: kotlin.Exception + """.trimIndent(), + reason + ) + } + + @Test + fun testReasonWithDoubleCause() { + val cause1 = Exception("Cause1 message") + val cause2 = Exception("Cause2 message", cause1) + val exception = Exception("Test message", cause2) + val reason = exception.getReason(true) + assertEquals( + """ + Test message + Caused by: kotlin.Exception: Cause2 message + Caused by: kotlin.Exception: Cause1 message + """.trimIndent(), + reason + ) + } +} diff --git a/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt b/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt index 2cd5ff69..8b5d32f4 100644 --- a/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt +++ b/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt @@ -1,7 +1,10 @@ +@file:OptIn(ExperimentalForeignApi::class) + package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentrySDK import io.sentry.kotlin.multiplatform.extensions.toCocoaOptionsConfiguration +import kotlinx.cinterop.ExperimentalForeignApi internal actual fun initSentry(configuration: OptionsConfiguration) { val options = SentryOptions() diff --git a/sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt similarity index 80% rename from sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt rename to sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt index e00d1b02..f88965c1 100644 --- a/sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt +++ b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt @@ -2,7 +2,9 @@ package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentrySDK import io.sentry.kotlin.multiplatform.extensions.toIosOptionsConfiguration +import kotlinx.cinterop.ExperimentalForeignApi +@OptIn(ExperimentalForeignApi::class) internal actual fun initSentry(configuration: OptionsConfiguration) { val options = SentryOptions() configuration.invoke(options) diff --git a/sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt similarity index 85% rename from sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt rename to sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt index bb7638d1..0ee67077 100644 --- a/sentry-kotlin-multiplatform/src/commonIosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt +++ b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt @@ -2,7 +2,9 @@ package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaSentryOptions import io.sentry.kotlin.multiplatform.SentryOptions +import kotlinx.cinterop.ExperimentalForeignApi +@OptIn(ExperimentalForeignApi::class) internal fun SentryOptions.toIosOptionsConfiguration(): (CocoaSentryOptions?) -> Unit = { // Apply base options available to all Cocoa/Apple targets it?.applyCocoaBaseOptions(this) diff --git a/settings.gradle.kts b/settings.gradle.kts index 68022c8e..694b007b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,30 +21,30 @@ rootProject.name = "sentry-kotlin-multiplatform-sdk" include(":sentry-kotlin-multiplatform") -/* -Simple KMP App with targets: - - Android - - iOS with SwiftUI and SPM - - JVM Desktop with Jetpack Compose - */ -include("sentry-samples:kmp-app-spm:shared") -include("sentry-samples:kmp-app-spm:androidApp") -include("sentry-samples:kmp-app-spm:desktopApp") - -/* -Simple KMP App with targets: - - Android - - iOS with SwiftUI and Cocoapods - - JVM Desktop with Jetpack Compose - */ -include("sentry-samples:kmp-app-cocoapods:shared") -include("sentry-samples:kmp-app-cocoapods:androidApp") -include("sentry-samples:kmp-app-cocoapods:desktopApp") - -/* -KMP App with MVVM and Dependency Injection with Koin: - - Android with Jetpack Compose - - iOS with SwiftUI and SPM - */ -include("sentry-samples:kmp-app-mvvm-di:shared") -include("sentry-samples:kmp-app-mvvm-di:androidApp") +// /* +// Simple KMP App with targets: +// - Android +// - iOS with SwiftUI and SPM +// - JVM Desktop with Jetpack Compose +// */ +// include("sentry-samples:kmp-app-spm:shared") +// include("sentry-samples:kmp-app-spm:androidApp") +// include("sentry-samples:kmp-app-spm:desktopApp") +// +// /* +// Simple KMP App with targets: +// - Android +// - iOS with SwiftUI and Cocoapods +// - JVM Desktop with Jetpack Compose +// */ +// include("sentry-samples:kmp-app-cocoapods:shared") +// include("sentry-samples:kmp-app-cocoapods:androidApp") +// include("sentry-samples:kmp-app-cocoapods:desktopApp") +// +// /* +// KMP App with MVVM and Dependency Injection with Koin: +// - Android with Jetpack Compose +// - iOS with SwiftUI and SPM +// */ +// include("sentry-samples:kmp-app-mvvm-di:shared") +// include("sentry-samples:kmp-app-mvvm-di:androidApp") From a5e2dec79e0e80b369b7a87b0b8347887678aa51 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 00:28:53 +0100 Subject: [PATCH 02/31] update api --- .../api/android/sentry-kotlin-multiplatform.api | 1 + .../api/jvm/sentry-kotlin-multiplatform.api | 1 + 2 files changed, 2 insertions(+) diff --git a/sentry-kotlin-multiplatform/api/android/sentry-kotlin-multiplatform.api b/sentry-kotlin-multiplatform/api/android/sentry-kotlin-multiplatform.api index 074d7115..89233344 100644 --- a/sentry-kotlin-multiplatform/api/android/sentry-kotlin-multiplatform.api +++ b/sentry-kotlin-multiplatform/api/android/sentry-kotlin-multiplatform.api @@ -150,6 +150,7 @@ public final class io/sentry/kotlin/multiplatform/SentryLevel : java/lang/Enum { public static final field FATAL Lio/sentry/kotlin/multiplatform/SentryLevel; public static final field INFO Lio/sentry/kotlin/multiplatform/SentryLevel; public static final field WARNING Lio/sentry/kotlin/multiplatform/SentryLevel; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lio/sentry/kotlin/multiplatform/SentryLevel; public static fun values ()[Lio/sentry/kotlin/multiplatform/SentryLevel; } diff --git a/sentry-kotlin-multiplatform/api/jvm/sentry-kotlin-multiplatform.api b/sentry-kotlin-multiplatform/api/jvm/sentry-kotlin-multiplatform.api index c79819de..e1f8a5cc 100644 --- a/sentry-kotlin-multiplatform/api/jvm/sentry-kotlin-multiplatform.api +++ b/sentry-kotlin-multiplatform/api/jvm/sentry-kotlin-multiplatform.api @@ -147,6 +147,7 @@ public final class io/sentry/kotlin/multiplatform/SentryLevel : java/lang/Enum { public static final field FATAL Lio/sentry/kotlin/multiplatform/SentryLevel; public static final field INFO Lio/sentry/kotlin/multiplatform/SentryLevel; public static final field WARNING Lio/sentry/kotlin/multiplatform/SentryLevel; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lio/sentry/kotlin/multiplatform/SentryLevel; public static fun values ()[Lio/sentry/kotlin/multiplatform/SentryLevel; } From 82dcd8c7d0f4d7c0f3494b3c31ba6601d51ca44d Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 00:59:28 +0100 Subject: [PATCH 03/31] Fix distZip --- build.gradle.kts | 8 ++++++-- buildSrc/src/main/java/Publication.kt | 6 ------ sentry-kotlin-multiplatform/build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1746297d..93d3f0d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,6 @@ plugins { kotlin(Config.kotlinSerializationPlugin).version(Config.kotlinVersion).apply(false) id(Config.QualityPlugins.kover).version(Config.QualityPlugins.koverVersion).apply(false) id(Config.QualityPlugins.binaryCompatibility).version(Config.QualityPlugins.binaryCompatibilityVersion).apply(false) - id("org.jetbrains.kotlin.android") version "1.9.20" apply false } allprojects { @@ -31,7 +30,7 @@ subprojects { val sep = File.separator configure { -// this.configureForMultiplatform(this@subprojects) + this.configureForMultiplatform(this@subprojects) } tasks.named("distZip").configure { @@ -46,6 +45,11 @@ subprojects { } afterEvaluate { + val platformDists = project.tasks.filter { task -> + task.name.matches(Regex("(.*)DistZip")) + }.toTypedArray() + project.tasks.getByName("distZip").finalizedBy(*platformDists) + apply() configure { diff --git a/buildSrc/src/main/java/Publication.kt b/buildSrc/src/main/java/Publication.kt index 9167e432..2c94b3eb 100644 --- a/buildSrc/src/main/java/Publication.kt +++ b/buildSrc/src/main/java/Publication.kt @@ -173,12 +173,6 @@ fun DistributionContainer.configureForMultiplatform(project: Project) { } fromKlib(project.name, "tvosSimulatorArm64", version) } - - // make other distZip tasks run together with the main distZip - val platformDists = project.tasks.filter { task -> - task.name.matches(Consts.taskRegex) - }.toTypedArray() - project.tasks.getByName("distZip").finalizedBy(*platformDists) } private fun CopySpec.fromKlib(projectName: String, target: String, version: String) { diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index 906802e5..42bb5e1b 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -15,7 +15,7 @@ plugins { koverReport { defaults { // adds the contents of the reports of `release` Android build variant to default reports -// mergeWith("release") + mergeWith("release") } } From 6e155f823c1c21fd61ece01d8b533e32bc040077 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 01:02:02 +0100 Subject: [PATCH 04/31] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24925f31..649a2d88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ### Dependencies +- Bump Kotlin version from v1.8.0 to v1.9.20 ([#146](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/146)) + - v1.9.20 is the first stable version of KMP - Bump Java SDK from v6.14.0 to v6.32.0 ([#131](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/131)) - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#6320) - [diff](https://github.com/getsentry/sentry-java/compare/6.14.0...6.32.0) From beef4f7bc2de3622c25f51a18e18dfa900277622 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 13:15:14 +0100 Subject: [PATCH 05/31] update --- buildSrc/src/main/java/Config.kt | 2 +- sentry-kotlin-multiplatform/build.gradle.kts | 3 --- sentry-samples/kmp-app-cocoapods/iosApp/Podfile.lock | 2 +- .../kmp-app-cocoapods/shared/shared.podspec | 11 +++++++++++ settings.gradle.kts | 12 ++++++------ 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index e9c57e19..1309912e 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,7 +1,7 @@ object Config { val agpVersion = "7.4.2" val kotlinVersion = "1.9.20" - val composeVersion = "1.3.1-rc01" + val composeVersion = "1.5.10" val gradleMavenPublishPluginVersion = "0.18.0" val multiplatform = "multiplatform" diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index 42bb5e1b..6ae3bb4d 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -31,9 +31,6 @@ android { } } } -dependencies { - implementation("androidx.core:core-ktx:+") -} kotlin { explicitApi() diff --git a/sentry-samples/kmp-app-cocoapods/iosApp/Podfile.lock b/sentry-samples/kmp-app-cocoapods/iosApp/Podfile.lock index c32432f8..ac971868 100644 --- a/sentry-samples/kmp-app-cocoapods/iosApp/Podfile.lock +++ b/sentry-samples/kmp-app-cocoapods/iosApp/Podfile.lock @@ -27,4 +27,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: f282da88f39e69507b0a255187c8a6b644477756 -COCOAPODS: 1.12.0 +COCOAPODS: 1.13.0 diff --git a/sentry-samples/kmp-app-cocoapods/shared/shared.podspec b/sentry-samples/kmp-app-cocoapods/shared/shared.podspec index 1fa7c843..98ad2c06 100644 --- a/sentry-samples/kmp-app-cocoapods/shared/shared.podspec +++ b/sentry-samples/kmp-app-cocoapods/shared/shared.podspec @@ -11,6 +11,17 @@ Pod::Spec.new do |spec| spec.ios.deployment_target = '14.1' spec.dependency 'Sentry', '~> 8.4.0' + if !Dir.exist?('build/cocoapods/framework/shared.framework') || Dir.empty?('build/cocoapods/framework/shared.framework') + raise " + + Kotlin framework 'shared' doesn't exist yet, so a proper Xcode project can't be generated. + 'pod install' should be executed after running ':generateDummyFramework' Gradle task: + + ./gradlew :sentry-samples:kmp-app-cocoapods:shared:generateDummyFramework + + Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" + end + spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':sentry-samples:kmp-app-cocoapods:shared', 'PRODUCT_MODULE_NAME' => 'shared', diff --git a/settings.gradle.kts b/settings.gradle.kts index 694b007b..e44bc7e2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,9 +27,9 @@ include(":sentry-kotlin-multiplatform") // - iOS with SwiftUI and SPM // - JVM Desktop with Jetpack Compose // */ -// include("sentry-samples:kmp-app-spm:shared") -// include("sentry-samples:kmp-app-spm:androidApp") -// include("sentry-samples:kmp-app-spm:desktopApp") +include("sentry-samples:kmp-app-spm:shared") + include("sentry-samples:kmp-app-spm:androidApp") + include("sentry-samples:kmp-app-spm:desktopApp") // // /* // Simple KMP App with targets: @@ -37,9 +37,9 @@ include(":sentry-kotlin-multiplatform") // - iOS with SwiftUI and Cocoapods // - JVM Desktop with Jetpack Compose // */ -// include("sentry-samples:kmp-app-cocoapods:shared") -// include("sentry-samples:kmp-app-cocoapods:androidApp") -// include("sentry-samples:kmp-app-cocoapods:desktopApp") + include("sentry-samples:kmp-app-cocoapods:shared") + include("sentry-samples:kmp-app-cocoapods:androidApp") + include("sentry-samples:kmp-app-cocoapods:desktopApp") // // /* // KMP App with MVVM and Dependency Injection with Koin: From 788521acdd35c379a96fbadb90c9004bb63cc167 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 14:51:13 +0100 Subject: [PATCH 06/31] remove optin --- sentry-kotlin-multiplatform/build.gradle.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index 6ae3bb4d..ee9a8b16 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -68,10 +68,6 @@ kotlin { implementation(Config.TestLibs.kotlinCommonAnnotation) } - commonTest.languageSettings { - optIn("kotlinx.cinterop.ExperimentalForeignApi") - } - androidMain.dependencies { implementation(Config.Libs.sentryAndroid) } From 79cba02be02d712caf8dc02d2157c36650127c3a Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 15:11:03 +0100 Subject: [PATCH 07/31] include samples --- settings.gradle.kts | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index e44bc7e2..5001a80e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,30 +21,30 @@ rootProject.name = "sentry-kotlin-multiplatform-sdk" include(":sentry-kotlin-multiplatform") -// /* -// Simple KMP App with targets: -// - Android -// - iOS with SwiftUI and SPM -// - JVM Desktop with Jetpack Compose -// */ +/* +Simple KMP App with targets: + - Android + - iOS with SwiftUI and SPM + - JVM Desktop with Jetpack Compose +*/ include("sentry-samples:kmp-app-spm:shared") - include("sentry-samples:kmp-app-spm:androidApp") - include("sentry-samples:kmp-app-spm:desktopApp") -// -// /* -// Simple KMP App with targets: -// - Android -// - iOS with SwiftUI and Cocoapods -// - JVM Desktop with Jetpack Compose -// */ - include("sentry-samples:kmp-app-cocoapods:shared") - include("sentry-samples:kmp-app-cocoapods:androidApp") - include("sentry-samples:kmp-app-cocoapods:desktopApp") -// -// /* -// KMP App with MVVM and Dependency Injection with Koin: -// - Android with Jetpack Compose -// - iOS with SwiftUI and SPM -// */ -// include("sentry-samples:kmp-app-mvvm-di:shared") -// include("sentry-samples:kmp-app-mvvm-di:androidApp") +include("sentry-samples:kmp-app-spm:androidApp") +include("sentry-samples:kmp-app-spm:desktopApp") + +/* +Simple KMP App with targets: + - Android + - iOS with SwiftUI and Cocoapods + - JVM Desktop with Jetpack Compose +*/ +include("sentry-samples:kmp-app-cocoapods:shared") +include("sentry-samples:kmp-app-cocoapods:androidApp") +include("sentry-samples:kmp-app-cocoapods:desktopApp") + +/* +KMP App with MVVM and Dependency Injection with Koin: + - Android with Jetpack Compose + - iOS with SwiftUI and SPM +*/ +include("sentry-samples:kmp-app-mvvm-di:shared") +include("sentry-samples:kmp-app-mvvm-di:androidApp") From 2dc9fe613cc596584b3784b6645e91703ca2b465 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 10 Nov 2023 22:42:51 +0100 Subject: [PATCH 08/31] fix --- buildSrc/src/main/java/Config.kt | 8 ++++---- sentry-kotlin-multiplatform/build.gradle.kts | 3 --- .../extensions/SentryAndroidOptionsExtensions.kt | 5 ++++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 1309912e..62d509f2 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -48,10 +48,10 @@ object Config { val kotlinCoroutinesTest = "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.0-RC" val kotlinxSerializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0" - val ktorClientCore = "io.ktor:ktor-client-core:2.3.0" - val ktorClientSerialization = "io.ktor:ktor-client-serialization:2.3.0" - val ktorClientOkHttp = "io.ktor:ktor-client-okhttp:2.3.0" - val ktorClientDarwin = "io.ktor:ktor-client-darwin:2.3.0" + val ktorClientCore = "io.ktor:ktor-client-core:2.3.6" + val ktorClientSerialization = "io.ktor:ktor-client-serialization:2.3.6" + val ktorClientOkHttp = "io.ktor:ktor-client-okhttp:2.3.6" + val ktorClientDarwin = "io.ktor:ktor-client-darwin:2.3.6" val roboelectric = "org.robolectric:robolectric:4.9" val junitKtx = "androidx.test.ext:junit-ktx:1.1.5" diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index ee9a8b16..ef93744e 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -102,9 +102,6 @@ kotlin { androidUnitTest.dependsOn(commonJvmTest) jvmTest.get().dependsOn(commonJvmTest) - appleTest.languageSettings { - optIn("kotlinx.cinterop.ExperimentalForeignApi::class") - } appleTest.dependencies { implementation(Config.TestLibs.ktorClientDarwin) } diff --git a/sentry-kotlin-multiplatform/src/androidMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryAndroidOptionsExtensions.kt b/sentry-kotlin-multiplatform/src/androidMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryAndroidOptionsExtensions.kt index cca0dd82..3837a666 100644 --- a/sentry-kotlin-multiplatform/src/androidMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryAndroidOptionsExtensions.kt +++ b/sentry-kotlin-multiplatform/src/androidMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryAndroidOptionsExtensions.kt @@ -3,6 +3,7 @@ package io.sentry.kotlin.multiplatform.extensions import io.sentry.android.core.SentryAndroidOptions import io.sentry.kotlin.multiplatform.BuildKonfig import io.sentry.kotlin.multiplatform.SentryOptions +import kotlin.collections.forEach as kForEach internal fun SentryOptions.toAndroidSentryOptionsCallback(): (SentryAndroidOptions) -> Unit = { // Apply base options available to all JVM targets @@ -15,7 +16,9 @@ internal fun SentryOptions.toAndroidSentryOptionsCallback(): (SentryAndroidOptio it.sdkVersion?.name = this.sdk?.name ?: BuildKonfig.SENTRY_KMP_ANDROID_SDK_NAME it.sdkVersion?.version = this.sdk?.version ?: BuildKonfig.VERSION_NAME - this.sdk?.packages?.forEach { sdkPackage -> + // kForEach solves an issue with linter where it thinks forEach is the Java version + // see here: https://stackoverflow.com/questions/44751469/kotlin-extension-functions-suddenly-require-api-level-24/68897591#68897591 + this.sdk?.packages?.kForEach { sdkPackage -> it.sdkVersion?.addPackage(sdkPackage.name, sdkPackage.version) } From 15b3bd08b64705d375e955fed540a26a43a52c1a Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 13 Nov 2023 23:50:56 +0100 Subject: [PATCH 09/31] Migrate samples to 1.9.20 --- .run/iosApp-cocoapods.run.xml | 2 +- .../kotlin/multiplatform/Attachment.apple.kt | 51 ---- .../multiplatform/CocoaScopeProvider.kt | 128 --------- .../kotlin/multiplatform/SentryApple.kt | 10 - .../multiplatform/SentryBridge.apple.kt | 92 ------- .../kotlin/multiplatform/SentryEvent.apple.kt | 57 ---- .../kotlin/multiplatform/TypeAliases.apple.kt | 25 -- .../extensions/BreadcrumbExtensions.apple.kt | 25 -- .../extensions/FoundationExtensions.kt | 34 --- .../extensions/MessageExtensions.apple.kt | 19 -- .../extensions/SentryEventExtensions.apple.kt | 22 -- .../SentryExceptionExtensions.apple.kt | 11 - .../extensions/SentryLevelExtensions.apple.kt | 9 - .../SentryOptionsExtensions.apple.kt | 93 ------- .../extensions/UserExtensions.apple.kt | 20 -- .../UserFeedbackExtensions.apple.kt | 14 - .../multiplatform/nsexception/NSException.kt | 74 ----- .../nsexception/SentryUnhandledExceptions.kt | 126 --------- .../multiplatform/nsexception/Throwable.kt | 83 ------ .../nsexception/UnhandledExceptionHook.kt | 36 --- .../multiplatform/protocol/SentryId.apple.kt | 24 -- .../kotlin/multiplatform/AppleSentryIdTest.kt | 16 -- .../multiplatform/BaseSentryScopeTest.kt | 10 - .../kotlin/multiplatform/BaseSentryTest.kt | 9 - .../multiplatform/BreadcrumbConfigurator.kt | 23 -- .../multiplatform/BreadcrumbTestConverter.kt | 28 -- .../kotlin/multiplatform/FoundationTest.kt | 48 ---- .../multiplatform/SentryEventConfigurator.kt | 25 -- .../multiplatform/SentryExceptionTest.kt | 64 ----- .../multiplatform/SentryLevelTestConverter.kt | 10 - .../nsexception/CommonAddressesTests.kt | 44 --- .../nsexception/InitAddressesTests.kt | 56 ---- .../nsexception/ThrowableCausesTests.kt | 53 ---- .../nsexception/ThrowableNameTests.kt | 48 ---- .../nsexception/ThrowableReasonTests.kt | 104 ------- .../kotlin/multiplatform/SentryE2ETest.kt | 258 +++++++++--------- .../androidApp/build.gradle.kts | 2 +- .../kmp-app-cocoapods/shared/build.gradle.kts | 38 +-- .../androidApp/build.gradle.kts | 6 +- .../kmp-app-mvvm-di/shared/build.gradle.kts | 46 +--- .../kmp-app-spm/androidApp/build.gradle.kts | 2 +- .../kmp-app-spm/shared/build.gradle.kts | 37 +-- 42 files changed, 164 insertions(+), 1718 deletions(-) delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt delete mode 100644 sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt diff --git a/.run/iosApp-cocoapods.run.xml b/.run/iosApp-cocoapods.run.xml index 8ce66786..a8eab207 100644 --- a/.run/iosApp-cocoapods.run.xml +++ b/.run/iosApp-cocoapods.run.xml @@ -1,5 +1,5 @@ - + diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt deleted file mode 100644 index d69637cc..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toByteArray -import io.sentry.kotlin.multiplatform.extensions.toNSData - -public actual class Attachment { - - internal lateinit var cocoaAttachment: CocoaAttachment - - public actual val filename: String - get() = cocoaAttachment.filename - - public actual val pathname: String? - get() = cocoaAttachment.path - - public actual val bytes: ByteArray? - get() = cocoaAttachment.data?.toByteArray() - - public actual val contentType: String? - get() = cocoaAttachment.contentType - - public actual companion object { - public actual fun fromScreenshot(screenshotBytes: ByteArray): Attachment { - return Attachment(screenshotBytes, "screenshot.png", "image/png") - } - } - - public actual constructor(pathname: String) { - cocoaAttachment = CocoaAttachment(pathname) - } - - public actual constructor(pathname: String, filename: String) { - cocoaAttachment = CocoaAttachment(pathname, filename) - } - - public actual constructor(pathname: String, filename: String, contentType: String?) { - contentType?.let { cocoaAttachment = CocoaAttachment(pathname, filename, it) } ?: run { - cocoaAttachment = CocoaAttachment(pathname, filename) - } - } - - public actual constructor(bytes: ByteArray, filename: String) { - cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename) - } - - public actual constructor(bytes: ByteArray, filename: String, contentType: String?) { - contentType?.let { cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename, it) } ?: run { - cocoaAttachment = CocoaAttachment(bytes.toNSData(), filename) - } - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt deleted file mode 100644 index f7906086..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt +++ /dev/null @@ -1,128 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb -import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel -import io.sentry.kotlin.multiplatform.extensions.toCocoaUser -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel -import io.sentry.kotlin.multiplatform.extensions.toKmpUser -import io.sentry.kotlin.multiplatform.extensions.toMutableMap -import io.sentry.kotlin.multiplatform.protocol.Breadcrumb -import io.sentry.kotlin.multiplatform.protocol.User -import Scope.Sentry.SentryScope as PrivateCocoaScope - -internal class CocoaScopeProvider(private val scope: CocoaScope) : Scope { - - /* - This bridge exposes private Cocoa SDK API to fetch internal properties such as user, level, etc. - We need this in order to return properties because the Cocoa SDK doesn't implement getters. - This is only used for get methods. - */ - private val privateScope = scope as? PrivateCocoaScope - - override var level: SentryLevel? - set(value) { - value?.let { scope.setLevel(it.toCocoaSentryLevel()) } - } - get() { - return privateScope?.levelEnum?.toKmpSentryLevel() - } - - override var user: User? - set(value) { - scope.setUser(value?.toCocoaUser()) - } - get() { - val privateUser = privateScope?.userObject as? CocoaUser - return privateUser?.let { it.toKmpUser() } - } - - override fun addAttachment(attachment: Attachment) { - scope.addAttachment(attachment.cocoaAttachment) - } - - override fun clearAttachments() { - scope.clearAttachments() - } - - override fun getContexts(): MutableMap { - val map = privateScope?.contextDictionary?.toMutableMap() - map?.let { return it } - return HashMap() - } - - override fun getTags(): MutableMap { - val map = privateScope?.tagDictionary?.toMutableMap() - map?.let { return it } - return HashMap() - } - - override fun addBreadcrumb(breadcrumb: Breadcrumb) { - scope.addBreadcrumb(breadcrumb.toCocoaBreadcrumb()) - } - - override fun clearBreadcrumbs() { - scope.clearBreadcrumbs() - } - - private fun setContextForPrimitiveValues(key: String, value: Any) { - scope.setContextValue(mapOf("value" to value), key) - } - - override fun setContext(key: String, value: Any) { - try { - (value as? Map)?.let { - scope.setContextValue(it, key) - } - } catch (e: Throwable) { - setContextForPrimitiveValues(key, value) - } - } - - override fun setContext(key: String, value: String) { - setContextForPrimitiveValues(key, value) - } - - override fun setContext(key: String, value: Boolean) { - setContextForPrimitiveValues(key, value) - } - - override fun setContext(key: String, value: Number) { - setContextForPrimitiveValues(key, value) - } - - override fun setContext(key: String, value: Char) { - setContextForPrimitiveValues(key, value) - } - - override fun setContext(key: String, value: Array<*>) { - setContextForPrimitiveValues(key, value) - } - - override fun setContext(key: String, value: Collection<*>) { - setContextForPrimitiveValues(key, value) - } - - override fun removeContext(key: String) { - scope.removeContextForKey(key) - } - - override fun setTag(key: String, value: String) { - scope.setTagValue(value, key) - } - - override fun removeTag(key: String) { - scope.removeTagForKey(key) - } - - override fun setExtra(key: String, value: String) { - scope.setExtraValue(value, key) - } - - override fun removeExtra(key: String) { - scope.removeExtraForKey(key) - } - - override fun clear() { - scope.clear() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt deleted file mode 100644 index 2f897b86..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import cocoapods.Sentry.SentrySDK -import io.sentry.kotlin.multiplatform.nsexception.setSentryUnhandledExceptionHook - -/** Convenience extension to setup unhandled exception hook */ -internal fun SentrySDK.Companion.start(configuration: (CocoaSentryOptions?) -> Unit) { - this.startWithConfigureOptions(configuration) - setSentryUnhandledExceptionHook() -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt deleted file mode 100644 index 3a7cd87d..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt +++ /dev/null @@ -1,92 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import cocoapods.Sentry.SentrySDK -import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb -import io.sentry.kotlin.multiplatform.extensions.toCocoaUser -import io.sentry.kotlin.multiplatform.extensions.toCocoaUserFeedback -import io.sentry.kotlin.multiplatform.nsexception.asNSException -import io.sentry.kotlin.multiplatform.protocol.Breadcrumb -import io.sentry.kotlin.multiplatform.protocol.SentryId -import io.sentry.kotlin.multiplatform.protocol.User -import io.sentry.kotlin.multiplatform.protocol.UserFeedback -import platform.Foundation.NSError -import platform.Foundation.NSException - -public actual abstract class Context - -internal expect fun initSentry(configuration: OptionsConfiguration) - -internal actual object SentryBridge { - - actual fun init(context: Context, configuration: OptionsConfiguration) { - initSentry(configuration) - } - - actual fun init(configuration: OptionsConfiguration) { - initSentry(configuration) - } - - actual fun captureMessage(message: String): SentryId { - val cocoaSentryId = SentrySDK.captureMessage(message) - return SentryId(cocoaSentryId.toString()) - } - - actual fun captureMessage(message: String, scopeCallback: ScopeCallback): SentryId { - val cocoaSentryId = SentrySDK.captureMessage(message, configureScopeCallback(scopeCallback)) - return SentryId(cocoaSentryId.toString()) - } - - actual fun captureException(throwable: Throwable): SentryId { - val cocoaSentryId = SentrySDK.captureException(throwable.asNSException(true)) - return SentryId(cocoaSentryId.toString()) - } - - actual fun captureException(throwable: Throwable, scopeCallback: ScopeCallback): SentryId { - val cocoaSentryId = SentrySDK.captureException( - throwable.asNSException(true), - configureScopeCallback(scopeCallback) - ) - return SentryId(cocoaSentryId.toString()) - } - - actual fun captureUserFeedback(userFeedback: UserFeedback) { - SentrySDK.captureUserFeedback(userFeedback.toCocoaUserFeedback()) - } - - actual fun configureScope(scopeCallback: ScopeCallback) { - SentrySDK.configureScope(configureScopeCallback(scopeCallback)) - } - - actual fun addBreadcrumb(breadcrumb: Breadcrumb) { - SentrySDK.addBreadcrumb(breadcrumb.toCocoaBreadcrumb()) - } - - actual fun setUser(user: User?) { - SentrySDK.setUser(user?.toCocoaUser()) - } - - actual fun close() { - SentrySDK.close() - } - - private fun configureScopeCallback(scopeCallback: ScopeCallback): (CocoaScope?) -> Unit { - return { cocoaScope -> - val cocoaScopeProvider = cocoaScope?.let { - CocoaScopeProvider(it) - } - cocoaScopeProvider?.let { - scopeCallback.invoke(it) - } - } - } -} - -@Suppress("unused") -public fun Sentry.captureError(error: NSError) { - SentrySDK.captureError(error) -} - -@Suppress("unused") -public fun Sentry.captureException(exception: NSException) { - SentrySDK.captureException(exception) -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt deleted file mode 100644 index 45c14ff9..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb -import io.sentry.kotlin.multiplatform.extensions.toKmpMessage -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryException -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel -import io.sentry.kotlin.multiplatform.extensions.toKmpUser -import io.sentry.kotlin.multiplatform.protocol.Message -import io.sentry.kotlin.multiplatform.protocol.SentryException -import io.sentry.kotlin.multiplatform.protocol.SentryId -import io.sentry.kotlin.multiplatform.protocol.User - -public actual class SentryEvent actual constructor() : SentryBaseEvent() { - public actual var level: SentryLevel? = null - public actual var message: Message? = null - public actual var logger: String? = null - public actual var fingerprint: MutableList = mutableListOf() - public actual var exceptions: MutableList = mutableListOf() - public override var release: String? = null - public override var environment: String? = null - public override var platform: String? = null - public override var user: User? = null - public override var serverName: String? = null - public override var dist: String? = null - - public constructor(cocoaSentryEvent: CocoaSentryEvent) : this() { - eventId = SentryId(cocoaSentryEvent.eventId.toString()) - level = cocoaSentryEvent.level?.toKmpSentryLevel() - message = cocoaSentryEvent.message?.toKmpMessage() - logger = cocoaSentryEvent.logger - release = cocoaSentryEvent.releaseName - environment = cocoaSentryEvent.environment - platform = cocoaSentryEvent.platform - user = cocoaSentryEvent.user?.toKmpUser() - serverName = cocoaSentryEvent.serverName - dist = cocoaSentryEvent.dist - - val cocoaFingerprint = - cocoaSentryEvent.fingerprint()?.toMutableList() as? MutableList - val cocoaSentryExceptions = - cocoaSentryEvent.exceptions?.map { (it as CocoaSentryException).toKmpSentryException() } - ?.toMutableList() - val cocoaContexts = - cocoaSentryEvent.context?.mapKeys { it.key as String }?.mapValues { it.value as Any } - val cocoaBreadcrumbs = cocoaSentryEvent.breadcrumbs?.mapNotNull { it as? CocoaBreadcrumb } - ?.map { it.toKmpBreadcrumb() }?.toMutableList() - val cocoaTags = - cocoaSentryEvent.tags?.mapKeys { it.key as String }?.mapValues { it.value as String } - ?.toMutableMap() - - cocoaFingerprint?.let { fingerprint = it } - cocoaSentryExceptions?.let { exceptions = it } - cocoaContexts?.let { contexts = it } - cocoaBreadcrumbs?.let { breadcrumbs = it } - cocoaTags?.let { tags = it } - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt deleted file mode 100644 index a85825f9..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt +++ /dev/null @@ -1,25 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import cocoapods.Sentry.SentryAttachment -import cocoapods.Sentry.SentryBreadcrumb -import cocoapods.Sentry.SentryEvent -import cocoapods.Sentry.SentryException -import cocoapods.Sentry.SentryId -import cocoapods.Sentry.SentryLevel -import cocoapods.Sentry.SentryMessage -import cocoapods.Sentry.SentryOptions -import cocoapods.Sentry.SentryScope -import cocoapods.Sentry.SentryUser -import cocoapods.Sentry.SentryUserFeedback - -internal typealias CocoaUser = SentryUser -internal typealias CocoaBreadcrumb = SentryBreadcrumb -internal typealias CocoaSentryOptions = SentryOptions -internal typealias CocoaScope = SentryScope -internal typealias CocoaSentryId = SentryId -internal typealias CocoaSentryLevel = SentryLevel -internal typealias CocoaAttachment = SentryAttachment -internal typealias CocoaUserFeedback = SentryUserFeedback -internal typealias CocoaSentryEvent = SentryEvent -internal typealias CocoaMessage = SentryMessage -internal typealias CocoaSentryException = SentryException diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt deleted file mode 100644 index acb05ae5..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt +++ /dev/null @@ -1,25 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.CocoaBreadcrumb -import io.sentry.kotlin.multiplatform.protocol.Breadcrumb - -internal fun Breadcrumb.toCocoaBreadcrumb() = CocoaBreadcrumb().apply { - val scope = this@toCocoaBreadcrumb - setMessage(scope.message) - setType(scope.type) - scope.category?.let { setCategory(it) } - scope.level?.let { setLevel(it.toCocoaSentryLevel()) } - setData(scope.getData()?.toMap()) -} - -internal fun CocoaBreadcrumb.toKmpBreadcrumb() = Breadcrumb().apply { - val scope = this@toKmpBreadcrumb - message = scope.message - type = scope.type - category = scope.category - val map = scope.data as? Map - map?.let { - this.setData(it.toMutableMap()) - } - level = scope.level?.toKmpSentryLevel() -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt deleted file mode 100644 index 8788c4b4..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt +++ /dev/null @@ -1,34 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import kotlinx.cinterop.addressOf -import kotlinx.cinterop.allocArrayOf -import kotlinx.cinterop.convert -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.usePinned -import platform.Foundation.NSData -import platform.Foundation.NSMutableDictionary -import platform.Foundation.allKeys -import platform.Foundation.create -import platform.posix.memcpy - -internal fun NSMutableDictionary.toMutableMap(): MutableMap { - val keys = this.allKeys - val map = mutableMapOf() - for (key in keys) { - map.put(key as K, this.objectForKey(key) as V) - } - return map -} - -internal fun NSData.toByteArray(): ByteArray = ByteArray(this@toByteArray.length.toInt()).apply { - usePinned { - memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length) - } -} - -internal fun ByteArray.toNSData(): NSData = memScoped { - NSData.create( - bytes = allocArrayOf(this@toNSData), - length = this@toNSData.size.toULong().convert() - ) -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt deleted file mode 100644 index c605f902..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.CocoaMessage -import io.sentry.kotlin.multiplatform.protocol.Message - -internal fun CocoaMessage.toKmpMessage() = Message( - message = message, - params = params as? List, - formatted = formatted -) - -internal fun Message.toCocoaMessage(): CocoaMessage { - val scope = this@toCocoaMessage - val cocoaMessage = scope.formatted?.let { CocoaMessage(it) } ?: CocoaMessage() - return cocoaMessage.apply { - message = scope.message - params = scope.params - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt deleted file mode 100644 index 73e6d8f3..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt +++ /dev/null @@ -1,22 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import cocoapods.Sentry.SentryId -import io.sentry.kotlin.multiplatform.CocoaSentryEvent -import io.sentry.kotlin.multiplatform.SentryEvent - -internal fun CocoaSentryEvent.applyKmpEvent(kmpEvent: SentryEvent): CocoaSentryEvent { - kmpEvent.level?.let { level = it.toCocoaSentryLevel() } - kmpEvent.platform?.let { platform = it } - message = kmpEvent.message?.toCocoaMessage() - logger = kmpEvent.logger - fingerprint = kmpEvent.fingerprint - releaseName = kmpEvent.release - environment = kmpEvent.environment - user = kmpEvent.user?.toCocoaUser() - serverName = kmpEvent.serverName - dist = kmpEvent.dist - breadcrumbs = kmpEvent.breadcrumbs.map { it.toCocoaBreadcrumb() }.toMutableList() - tags = kmpEvent.tags.toMutableMap() - eventId = SentryId(kmpEvent.eventId.toString()) - return this -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt deleted file mode 100644 index d811f745..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.CocoaSentryException -import io.sentry.kotlin.multiplatform.protocol.SentryException - -internal fun CocoaSentryException.toKmpSentryException() = SentryException( - type = type, - value = value, - module = module, - threadId = threadId?.longLongValue // longLong represents a 64-bit integer like Kotlin Long -) diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt deleted file mode 100644 index a6962949..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.SentryLevel -import kotlinx.cinterop.convert -import cocoapods.Sentry.SentryLevel as CocoaSentryLevel - -internal fun SentryLevel.toCocoaSentryLevel() = this.toInt().convert() - -internal fun CocoaSentryLevel.toKmpSentryLevel() = SentryLevel.fromInt(this.toInt()) diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt deleted file mode 100644 index 34063c1a..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt +++ /dev/null @@ -1,93 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import PrivateSentrySDKOnly.Sentry.PrivateSentrySDKOnly -import cocoapods.Sentry.SentryHttpStatusCodeRange -import io.sentry.kotlin.multiplatform.BuildKonfig -import io.sentry.kotlin.multiplatform.CocoaSentryEvent -import io.sentry.kotlin.multiplatform.CocoaSentryOptions -import io.sentry.kotlin.multiplatform.SentryEvent -import io.sentry.kotlin.multiplatform.SentryOptions -import io.sentry.kotlin.multiplatform.nsexception.dropKotlinCrashEvent -import kotlinx.cinterop.convert -import platform.Foundation.NSNumber -import NSException.Sentry.SentryEvent as NSExceptionSentryEvent - -internal fun SentryOptions.toCocoaOptionsConfiguration(): (CocoaSentryOptions?) -> Unit = { - it?.applyCocoaBaseOptions(this) -} - -/** - * Applies the given options to this CocoaSentryOptions. - * This avoids code duplication for init on iOS. - */ -internal fun CocoaSentryOptions.applyCocoaBaseOptions(options: SentryOptions) { - dsn = options.dsn - attachStacktrace = options.attachStackTrace - dist = options.dist - options.environment?.let { - environment = it - } - releaseName = options.release - debug = options.debug - sessionTrackingIntervalMillis = options.sessionTrackingIntervalMillis.convert() - enableAutoSessionTracking = options.enableAutoSessionTracking - maxAttachmentSize = options.maxAttachmentSize.convert() - maxBreadcrumbs = options.maxBreadcrumbs.convert() - options.sampleRate?.let { - sampleRate = NSNumber(double = it) - } - options.tracesSampleRate?.let { - tracesSampleRate = NSNumber(double = it) - } - beforeSend = { event -> - val cocoaName = BuildKonfig.SENTRY_COCOA_PACKAGE_NAME - val cocoaVersion = BuildKonfig.SENTRY_COCOA_VERSION - - val sdk = event?.sdk?.toMutableMap() - - val packages = options.sdk?.packages?.map { - mapOf("name" to it.name, "version" to it.version) - }?.toMutableList() ?: mutableListOf() - - val names = packages.map { it["name"] } - if (!names.contains(cocoaName)) { - packages.add(mapOf("name" to cocoaName, "version" to cocoaVersion)) - } - - sdk?.set("packages", packages) - - event?.sdk = sdk - - if (options.beforeSend == null) { - dropKotlinCrashEvent(event as NSExceptionSentryEvent?) as CocoaSentryEvent? - } else { - val modifiedEvent = event?.let { SentryEvent(it) }?.let { unwrappedEvent -> - val result = options.beforeSend?.invoke(unwrappedEvent) - result?.let { event.applyKmpEvent(it) } - } - dropKotlinCrashEvent(modifiedEvent as NSExceptionSentryEvent?) as CocoaSentryEvent? - } - } - - val sdkName = options.sdk?.name ?: BuildKonfig.SENTRY_KMP_COCOA_SDK_NAME - val sdkVersion = options.sdk?.version ?: BuildKonfig.VERSION_NAME - PrivateSentrySDKOnly.setSdkName(sdkName, sdkVersion) - - beforeBreadcrumb = { cocoaBreadcrumb -> - if (options.beforeBreadcrumb == null) { - cocoaBreadcrumb - } else { - cocoaBreadcrumb?.toKmpBreadcrumb() - ?.let { options.beforeBreadcrumb?.invoke(it) }?.toCocoaBreadcrumb() - } - } - - enableCaptureFailedRequests = options.enableCaptureFailedRequests - failedRequestTargets = options.failedRequestTargets - failedRequestStatusCodes = options.failedRequestStatusCodes.map { - SentryHttpStatusCodeRange( - min = it.min.convert(), - max = it.max.convert() - ) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt deleted file mode 100644 index b2af2f82..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt +++ /dev/null @@ -1,20 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.CocoaUser -import io.sentry.kotlin.multiplatform.protocol.User - -internal fun User.toCocoaUser() = CocoaUser().apply { - val scope = this@toCocoaUser - userId = scope.id - username = scope.username - email = scope.email - ipAddress = scope.ipAddress -} - -internal fun CocoaUser.toKmpUser() = User().apply { - val scope = this@toKmpUser - id = scope.userId - username = scope.username - email = scope.email - ipAddress = scope.ipAddress -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt deleted file mode 100644 index 41561b19..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.sentry.kotlin.multiplatform.extensions - -import io.sentry.kotlin.multiplatform.CocoaSentryId -import io.sentry.kotlin.multiplatform.CocoaUserFeedback -import io.sentry.kotlin.multiplatform.protocol.UserFeedback - -internal fun UserFeedback.toCocoaUserFeedback(): CocoaUserFeedback { - val sentryId = CocoaSentryId(sentryId.toString()) - return CocoaUserFeedback(sentryId).apply { - comments = this@toCocoaUserFeedback.comments.toString() - email = this@toCocoaUserFeedback.email.toString() - name = this@toCocoaUserFeedback.name.toString() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt deleted file mode 100644 index 3ea684d8..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt +++ /dev/null @@ -1,74 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/NSException.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlinx.cinterop.convert -import platform.Foundation.NSException -import platform.Foundation.NSNumber -import platform.darwin.NSUInteger -import kotlin.reflect.KClass - -/** - * Returns a [NSException] representing `this` [Throwable]. - * If [appendCausedBy] is `true` then the name, message and stack trace - * of the [causes][Throwable.cause] will be appended, else causes are ignored. - */ -internal fun Throwable.asNSException(appendCausedBy: Boolean = false): NSException { - val returnAddresses = getFilteredStackTraceAddresses().let { addresses -> - if (!appendCausedBy) return@let addresses - addresses.toMutableList().apply { - for (cause in causes) { - addAll(cause.getFilteredStackTraceAddresses(true, addresses)) - } - } - }.map { - @Suppress("RemoveExplicitTypeArguments") - NSNumber(unsignedInteger = it.convert()) - } - return ThrowableNSException(name, getReason(appendCausedBy), returnAddresses) -} - -/** - * Returns the [qualifiedName][KClass.qualifiedName] or [simpleName][KClass.simpleName] of `this` throwable. - * If both are `null` then "Throwable" is returned. - */ -internal val Throwable.name: String - get() = this::class.qualifiedName ?: this::class.simpleName ?: "Throwable" - -/** - * Returns the [message][Throwable.message] of this throwable. - * If [appendCausedBy] is `true` then caused by lines with the format - * "Caused by: $[name]: $[message][Throwable.message]" will be appended. - */ -internal fun Throwable.getReason(appendCausedBy: Boolean = false): String? { - if (!appendCausedBy) return message - return buildString { - message?.let(::append) - for (cause in causes) { - if (isNotEmpty()) appendLine() - append("Caused by: ") - append(cause.name) - cause.message?.let { append(": $it") } - } - }.takeIf { it.isNotEmpty() } -} - -internal class ThrowableNSException( - name: String, - reason: String?, - private val returnAddresses: List -) : NSException(name, reason, null) { - override fun callStackReturnAddresses(): List = returnAddresses -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt deleted file mode 100644 index 6fded3c5..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt +++ /dev/null @@ -1,126 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-sentry/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/sentry/Sentry.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import NSException.Sentry.NSExceptionKt_SentryCrashStackCursorCleanup -import NSException.Sentry.NSExceptionKt_SentryCrashStackCursorFromNSException -import NSException.Sentry.NSExceptionKt_SentryMechanismSetNotHandled -import NSException.Sentry.NSExceptionKt_SentryThreadSetCrashed -import NSException.Sentry.SentryDependencyContainer -import NSException.Sentry.SentryEnvelope -import NSException.Sentry.SentryEnvelopeHeader -import NSException.Sentry.SentryEnvelopeItem -import NSException.Sentry.SentryEvent -import NSException.Sentry.SentryException -import NSException.Sentry.SentryMechanism -import NSException.Sentry.SentrySDK -import NSException.Sentry.SentryThread -import NSException.Sentry.SentryThreadInspector -import NSException.Sentry.currentHub -import NSException.Sentry.isCrashEvent -import NSException.Sentry.kSentryLevelFatal -import NSException.Sentry.prepareEvent -import NSException.Sentry.storeEnvelope -import NSException.Sentry.threadInspector -import kotlinx.cinterop.UnsafeNumber -import platform.Foundation.NSException -import platform.Foundation.NSNumber - -/** - * Drops the Kotlin crash that follows an unhandled Kotlin exception except our custom SentryEvent. - */ -internal fun dropKotlinCrashEvent(event: SentryEvent?): SentryEvent? { - return event?.takeUnless { it.isCrashEvent && (it.tags?.containsKey(KOTLIN_CRASH_TAG) ?: false) } -} - -/** - * Sets the unhandled exception hook such that all unhandled exceptions are logged to Sentry as fatal exceptions. - * If an unhandled exception hook was already set, that hook will be invoked after the exception is logged. - * Note: once the exception is logged the program will be terminated. - * @see wrapUnhandledExceptionHook - */ -internal fun setSentryUnhandledExceptionHook(): Unit = wrapUnhandledExceptionHook { throwable -> - val envelope = throwable.asSentryEnvelope() - // The envelope will be persisted, so we can safely terminate afterwards. - // https://github.com/getsentry/sentry-cocoa/blob/678172142ac1d10f5ed7978f69d16ab03e801057/Sources/Sentry/SentryClient.m#L409 - SentrySDK.storeEnvelope(envelope) - SentrySDK.configureScope { scope -> - scope?.setTagValue(KOTLIN_CRASH_TAG, KOTLIN_CRASH_TAG) - } -} - -/** - * Tag used to mark the Kotlin termination crash. - */ -internal const val KOTLIN_CRASH_TAG = "nsexceptionkt.kotlin_crashed" - -/** - * Converts `this` [Throwable] to a [SentryEnvelope]. - */ -internal fun Throwable.asSentryEnvelope(): SentryEnvelope { - val event = asSentryEvent() - val preparedEvent = SentrySDK.currentHub().let { hub -> - hub.getClient()?.prepareEvent(event, hub.scope, alwaysAttachStacktrace = false, isCrashEvent = true) - } ?: event - val item = SentryEnvelopeItem(preparedEvent) - // TODO: pass traceState when enabling performance monitoring for KMP SDK - val header = SentryEnvelopeHeader(preparedEvent.eventId, null) - return SentryEnvelope(header, listOf(item)) -} - -/** - * Converts `this` [Throwable] to a [SentryEvent]. - */ -@Suppress("UnnecessaryOptInAnnotation") -@OptIn(UnsafeNumber::class) -private fun Throwable.asSentryEvent(): SentryEvent = SentryEvent(kSentryLevelFatal).apply { - isCrashEvent = true - @Suppress("UNCHECKED_CAST") - val threads = threadInspector?.getCurrentThreadsWithStackTrace() as List? - this.threads = threads - val currentThread = threads?.firstOrNull { it.current?.boolValue ?: false }?.apply { - NSExceptionKt_SentryThreadSetCrashed(this) - // Crashed threats shouldn't have a stacktrace, the thread_id should be set on the exception instead - // https://develop.sentry.dev/sdk/event-payloads/threads/ - stacktrace = null - } - debugMeta = threads?.let { - SentryDependencyContainer.sharedInstance().debugImageProvider.getDebugImagesForThreads(it) - } - exceptions = this@asSentryEvent - .let { throwable -> throwable.causes.asReversed() + throwable } - .map { it.asNSException().asSentryException(currentThread?.threadId) } -} - -/** - * Converts `this` [NSException] to a [SentryException]. - */ -private fun NSException.asSentryException( - threadId: NSNumber? -): SentryException = SentryException(reason ?: "", name ?: "Throwable").apply { - this.threadId = threadId - mechanism = SentryMechanism("generic").apply { - NSExceptionKt_SentryMechanismSetNotHandled(this) - } - stacktrace = threadInspector?.stacktraceBuilder?.let { stacktraceBuilder -> - val cursor = NSExceptionKt_SentryCrashStackCursorFromNSException(this@asSentryException) - val stacktrace = stacktraceBuilder.retrieveStacktraceFromCursor(cursor) - NSExceptionKt_SentryCrashStackCursorCleanup(cursor) - stacktrace - } -} - -private val threadInspector: SentryThreadInspector? - get() = SentrySDK.currentHub().getClient()?.threadInspector diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt deleted file mode 100644 index 8fec98f7..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt +++ /dev/null @@ -1,83 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/Throwable.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -/** - * Returns a list with all the [causes][Throwable.cause]. - * The first element will be the cause, the second the cause of the cause, etc. - * This function stops once a reference cycles is detected. - */ -internal val Throwable.causes: List get() = buildList { - val causes = mutableSetOf() - var cause = cause - while (cause != null && causes.add(cause)) { - add(cause) - cause = cause.cause - } -} - -/** - * Returns a list of stack trace addresses representing - * the stack trace of the constructor call to `this` [Throwable]. - * @param keepLastInit `true` to preserve the last constructor call, `false` to drop all constructor calls. - * @param commonAddresses a list of addresses used to drop the last common addresses. - * @see getStackTraceAddresses - */ -internal fun Throwable.getFilteredStackTraceAddresses( - keepLastInit: Boolean = false, - commonAddresses: List = emptyList() -): List = getStackTraceAddresses().dropInitAddresses( - qualifiedClassName = this::class.qualifiedName ?: Throwable::class.qualifiedName!!, - stackTrace = getStackTrace(), - keepLast = keepLastInit -).dropCommonAddresses(commonAddresses) - -/** - * Returns a list containing all addresses expect for the first addresses - * matching the constructor call of the [qualifiedClassName]. - * If [keepLast] is `true` the last constructor call won't be dropped. - */ -internal fun List.dropInitAddresses( - qualifiedClassName: String, - stackTrace: Array, - keepLast: Boolean = false -): List { - val exceptionInit = "kfun:$qualifiedClassName#" - var dropCount = 0 - var foundInit = false - for (i in stackTrace.indices) { - if (stackTrace[i].contains(exceptionInit)) { - foundInit = true - } else if (foundInit) { - dropCount = i - break - } - } - if (keepLast) dropCount-- - return drop(kotlin.math.max(0, dropCount)) -} - -/** - * Returns a list containing all addresses expect for the last addresses that match with the [commonAddresses]. - */ -internal fun List.dropCommonAddresses( - commonAddresses: List -): List { - var i = commonAddresses.size - if (i == 0) return this - return dropLastWhile { - i-- >= 0 && commonAddresses[i] == it - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt deleted file mode 100644 index 538aed3b..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt +++ /dev/null @@ -1,36 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonMain/kotlin/com/rickclephas/kmp/nsexceptionkt/core/UnhandledExceptionHook.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.native.concurrent.AtomicReference -import kotlin.native.concurrent.freeze - -/** - * Wraps the unhandled exception hook such that the provided [hook] is invoked - * before the currently set unhandled exception hook is invoked. - * Note: once the unhandled exception hook returns the program will be terminated. - * @see setUnhandledExceptionHook - * @see terminateWithUnhandledException - */ -@OptIn(ExperimentalStdlibApi::class) -internal fun wrapUnhandledExceptionHook(hook: (Throwable) -> Unit) { - val prevHook = AtomicReference(null) - val wrappedHook: ReportUnhandledExceptionHook = { - hook(it) - prevHook.value?.invoke(it) - terminateWithUnhandledException(it) - } - prevHook.value = setUnhandledExceptionHook(wrappedHook.freeze()) -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt b/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt deleted file mode 100644 index 9f054bfe..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.sentry.kotlin.multiplatform.protocol - -import io.sentry.kotlin.multiplatform.CocoaSentryId - -public actual data class SentryId actual constructor(val sentryIdString: String) { - - public actual companion object { - public actual val EMPTY_ID: SentryId = SentryId("") - } - - private var cocoaSentryId: CocoaSentryId? = null - - init { - cocoaSentryId = if (sentryIdString.isEmpty()) { - CocoaSentryId.empty() - } else { - CocoaSentryId(sentryIdString) - } - } - - actual override fun toString(): String { - return cocoaSentryId.toString() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt deleted file mode 100644 index 9601553b..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/AppleSentryIdTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.protocol.SentryId -import kotlin.test.Test -import kotlin.test.assertEquals - -class AppleSentryIdTest { - - @Test - fun `Cocoa SentryId with invalid uuid string returns only zeroes`() { - val uuidString = "ec720-b6f6-4efc--5c1" - val expected = SentryId.EMPTY_ID.toString() - val actual = SentryId(uuidString).toString() - assertEquals(expected, actual) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt deleted file mode 100644 index bb9aac47..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import cocoapods.Sentry.SentryScope as CocoaScope - -actual abstract class BaseSentryScopeTest { - actual fun initializeScope(): Scope { - val cocoaScope = CocoaScope() - return CocoaScopeProvider(cocoaScope) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt deleted file mode 100644 index 1ea225ae..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryTest.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.sentry.kotlin.multiplatform - -actual abstract class BaseSentryTest { - actual val platform: String = "Apple" - actual val authToken: String? = "fake-auth-token" - actual fun sentryInit(optionsConfiguration: OptionsConfiguration) { - Sentry.init(optionsConfiguration) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt deleted file mode 100644 index 944d7514..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt +++ /dev/null @@ -1,23 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions -import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb -import io.sentry.kotlin.multiplatform.protocol.Breadcrumb - -actual class BreadcrumbConfigurator { - private val cocoaBreadcrumb = CocoaBreadcrumb() - actual val originalBreadcrumb: Breadcrumb = cocoaBreadcrumb.toKmpBreadcrumb() - - actual fun applyOptions(optionsConfiguration: OptionsConfiguration): Breadcrumb? { - val kmpOptions = SentryOptions() - optionsConfiguration.invoke(kmpOptions) - return applyOptions(kmpOptions) - } - - actual fun applyOptions(options: SentryOptions): Breadcrumb? { - val cocoaOptions = CocoaSentryOptions() - cocoaOptions.applyCocoaBaseOptions(options) - val cocoaModifiedBreadcrumb = cocoaOptions.beforeBreadcrumb?.invoke(cocoaBreadcrumb) - return cocoaModifiedBreadcrumb?.toKmpBreadcrumb() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt deleted file mode 100644 index 906f89fd..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel -import io.sentry.kotlin.multiplatform.protocol.Breadcrumb - -actual data class BreadcrumbTestConverter actual constructor(val breadcrumb: Breadcrumb) { - - actual fun getType(): String? { - return breadcrumb.toCocoaBreadcrumb().type - } - - actual fun getCategory(): String? { - return breadcrumb.toCocoaBreadcrumb().category - } - - actual fun getMessage(): String? { - return breadcrumb.toCocoaBreadcrumb().message - } - - actual fun getData(): MutableMap { - return breadcrumb.toCocoaBreadcrumb().data as MutableMap - } - - actual fun getLevel(): SentryLevel? { - return breadcrumb.toCocoaBreadcrumb().level.toKmpSentryLevel() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt deleted file mode 100644 index 1218677b..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toByteArray -import io.sentry.kotlin.multiplatform.extensions.toNSData -import platform.Foundation.NSNumber -import platform.Foundation.NSString -import platform.Foundation.NSUTF8StringEncoding -import platform.Foundation.dataUsingEncoding -import kotlin.test.Test -import kotlin.test.assertContentEquals -import kotlin.test.assertEquals - -class FoundationTest { - @Test - fun `convert string to NSData and ByteArray is correct`() { - val text = "$!()I!(DKDASKDKSD(#(ldkiadjk91jd" - val nsString = "$!()I!(DKDASKDKSD(#(ldkiadjk91jd" as NSString - - val nsData = nsString.dataUsingEncoding(NSUTF8StringEncoding)!! - val byteArray = text.encodeToByteArray() - - assertContentEquals(byteArray, nsData.toByteArray()) - assertContentEquals(byteArray, byteArray.toNSData().toByteArray()) - assertEquals(nsData, byteArray.toNSData()) - assertEquals(nsData, nsData.toByteArray().toNSData()) - } - - @Test - fun `NSNumber longLong converts to Long correctly`() { - val longValue = 4937446359977427944L - val nsNumber = NSNumber(longLong = longValue) - assertEquals(longValue, nsNumber.longLongValue) - } - - @Test - fun `NSNumber int converts to Long correctly`() { - val intValue = 493744635 - val nsNumber = NSNumber(int = intValue) - assertEquals(intValue.toLong(), nsNumber.longLongValue) - } - - @Test - fun `NSNumber short converts to Long correctly`() { - val shortValue: Short = 4937 - val nsNumber = NSNumber(short = shortValue) - assertEquals(shortValue.toLong(), nsNumber.longLongValue) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt deleted file mode 100644 index 9577fd61..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt +++ /dev/null @@ -1,25 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions - -actual class SentryEventConfigurator { - private val cocoaSentryEvent = CocoaSentryEvent() - actual val originalEvent: SentryEvent = SentryEvent(cocoaSentryEvent) - - actual fun applyOptions(optionsConfiguration: OptionsConfiguration): SentryEvent? { - val kmpOptions = SentryOptions() - optionsConfiguration.invoke(kmpOptions) - return applyOptions(kmpOptions) - } - - actual fun applyOptions(options: SentryOptions): SentryEvent? { - val cocoaOptions = CocoaSentryOptions() - cocoaOptions.applyCocoaBaseOptions(options) - val cocoaModifiedSentryEvent = cocoaOptions.beforeSend?.invoke(cocoaSentryEvent) - return if (cocoaModifiedSentryEvent == null) { - null - } else { - SentryEvent(cocoaModifiedSentryEvent) - } - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt deleted file mode 100644 index fbcf2037..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt +++ /dev/null @@ -1,64 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryException -import io.sentry.kotlin.multiplatform.protocol.SentryException -import kotlinx.cinterop.convert -import platform.Foundation.NSNumber -import kotlin.test.Test - -class SentryExceptionTest { - private val value = "testValue" - private val type = "type" - private val threadId = 1 - - private fun getCocoaSentryException(): CocoaSentryException { - return CocoaSentryException(value = value, type = type) - } - - private fun getKmpSentryException(threadId: Long? = this.threadId.toLong()): SentryException { - return SentryException(value = value, type = type, threadId = threadId) - } - - @Test - fun `SentryException ThreadId NSNumber long conversion`() { - val cocoaSentryException = getCocoaSentryException().apply { - threadId = NSNumber(long = this@SentryExceptionTest.threadId.convert()) - } - val sentryException = getKmpSentryException() - assert(cocoaSentryException.toKmpSentryException() == sentryException) - } - - @Test - fun `SentryException ThreadId NSNumber longLong conversion`() { - val cocoaSentryException = getCocoaSentryException().apply { - threadId = NSNumber(longLong = this@SentryExceptionTest.threadId.convert()) - } - val sentryException = getKmpSentryException() - assert(cocoaSentryException.toKmpSentryException() == sentryException) - } - - @Test - fun `SentryException ThreadId NSNumber int conversion`() { - val cocoaSentryException = getCocoaSentryException().apply { - threadId = NSNumber(int = this@SentryExceptionTest.threadId.convert()) - } - val sentryException = getKmpSentryException() - assert(cocoaSentryException.toKmpSentryException() == sentryException) - } - - @Test - fun `SentryException ThreadId NSNumber short conversion`() { - val cocoaSentryException = getCocoaSentryException().apply { - threadId = NSNumber(short = this@SentryExceptionTest.threadId.convert()) - } - val sentryException = getKmpSentryException() - assert(cocoaSentryException.toKmpSentryException() == sentryException) - } - - @Test - fun `SentryException ThreadId NSNumber null conversion`() { - val cocoaSentryException = getCocoaSentryException() - val sentryException = getKmpSentryException(threadId = null) - assert(cocoaSentryException.toKmpSentryException() == sentryException) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt deleted file mode 100644 index 10ffa121..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.sentry.kotlin.multiplatform - -import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel -import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel - -actual class SentryLevelTestConverter actual constructor() { - actual fun convert(sentryLevel: SentryLevel?): SentryLevel? { - return sentryLevel?.toCocoaSentryLevel()?.toKmpSentryLevel() - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt deleted file mode 100644 index c157eb30..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/CommonAddressesTests.kt +++ /dev/null @@ -1,44 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/CommonAddressesTests.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertSame - -class CommonAddressesTests { - - @Test - fun testDropCommon() { - val commonAddresses = listOf(5, 4, 3, 2, 1, 0) - val addresses = listOf(8, 7, 6, 2, 1, 0) - val withoutCommonAddresses = addresses.dropCommonAddresses(commonAddresses) - assertEquals(listOf(8, 7, 6), withoutCommonAddresses) - } - - @Test - fun testDropCommonEmptyCommon() { - val addresses = listOf(0, 1, 2) - val withoutCommonAddresses = addresses.dropCommonAddresses(emptyList()) - assertSame(addresses, withoutCommonAddresses) - } - - @Test - fun testDropCommonSameAddresses() { - val addresses = listOf(0, 1, 2) - val withoutCommonAddresses = addresses.dropCommonAddresses(addresses) - assertEquals(emptyList(), withoutCommonAddresses) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt deleted file mode 100644 index a5a81db2..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/InitAddressesTests.kt +++ /dev/null @@ -1,56 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/InitAddressesTests.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.test.Test -import kotlin.test.assertEquals - -class InitAddressesTests { - - private val qualifiedClassName = "my.app.CustomException" - private val addresses = listOf(0, 1, 2, 3, 4, 5) - private val stackTrace = arrayOf( - "123 kfun:kotlin.Throwable#(kotlin.String?){} + 24 abc", - "456 kfun:kotlin.Exception#(kotlin.String?){} + 5 def", - "789 kfun:my.app.CustomException#(kotlin.String?){} + 10 hij", - "012 kfun:my.app.CustomException#(){} + 12 klm", - "345 kfun:my.app.class#function1(){} + 50 nop", - "678 kfun:my.app.class#function2(){} + 60 qrs" - ) - - @Test - fun testDropInit() { - val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, false) - assertEquals(listOf(4, 5), withoutInitAddresses) - } - - @Test - fun testDropInitKeepLast() { - val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, true) - assertEquals(listOf(3, 4, 5), withoutInitAddresses) - } - - private fun testDropInitUnknownClassName(keepLast: Boolean) { - val qualifiedClassName = "my.app.SomeOtherException" - val withoutInitAddresses = addresses.dropInitAddresses(qualifiedClassName, stackTrace, keepLast) - assertEquals(addresses, withoutInitAddresses) - } - - @Test - fun testDropInitUnknownClassNameDropLast() = testDropInitUnknownClassName(false) - - @Test - fun testDropInitUnknownClassNameKeepLast() = testDropInitUnknownClassName(true) -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt deleted file mode 100644 index cce236bb..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt +++ /dev/null @@ -1,53 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableCausesTests.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.test.Test -import kotlin.test.assertEquals - -class ThrowableCausesTests { - - @Test - fun testNoCauses() { - assert(Throwable().causes.isEmpty()) - } - - @Test - fun testSingleCause() { - val cause = Throwable("Cause throwable") - val throwable = Throwable("Test throwable", cause) - assertEquals(listOf(cause), throwable.causes) - } - - @Test - fun testMultipleCauses() { - val cause1 = Throwable("Cause 1 throwable") - val cause2 = Throwable("Cause 2 throwable", cause1) - val throwable = Throwable("Test throwable", cause2) - assertEquals(listOf(cause2, cause1), throwable.causes) - } - - private class MyThrowable(override val message: String?) : Throwable() { - override var cause: Throwable? = null - } - - @Test - fun testReferenceCycle() { - val cause = MyThrowable("Cause throwable") - val throwable = Throwable("Test throwable", cause) - cause.cause = throwable - assertEquals(listOf(cause, throwable), throwable.causes) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt deleted file mode 100644 index 2caeda5c..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableNameTests.kt +++ /dev/null @@ -1,48 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableNameTests.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.test.Test -import kotlin.test.assertEquals - -class ThrowableNameTests { - - private class MyThrowable : Throwable() - - @Test - fun testMyThrowableName() { - val exception = MyThrowable() - assertEquals("io.sentry.kotlin.multiplatform.nsexception.ThrowableNameTests.MyThrowable", exception.name) - } - - @Test - fun testIllegalArgumentExceptionName() { - val exception = IllegalArgumentException() - assertEquals("kotlin.IllegalArgumentException", exception.name) - } - - @Test - fun testLocalThrowableName() { - class MyLocalThrowable : Throwable() - val throwable = MyLocalThrowable() - assertEquals("MyLocalThrowable", throwable.name) - } - - @Test - fun testAnonymousThrowableName() { - val throwable = object : Throwable() { } - assertEquals("Throwable", throwable.name) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt b/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt deleted file mode 100644 index d7cb9f90..00000000 --- a/sentry-kotlin-multiplatform/src/commonAppleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableReasonTests.kt +++ /dev/null @@ -1,104 +0,0 @@ -// https://github.com/rickclephas/NSExceptionKt/blob/master/nsexception-kt-core/src/commonTest/kotlin/com/rickclephas/kmp/nsexceptionkt/core/ThrowableReasonTests.kt -// -// Copyright (c) 2022 Rick Clephas -// -// 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 be included in all -// copies or substantial portions of the Software. - -package io.sentry.kotlin.multiplatform.nsexception - -import kotlin.test.Test -import kotlin.test.assertEquals - -class ThrowableReasonTests { - - private fun testReasonNoCause(message: String?, appendCausedBy: Boolean) { - val exception = Exception(message) - val reason = exception.getReason(appendCausedBy) - assertEquals(message, reason) - } - - @Test - fun testReasonNoCauseDontAppend() = testReasonNoCause("Test message", false) - - @Test - fun testReasonNoCauseAppend() = testReasonNoCause("Test message", true) - - @Test - fun testReasonNoMessageNoCauseDontAppend() = testReasonNoCause(null, false) - - @Test - fun testReasonNoMessageNoCauseAppend() = testReasonNoCause(null, true) - - @Test - fun testReasonWithCauseDontAppend() { - val cause = Exception("Cause message") - val message = "Test message" - val exception = Exception(message, cause) - val reason = exception.getReason(false) - assertEquals(message, reason) - } - - @Test - fun testReasonWithCause() { - val cause = Exception("Cause message") - val exception = Exception("Test message", cause) - val reason = exception.getReason(true) - assertEquals( - """ - Test message - Caused by: kotlin.Exception: Cause message - """.trimIndent(), - reason - ) - } - - @Test - fun testReasonNoMessageWithCause() { - val cause = Exception("Cause message") - val exception = Exception(null, cause) - val reason = exception.getReason(true) - assertEquals( - """ - Caused by: kotlin.Exception: Cause message - """.trimIndent(), - reason - ) - } - - @Test - fun testReasonNoCauseMessage() { - val exception = Exception("Test message", Exception()) - val reason = exception.getReason(true) - assertEquals( - """ - Test message - Caused by: kotlin.Exception - """.trimIndent(), - reason - ) - } - - @Test - fun testReasonWithDoubleCause() { - val cause1 = Exception("Cause1 message") - val cause2 = Exception("Cause2 message", cause1) - val exception = Exception("Test message", cause2) - val reason = exception.getReason(true) - assertEquals( - """ - Test message - Caused by: kotlin.Exception: Cause2 message - Caused by: kotlin.Exception: Cause1 message - """.trimIndent(), - reason - ) - } -} diff --git a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt index 517dd648..859a60f5 100644 --- a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt +++ b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt @@ -1,129 +1,129 @@ -package io.sentry.kotlin.multiplatform - -import io.ktor.client.HttpClient -import io.ktor.client.request.get -import io.ktor.client.request.headers -import io.ktor.client.statement.bodyAsText -import io.ktor.http.HttpHeaders -import io.sentry.kotlin.multiplatform.utils.org -import io.sentry.kotlin.multiplatform.utils.projectSlug -import io.sentry.kotlin.multiplatform.utils.realDsn -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue -import kotlin.time.Duration.Companion.seconds - -@Serializable -private data class SentryEventSerializable( - val id: String? = null, - val project: Long? = null, - val release: String? = null, - val platform: String? = null, - val message: String? = "", - val tags: List> = listOf(), - val fingerprint: List = listOf(), - val level: String? = null, - val logger: String? = null, - val title: String? = null -) - -class SentryE2ETest : BaseSentryTest() { - private val client = HttpClient() - private val jsonDecoder = Json { ignoreUnknownKeys = true } - private var sentEvent: SentryEvent? = null - - @BeforeTest - fun setup() { - assertNotNull(authToken) - assertTrue(authToken.isNotEmpty()) - sentryInit { options -> - options.dsn = realDsn - options.beforeSend = { event -> - sentEvent = event - event - } - } - } - - private suspend fun fetchEvent(eventId: String): String { - val url = - "https://sentry.io/api/0/projects/$org/$projectSlug/events/$eventId/" - val response = client.get(url) { - headers { - append( - HttpHeaders.Authorization, - "Bearer $authToken" - ) - } - } - return response.bodyAsText() - } - - private suspend fun waitForEventRetrieval(eventId: String): SentryEventSerializable { - var json = "" - val result: SentryEventSerializable = withContext(Dispatchers.Default) { - while (json.isEmpty() || json.contains("Event not found")) { - delay(5000) - json = fetchEvent(eventId) - assertFalse(json.contains("Invalid token"), "Invalid auth token") - } - jsonDecoder.decodeFromString(json) - } - return result - } - - // TODO: e2e tests are currently disabled for Apple targets as there are SSL issues that prevent sending events in tests - // See: https://github.com/getsentry/sentry-kotlin-multiplatform/issues/17 - - @Test - fun `capture message and fetch event from Sentry`() = runTest(timeout = 30.seconds) { - if (platform != "Apple") { - val message = "Test running on $platform" - val eventId = Sentry.captureMessage(message) - val fetchedEvent = waitForEventRetrieval(eventId.toString()) - fetchedEvent.tags.forEach { println(it["value"]) } - assertEquals(eventId.toString(), fetchedEvent.id) - assertEquals(sentEvent?.message?.formatted, fetchedEvent.message) - assertEquals(message, fetchedEvent.title) - assertEquals(sentEvent?.release, fetchedEvent.release) - assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) - assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) - assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.level?.name?.lowercase() }?.size) - assertEquals(sentEvent?.logger, fetchedEvent.logger) - } - } - - @Test - fun `capture exception and fetch event from Sentry`() = runTest(timeout = 30.seconds) { - if (platform != "Apple") { - val exceptionMessage = "Test exception on platform $platform" - val eventId = - Sentry.captureException(IllegalArgumentException(exceptionMessage)) - val fetchedEvent = waitForEventRetrieval(eventId.toString()) - assertEquals(eventId.toString(), fetchedEvent.id) - assertEquals("IllegalArgumentException: $exceptionMessage", fetchedEvent.title) - assertEquals(sentEvent?.release, fetchedEvent.release) - assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) - assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) - assertEquals(2, fetchedEvent.tags.find { it["value"] == SentryLevel.ERROR.toString().lowercase() }?.size) - assertEquals(sentEvent?.logger, fetchedEvent.logger) - } - } - - @AfterTest - fun tearDown() { - sentEvent = null - Sentry.close() - } -} +// package io.sentry.kotlin.multiplatform +// +// import io.ktor.client.HttpClient +// import io.ktor.client.request.get +// import io.ktor.client.request.headers +// import io.ktor.client.statement.bodyAsText +// import io.ktor.http.HttpHeaders +// import io.sentry.kotlin.multiplatform.utils.org +// import io.sentry.kotlin.multiplatform.utils.projectSlug +// import io.sentry.kotlin.multiplatform.utils.realDsn +// import kotlinx.coroutines.Dispatchers +// import kotlinx.coroutines.delay +// import kotlinx.coroutines.test.runTest +// import kotlinx.coroutines.withContext +// import kotlinx.serialization.Serializable +// import kotlinx.serialization.decodeFromString +// import kotlinx.serialization.json.Json +// import kotlin.test.AfterTest +// import kotlin.test.BeforeTest +// import kotlin.test.Test +// import kotlin.test.assertEquals +// import kotlin.test.assertFalse +// import kotlin.test.assertNotNull +// import kotlin.test.assertTrue +// import kotlin.time.Duration.Companion.seconds +// +// @Serializable +// private data class SentryEventSerializable( +// val id: String? = null, +// val project: Long? = null, +// val release: String? = null, +// val platform: String? = null, +// val message: String? = "", +// val tags: List> = listOf(), +// val fingerprint: List = listOf(), +// val level: String? = null, +// val logger: String? = null, +// val title: String? = null +// ) +// +// class SentryE2ETest : BaseSentryTest() { +// private val client = HttpClient() +// private val jsonDecoder = Json { ignoreUnknownKeys = true } +// private var sentEvent: SentryEvent? = null +// +// @BeforeTest +// fun setup() { +// assertNotNull(authToken) +// assertTrue(authToken.isNotEmpty()) +// sentryInit { options -> +// options.dsn = realDsn +// options.beforeSend = { event -> +// sentEvent = event +// event +// } +// } +// } +// +// private suspend fun fetchEvent(eventId: String): String { +// val url = +// "https://sentry.io/api/0/projects/$org/$projectSlug/events/$eventId/" +// val response = client.get(url) { +// headers { +// append( +// HttpHeaders.Authorization, +// "Bearer $authToken" +// ) +// } +// } +// return response.bodyAsText() +// } +// +// private suspend fun waitForEventRetrieval(eventId: String): SentryEventSerializable { +// var json = "" +// val result: SentryEventSerializable = withContext(Dispatchers.Default) { +// while (json.isEmpty() || json.contains("Event not found")) { +// delay(5000) +// json = fetchEvent(eventId) +// assertFalse(json.contains("Invalid token"), "Invalid auth token") +// } +// jsonDecoder.decodeFromString(json) +// } +// return result +// } +// +// // TODO: e2e tests are currently disabled for Apple targets as there are SSL issues that prevent sending events in tests +// // See: https://github.com/getsentry/sentry-kotlin-multiplatform/issues/17 +// +// @Test +// fun `capture message and fetch event from Sentry`() = runTest(timeout = 30.seconds) { +// if (platform != "Apple") { +// val message = "Test running on $platform" +// val eventId = Sentry.captureMessage(message) +// val fetchedEvent = waitForEventRetrieval(eventId.toString()) +// fetchedEvent.tags.forEach { println(it["value"]) } +// assertEquals(eventId.toString(), fetchedEvent.id) +// assertEquals(sentEvent?.message?.formatted, fetchedEvent.message) +// assertEquals(message, fetchedEvent.title) +// assertEquals(sentEvent?.release, fetchedEvent.release) +// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) +// assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) +// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.level?.name?.lowercase() }?.size) +// assertEquals(sentEvent?.logger, fetchedEvent.logger) +// } +// } +// +// @Test +// fun `capture exception and fetch event from Sentry`() = runTest(timeout = 30.seconds) { +// if (platform != "Apple") { +// val exceptionMessage = "Test exception on platform $platform" +// val eventId = +// Sentry.captureException(IllegalArgumentException(exceptionMessage)) +// val fetchedEvent = waitForEventRetrieval(eventId.toString()) +// assertEquals(eventId.toString(), fetchedEvent.id) +// assertEquals("IllegalArgumentException: $exceptionMessage", fetchedEvent.title) +// assertEquals(sentEvent?.release, fetchedEvent.release) +// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) +// assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) +// assertEquals(2, fetchedEvent.tags.find { it["value"] == SentryLevel.ERROR.toString().lowercase() }?.size) +// assertEquals(sentEvent?.logger, fetchedEvent.logger) +// } +// } +// +// @AfterTest +// fun tearDown() { +// sentEvent = null +// Sentry.close() +// } +// } diff --git a/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts b/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts index 3e70dcaf..550994e5 100644 --- a/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts @@ -47,5 +47,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(false) + autoUploadProguardMapping.set(true) } diff --git a/sentry-samples/kmp-app-cocoapods/shared/build.gradle.kts b/sentry-samples/kmp-app-cocoapods/shared/build.gradle.kts index 3f4394e1..71ace780 100644 --- a/sentry-samples/kmp-app-cocoapods/shared/build.gradle.kts +++ b/sentry-samples/kmp-app-cocoapods/shared/build.gradle.kts @@ -5,7 +5,9 @@ plugins { } kotlin { - android { + applyDefaultHierarchyTemplate() + + androidTarget { compilations.all { kotlinOptions { jvmTarget = "1.8" @@ -33,36 +35,12 @@ kotlin { } sourceSets { - val commonMain by getting { - dependencies { - api(project(":sentry-kotlin-multiplatform")) - } - } - val commonTest by getting { - dependencies { - implementation(kotlin("test")) - } - } - val jvmMain by getting - val androidMain by getting - val androidUnitTest by getting - val iosX64Main by getting - val iosArm64Main by getting - val iosSimulatorArm64Main by getting - val iosMain by creating { - dependsOn(commonMain) - iosX64Main.dependsOn(this) - iosArm64Main.dependsOn(this) - iosSimulatorArm64Main.dependsOn(this) + commonMain.dependencies { + api(project(":sentry-kotlin-multiplatform")) } - val iosX64Test by getting - val iosArm64Test by getting - val iosSimulatorArm64Test by getting - val iosTest by creating { - dependsOn(commonTest) - iosX64Test.dependsOn(this) - iosArm64Test.dependsOn(this) - iosSimulatorArm64Test.dependsOn(this) + + commonTest.dependencies { + implementation(kotlin("test")) } } } diff --git a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts index 7e62c3c7..262a30f7 100644 --- a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts @@ -41,7 +41,7 @@ android { jvmTarget = JavaVersion.VERSION_1_8.toString() } composeOptions { - kotlinCompilerExtensionVersion = "1.4.0-dev-k1.8.0-33c0ad36f83" + kotlinCompilerExtensionVersion = "1.5.4" } } @@ -57,7 +57,7 @@ dependencies { implementation("androidx.navigation:navigation-compose:2.5.3") implementation("androidx.navigation:navigation-runtime:2.5.3") implementation("io.insert-koin:koin-android:3.4.0") - implementation("androidx.compose.compiler:compiler:1.4.0-dev-k1.8.0-33c0ad36f83") + implementation("androidx.compose.compiler:compiler:1.5.4") implementation("androidx.compose.ui:ui:1.5.0-alpha02") implementation("androidx.compose.ui:ui-tooling:1.5.0-alpha02") implementation("androidx.compose.foundation:foundation:1.5.0-alpha02") @@ -73,5 +73,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(false) + autoUploadProguardMapping.set(true) } diff --git a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts index f906eba3..2f233076 100644 --- a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts @@ -4,7 +4,9 @@ plugins { } kotlin { - android() + applyDefaultHierarchyTemplate() + + androidTarget() listOf( iosX64(), iosArm64(), @@ -18,40 +20,18 @@ kotlin { } sourceSets { - val commonMain by getting { - dependencies { - api(project(":sentry-kotlin-multiplatform")) - implementation("io.insert-koin:koin-core:3.4.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - } - } - val commonTest by getting { - dependencies { - implementation(kotlin("test")) - } + commonMain.dependencies { + api(project(":sentry-kotlin-multiplatform")) + implementation("io.insert-koin:koin-core:3.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") } - val androidMain by getting { - dependencies { - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1") - } - } - val iosX64Main by getting - val iosArm64Main by getting - val iosSimulatorArm64Main by getting - val iosMain by creating { - dependsOn(commonMain) - iosX64Main.dependsOn(this) - iosArm64Main.dependsOn(this) - iosSimulatorArm64Main.dependsOn(this) + + commonTest.dependencies { + implementation(kotlin("test")) } - val iosX64Test by getting - val iosArm64Test by getting - val iosSimulatorArm64Test by getting - val iosTest by creating { - dependsOn(commonTest) - iosX64Test.dependsOn(this) - iosArm64Test.dependsOn(this) - iosSimulatorArm64Test.dependsOn(this) + + androidMain.dependencies { + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1") } } } diff --git a/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts b/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts index 3e70dcaf..550994e5 100644 --- a/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts @@ -47,5 +47,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(false) + autoUploadProguardMapping.set(true) } diff --git a/sentry-samples/kmp-app-spm/shared/build.gradle.kts b/sentry-samples/kmp-app-spm/shared/build.gradle.kts index ccfd58e5..53b9aa00 100644 --- a/sentry-samples/kmp-app-spm/shared/build.gradle.kts +++ b/sentry-samples/kmp-app-spm/shared/build.gradle.kts @@ -4,7 +4,9 @@ plugins { } kotlin { - android() + applyDefaultHierarchyTemplate() + + androidTarget() jvm() listOf( iosX64(), @@ -19,35 +21,12 @@ kotlin { } sourceSets { - val commonMain by getting { - dependencies { - api(project(":sentry-kotlin-multiplatform")) - } - } - val commonTest by getting { - dependencies { - implementation(kotlin("test")) - } + commonMain.dependencies { + api(project(":sentry-kotlin-multiplatform")) } - val jvmMain by getting - val androidMain by getting - val iosX64Main by getting - val iosArm64Main by getting - val iosSimulatorArm64Main by getting - val iosMain by creating { - dependsOn(commonMain) - iosX64Main.dependsOn(this) - iosArm64Main.dependsOn(this) - iosSimulatorArm64Main.dependsOn(this) - } - val iosX64Test by getting - val iosArm64Test by getting - val iosSimulatorArm64Test by getting - val iosTest by creating { - dependsOn(commonTest) - iosX64Test.dependsOn(this) - iosArm64Test.dependsOn(this) - iosSimulatorArm64Test.dependsOn(this) + + commonTest.dependencies { + implementation(kotlin("test")) } } } From 43a27e55b2bb1ea65fe3aaac6eb3876e02a6a03f Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 13 Nov 2023 23:52:38 +0100 Subject: [PATCH 10/31] Add e2e test --- .../kotlin/multiplatform/SentryE2ETest.kt | 258 +++++++++--------- 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt index 859a60f5..517dd648 100644 --- a/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt +++ b/sentry-kotlin-multiplatform/src/commonTest/kotlin/io/sentry/kotlin/multiplatform/SentryE2ETest.kt @@ -1,129 +1,129 @@ -// package io.sentry.kotlin.multiplatform -// -// import io.ktor.client.HttpClient -// import io.ktor.client.request.get -// import io.ktor.client.request.headers -// import io.ktor.client.statement.bodyAsText -// import io.ktor.http.HttpHeaders -// import io.sentry.kotlin.multiplatform.utils.org -// import io.sentry.kotlin.multiplatform.utils.projectSlug -// import io.sentry.kotlin.multiplatform.utils.realDsn -// import kotlinx.coroutines.Dispatchers -// import kotlinx.coroutines.delay -// import kotlinx.coroutines.test.runTest -// import kotlinx.coroutines.withContext -// import kotlinx.serialization.Serializable -// import kotlinx.serialization.decodeFromString -// import kotlinx.serialization.json.Json -// import kotlin.test.AfterTest -// import kotlin.test.BeforeTest -// import kotlin.test.Test -// import kotlin.test.assertEquals -// import kotlin.test.assertFalse -// import kotlin.test.assertNotNull -// import kotlin.test.assertTrue -// import kotlin.time.Duration.Companion.seconds -// -// @Serializable -// private data class SentryEventSerializable( -// val id: String? = null, -// val project: Long? = null, -// val release: String? = null, -// val platform: String? = null, -// val message: String? = "", -// val tags: List> = listOf(), -// val fingerprint: List = listOf(), -// val level: String? = null, -// val logger: String? = null, -// val title: String? = null -// ) -// -// class SentryE2ETest : BaseSentryTest() { -// private val client = HttpClient() -// private val jsonDecoder = Json { ignoreUnknownKeys = true } -// private var sentEvent: SentryEvent? = null -// -// @BeforeTest -// fun setup() { -// assertNotNull(authToken) -// assertTrue(authToken.isNotEmpty()) -// sentryInit { options -> -// options.dsn = realDsn -// options.beforeSend = { event -> -// sentEvent = event -// event -// } -// } -// } -// -// private suspend fun fetchEvent(eventId: String): String { -// val url = -// "https://sentry.io/api/0/projects/$org/$projectSlug/events/$eventId/" -// val response = client.get(url) { -// headers { -// append( -// HttpHeaders.Authorization, -// "Bearer $authToken" -// ) -// } -// } -// return response.bodyAsText() -// } -// -// private suspend fun waitForEventRetrieval(eventId: String): SentryEventSerializable { -// var json = "" -// val result: SentryEventSerializable = withContext(Dispatchers.Default) { -// while (json.isEmpty() || json.contains("Event not found")) { -// delay(5000) -// json = fetchEvent(eventId) -// assertFalse(json.contains("Invalid token"), "Invalid auth token") -// } -// jsonDecoder.decodeFromString(json) -// } -// return result -// } -// -// // TODO: e2e tests are currently disabled for Apple targets as there are SSL issues that prevent sending events in tests -// // See: https://github.com/getsentry/sentry-kotlin-multiplatform/issues/17 -// -// @Test -// fun `capture message and fetch event from Sentry`() = runTest(timeout = 30.seconds) { -// if (platform != "Apple") { -// val message = "Test running on $platform" -// val eventId = Sentry.captureMessage(message) -// val fetchedEvent = waitForEventRetrieval(eventId.toString()) -// fetchedEvent.tags.forEach { println(it["value"]) } -// assertEquals(eventId.toString(), fetchedEvent.id) -// assertEquals(sentEvent?.message?.formatted, fetchedEvent.message) -// assertEquals(message, fetchedEvent.title) -// assertEquals(sentEvent?.release, fetchedEvent.release) -// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) -// assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) -// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.level?.name?.lowercase() }?.size) -// assertEquals(sentEvent?.logger, fetchedEvent.logger) -// } -// } -// -// @Test -// fun `capture exception and fetch event from Sentry`() = runTest(timeout = 30.seconds) { -// if (platform != "Apple") { -// val exceptionMessage = "Test exception on platform $platform" -// val eventId = -// Sentry.captureException(IllegalArgumentException(exceptionMessage)) -// val fetchedEvent = waitForEventRetrieval(eventId.toString()) -// assertEquals(eventId.toString(), fetchedEvent.id) -// assertEquals("IllegalArgumentException: $exceptionMessage", fetchedEvent.title) -// assertEquals(sentEvent?.release, fetchedEvent.release) -// assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) -// assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) -// assertEquals(2, fetchedEvent.tags.find { it["value"] == SentryLevel.ERROR.toString().lowercase() }?.size) -// assertEquals(sentEvent?.logger, fetchedEvent.logger) -// } -// } -// -// @AfterTest -// fun tearDown() { -// sentEvent = null -// Sentry.close() -// } -// } +package io.sentry.kotlin.multiplatform + +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.client.request.headers +import io.ktor.client.statement.bodyAsText +import io.ktor.http.HttpHeaders +import io.sentry.kotlin.multiplatform.utils.org +import io.sentry.kotlin.multiplatform.utils.projectSlug +import io.sentry.kotlin.multiplatform.utils.realDsn +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.time.Duration.Companion.seconds + +@Serializable +private data class SentryEventSerializable( + val id: String? = null, + val project: Long? = null, + val release: String? = null, + val platform: String? = null, + val message: String? = "", + val tags: List> = listOf(), + val fingerprint: List = listOf(), + val level: String? = null, + val logger: String? = null, + val title: String? = null +) + +class SentryE2ETest : BaseSentryTest() { + private val client = HttpClient() + private val jsonDecoder = Json { ignoreUnknownKeys = true } + private var sentEvent: SentryEvent? = null + + @BeforeTest + fun setup() { + assertNotNull(authToken) + assertTrue(authToken.isNotEmpty()) + sentryInit { options -> + options.dsn = realDsn + options.beforeSend = { event -> + sentEvent = event + event + } + } + } + + private suspend fun fetchEvent(eventId: String): String { + val url = + "https://sentry.io/api/0/projects/$org/$projectSlug/events/$eventId/" + val response = client.get(url) { + headers { + append( + HttpHeaders.Authorization, + "Bearer $authToken" + ) + } + } + return response.bodyAsText() + } + + private suspend fun waitForEventRetrieval(eventId: String): SentryEventSerializable { + var json = "" + val result: SentryEventSerializable = withContext(Dispatchers.Default) { + while (json.isEmpty() || json.contains("Event not found")) { + delay(5000) + json = fetchEvent(eventId) + assertFalse(json.contains("Invalid token"), "Invalid auth token") + } + jsonDecoder.decodeFromString(json) + } + return result + } + + // TODO: e2e tests are currently disabled for Apple targets as there are SSL issues that prevent sending events in tests + // See: https://github.com/getsentry/sentry-kotlin-multiplatform/issues/17 + + @Test + fun `capture message and fetch event from Sentry`() = runTest(timeout = 30.seconds) { + if (platform != "Apple") { + val message = "Test running on $platform" + val eventId = Sentry.captureMessage(message) + val fetchedEvent = waitForEventRetrieval(eventId.toString()) + fetchedEvent.tags.forEach { println(it["value"]) } + assertEquals(eventId.toString(), fetchedEvent.id) + assertEquals(sentEvent?.message?.formatted, fetchedEvent.message) + assertEquals(message, fetchedEvent.title) + assertEquals(sentEvent?.release, fetchedEvent.release) + assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) + assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) + assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.level?.name?.lowercase() }?.size) + assertEquals(sentEvent?.logger, fetchedEvent.logger) + } + } + + @Test + fun `capture exception and fetch event from Sentry`() = runTest(timeout = 30.seconds) { + if (platform != "Apple") { + val exceptionMessage = "Test exception on platform $platform" + val eventId = + Sentry.captureException(IllegalArgumentException(exceptionMessage)) + val fetchedEvent = waitForEventRetrieval(eventId.toString()) + assertEquals(eventId.toString(), fetchedEvent.id) + assertEquals("IllegalArgumentException: $exceptionMessage", fetchedEvent.title) + assertEquals(sentEvent?.release, fetchedEvent.release) + assertEquals(2, fetchedEvent.tags.find { it["value"] == sentEvent?.environment }?.size) + assertEquals(sentEvent?.fingerprint?.toList(), fetchedEvent.fingerprint) + assertEquals(2, fetchedEvent.tags.find { it["value"] == SentryLevel.ERROR.toString().lowercase() }?.size) + assertEquals(sentEvent?.logger, fetchedEvent.logger) + } + } + + @AfterTest + fun tearDown() { + sentEvent = null + Sentry.close() + } +} From 8610d838c0b0a1e2452bc694fb649db4d14f389e Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 13 Nov 2023 23:54:23 +0100 Subject: [PATCH 11/31] Add optin --- .../io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt index acb8c65e..05824b90 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt @@ -1,10 +1,11 @@ -@file:OptIn(ExperimentalForeignApi::class) +@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber actual class SentryLevelTestConverter actual constructor() { actual fun convert(sentryLevel: SentryLevel?): SentryLevel? { From 8d8cb705938a129b37745a2b756a3a3b35b407f7 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 13 Nov 2023 23:58:42 +0100 Subject: [PATCH 12/31] Disable automatic proguard upload --- sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts | 2 +- sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts | 2 +- sentry-samples/kmp-app-spm/androidApp/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts b/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts index 550994e5..3e70dcaf 100644 --- a/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-cocoapods/androidApp/build.gradle.kts @@ -47,5 +47,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(true) + autoUploadProguardMapping.set(false) } diff --git a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts index 262a30f7..0cf4ac08 100644 --- a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts @@ -73,5 +73,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(true) + autoUploadProguardMapping.set(false) } diff --git a/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts b/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts index 550994e5..3e70dcaf 100644 --- a/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-spm/androidApp/build.gradle.kts @@ -47,5 +47,5 @@ configurations { } sentry { - autoUploadProguardMapping.set(true) + autoUploadProguardMapping.set(false) } From 3f6b24aff95ada3e253ed56538bbedae10eebb31 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Tue, 14 Nov 2023 00:12:01 +0100 Subject: [PATCH 13/31] Increase jvm memory usage --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f6dccb9c..86a23332 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ jvm.version=1.8 versionName=0.3.0 # Increase memory for in-process compiler execution. -org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" +org.gradle.jvmargs=-Xmx6g # https://kotlinlang.org/docs/migrating-multiplatform-project-to-14.html#migrate-to-the-hierarchical-project-structure kotlin.mpp.enableCInteropCommonization=true From 664372f6ad34c27c0c31cb219251236683075868 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Tue, 14 Nov 2023 00:32:55 +0100 Subject: [PATCH 14/31] Update changelog --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 495d156f..09041c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Dependencies + +- Bump Kotlin version from v1.8.0 to v1.9.20 ([#146](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/146)) + - v1.9.20 is the first stable version of KMP + ## 0.3.0 ### Features @@ -9,8 +16,6 @@ ### Dependencies -- Bump Kotlin version from v1.8.0 to v1.9.20 ([#146](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/146)) - - v1.9.20 is the first stable version of KMP - Bump Java SDK from v6.14.0 to v6.32.0 ([#131](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/131)) - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#6320) - [diff](https://github.com/getsentry/sentry-java/compare/6.14.0...6.32.0) From cb533cd8c8ac2b318dc844e72eb98e14cd1ed8b2 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Wed, 15 Nov 2023 01:46:42 +0100 Subject: [PATCH 15/31] fix sample --- .run/iosApp-mvvm-di-spm.run.xml | 2 +- .../kmp-app-mvvm-di/shared/build.gradle.kts | 21 +++---------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.run/iosApp-mvvm-di-spm.run.xml b/.run/iosApp-mvvm-di-spm.run.xml index c449975c..764d689b 100644 --- a/.run/iosApp-mvvm-di-spm.run.xml +++ b/.run/iosApp-mvvm-di-spm.run.xml @@ -1,5 +1,5 @@ - + diff --git a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts index 2f233076..eb606bfb 100644 --- a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts @@ -22,8 +22,8 @@ kotlin { sourceSets { commonMain.dependencies { api(project(":sentry-kotlin-multiplatform")) - implementation("io.insert-koin:koin-core:3.4.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("io.insert-koin:koin-core:3.5.2-RC1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") } commonTest.dependencies { @@ -31,7 +31,7 @@ kotlin { } androidMain.dependencies { - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") } } } @@ -43,18 +43,3 @@ android { minSdk = Config.Android.minSdkVersion } } - -// Workaround for KotlinMetadata tasks failing when using ./gradlew build. -// However, running this sample on iOS and Android simulators remains unaffected. -afterEvaluate { - afterEvaluate { - tasks.configureEach { - if ( - name.startsWith("compile") && - name.endsWith("KotlinMetadata") - ) { - enabled = false - } - } - } -} From 17cd4cb5b28be355f9dcd6b154ae1a4cfeeeff51 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Wed, 15 Nov 2023 14:16:59 +0100 Subject: [PATCH 16/31] fix sample --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index e3398fd4..24324985 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ buildProject: # Build Apple Samples buildAppleSamples: + ./gradlew build -p sentry-samples cd ./sentry-samples/kmp-app-cocoapods/iosApp/iosApp && touch iosApp.xcconfig cd ./sentry-samples/kmp-app-spm/iosApp && touch iosApp.xcconfig cd ./sentry-samples/kmp-app-mvvm-di/iosApp && touch iosApp.xcconfig From 58c34d779d254486965a5dee9015659e9bee67b7 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Wed, 15 Nov 2023 14:17:31 +0100 Subject: [PATCH 17/31] use large macos image --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e7296d61..b9c63e33 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest] + os: [macos-latest-large] java: ["11"] steps: From c447976c342d31ad319c891d307ab6b03fa68c31 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Wed, 15 Nov 2023 16:19:49 +0100 Subject: [PATCH 18/31] Fix ci --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24324985..6409b50a 100644 --- a/Makefile +++ b/Makefile @@ -37,11 +37,11 @@ buildProject: # Build Apple Samples buildAppleSamples: - ./gradlew build -p sentry-samples cd ./sentry-samples/kmp-app-cocoapods/iosApp/iosApp && touch iosApp.xcconfig cd ./sentry-samples/kmp-app-spm/iosApp && touch iosApp.xcconfig cd ./sentry-samples/kmp-app-mvvm-di/iosApp && touch iosApp.xcconfig sudo xcode-select --switch /Applications/Xcode.app && /usr/bin/xcodebuild -version + ./gradlew ":sentry-samples:kmp-app-cocoapods:shared:podInstall" cd ./sentry-samples/kmp-app-cocoapods/iosApp; pod install xcodebuild -workspace ./sentry-samples/kmp-app-cocoapods/iosApp/iosApp.xcworkspace -scheme iosApp -configuration Debug -sdk iphonesimulator -arch arm64 xcodebuild -project ./sentry-samples/kmp-app-spm/iosApp.xcodeproj -scheme iosApp -configuration Debug -sdk iphonesimulator -arch arm64 From f8db364d312f4379029ec5644f1595bb910c171e Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Wed, 22 Nov 2023 17:28:44 +0100 Subject: [PATCH 19/31] Update optIn --- sentry-kotlin-multiplatform/build.gradle.kts | 8 ++++++++ .../io/sentry/kotlin/multiplatform/Attachment.apple.kt | 2 -- .../io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt | 3 --- .../kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt | 2 -- .../io/sentry/kotlin/multiplatform/SentryBridge.apple.kt | 4 ---- .../io/sentry/kotlin/multiplatform/SentryEvent.apple.kt | 4 ---- .../io/sentry/kotlin/multiplatform/TypeAliases.apple.kt | 4 ---- .../extensions/BreadcrumbExtensions.apple.kt | 4 ---- .../multiplatform/extensions/FoundationExtensions.kt | 4 ---- .../multiplatform/extensions/MessageExtensions.apple.kt | 3 --- .../extensions/SentryEventExtensions.apple.kt | 3 --- .../extensions/SentryExceptionExtensions.apple.kt | 3 --- .../extensions/SentryLevelExtensions.apple.kt | 4 ---- .../extensions/SentryOptionsExtensions.apple.kt | 4 ---- .../multiplatform/extensions/UserExtensions.apple.kt | 3 --- .../extensions/UserFeedbackExtensions.apple.kt | 3 --- .../kotlin/multiplatform/nsexception/NSException.kt | 4 ---- .../nsexception/SentryUnhandledExceptions.kt | 8 -------- .../sentry/kotlin/multiplatform/nsexception/Throwable.kt | 3 --- .../multiplatform/nsexception/UnhandledExceptionHook.kt | 2 -- .../kotlin/multiplatform/protocol/SentryId.apple.kt | 2 -- .../io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt | 3 --- .../sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt | 3 --- .../kotlin/multiplatform/BreadcrumbTestConverter.kt | 4 ---- .../io/sentry/kotlin/multiplatform/FoundationTest.kt | 3 --- .../kotlin/multiplatform/SentryEventConfigurator.kt | 3 --- .../io/sentry/kotlin/multiplatform/SentryExceptionTest.kt | 5 ----- .../kotlin/multiplatform/SentryLevelTestConverter.kt | 4 ---- .../multiplatform/nsexception/ThrowableCausesTests.kt | 3 --- .../kotlin/multiplatform/SentryInit.tvwatchmacos.kt | 3 --- .../io/sentry/kotlin/multiplatform/SentryInit.ios.kt | 2 -- .../extensions/SentryOptionsExtensions.ios.kt | 2 -- 32 files changed, 8 insertions(+), 104 deletions(-) diff --git a/sentry-kotlin-multiplatform/build.gradle.kts b/sentry-kotlin-multiplatform/build.gradle.kts index ef93744e..e939e81f 100644 --- a/sentry-kotlin-multiplatform/build.gradle.kts +++ b/sentry-kotlin-multiplatform/build.gradle.kts @@ -54,6 +54,14 @@ kotlin { macosArm64() sourceSets { + all { + languageSettings.apply { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + optIn("kotlinx.cinterop.UnsafeNumber") + optIn("kotlin.experimental.ExperimentalNativeApi") + } + } + commonMain.dependencies { implementation(Config.Libs.kotlinStd) } diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt index dea218c5..d69637cc 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/Attachment.apple.kt @@ -2,9 +2,7 @@ package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toByteArray import io.sentry.kotlin.multiplatform.extensions.toNSData -import kotlinx.cinterop.ExperimentalForeignApi -@OptIn(ExperimentalForeignApi::class) public actual class Attachment { internal lateinit var cocoaAttachment: CocoaAttachment diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt index 6eecfa37..f7906086 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/CocoaScopeProvider.kt @@ -8,11 +8,8 @@ import io.sentry.kotlin.multiplatform.extensions.toKmpUser import io.sentry.kotlin.multiplatform.extensions.toMutableMap import io.sentry.kotlin.multiplatform.protocol.Breadcrumb import io.sentry.kotlin.multiplatform.protocol.User -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import Scope.Sentry.SentryScope as PrivateCocoaScope -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal class CocoaScopeProvider(private val scope: CocoaScope) : Scope { /* diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt index de81a7b1..2f897b86 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryApple.kt @@ -2,10 +2,8 @@ package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentrySDK import io.sentry.kotlin.multiplatform.nsexception.setSentryUnhandledExceptionHook -import kotlinx.cinterop.ExperimentalForeignApi /** Convenience extension to setup unhandled exception hook */ -@OptIn(ExperimentalForeignApi::class) internal fun SentrySDK.Companion.start(configuration: (CocoaSentryOptions?) -> Unit) { this.startWithConfigureOptions(configuration) setSentryUnhandledExceptionHook() diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt index cad99df5..3a7cd87d 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryBridge.apple.kt @@ -9,7 +9,6 @@ import io.sentry.kotlin.multiplatform.protocol.Breadcrumb import io.sentry.kotlin.multiplatform.protocol.SentryId import io.sentry.kotlin.multiplatform.protocol.User import io.sentry.kotlin.multiplatform.protocol.UserFeedback -import kotlinx.cinterop.ExperimentalForeignApi import platform.Foundation.NSError import platform.Foundation.NSException @@ -17,7 +16,6 @@ public actual abstract class Context internal expect fun initSentry(configuration: OptionsConfiguration) -@OptIn(ExperimentalForeignApi::class) internal actual object SentryBridge { actual fun init(context: Context, configuration: OptionsConfiguration) { @@ -83,13 +81,11 @@ internal actual object SentryBridge { } } -@OptIn(ExperimentalForeignApi::class) @Suppress("unused") public fun Sentry.captureError(error: NSError) { SentrySDK.captureError(error) } -@OptIn(ExperimentalForeignApi::class) @Suppress("unused") public fun Sentry.captureException(exception: NSException) { SentrySDK.captureException(exception) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt index d57019ca..45c14ff9 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/SentryEvent.apple.kt @@ -1,5 +1,3 @@ -@file:OptIn(UnsafeNumber::class, ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb @@ -11,8 +9,6 @@ import io.sentry.kotlin.multiplatform.protocol.Message import io.sentry.kotlin.multiplatform.protocol.SentryException import io.sentry.kotlin.multiplatform.protocol.SentryId import io.sentry.kotlin.multiplatform.protocol.User -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber public actual class SentryEvent actual constructor() : SentryBaseEvent() { public actual var level: SentryLevel? = null diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt index c193edd1..a85825f9 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/TypeAliases.apple.kt @@ -1,5 +1,3 @@ -@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentryAttachment @@ -13,8 +11,6 @@ import cocoapods.Sentry.SentryOptions import cocoapods.Sentry.SentryScope import cocoapods.Sentry.SentryUser import cocoapods.Sentry.SentryUserFeedback -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber internal typealias CocoaUser = SentryUser internal typealias CocoaBreadcrumb = SentryBreadcrumb diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt index b7be6eac..385d2af4 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/BreadcrumbExtensions.apple.kt @@ -2,10 +2,7 @@ package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaBreadcrumb import io.sentry.kotlin.multiplatform.protocol.Breadcrumb -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun Breadcrumb.toCocoaBreadcrumb() = CocoaBreadcrumb().apply { val scope = this@toCocoaBreadcrumb setMessage(scope.message) @@ -15,7 +12,6 @@ internal fun Breadcrumb.toCocoaBreadcrumb() = CocoaBreadcrumb().apply { setData(scope.getData()?.toMap()) } -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun CocoaBreadcrumb.toKmpBreadcrumb() = Breadcrumb().apply { val scope = this@toKmpBreadcrumb message = scope.message diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt index 570fa621..8788c4b4 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/FoundationExtensions.kt @@ -1,7 +1,5 @@ package io.sentry.kotlin.multiplatform.extensions -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import kotlinx.cinterop.addressOf import kotlinx.cinterop.allocArrayOf import kotlinx.cinterop.convert @@ -22,14 +20,12 @@ internal fun NSMutableDictionary.toMutableMap(): MutableMap { return map } -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun NSData.toByteArray(): ByteArray = ByteArray(this@toByteArray.length.toInt()).apply { usePinned { memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length) } } -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun ByteArray.toNSData(): NSData = memScoped { NSData.create( bytes = allocArrayOf(this@toNSData), diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt index cba2989f..c605f902 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/MessageExtensions.apple.kt @@ -1,10 +1,7 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaMessage import io.sentry.kotlin.multiplatform.protocol.Message -import kotlinx.cinterop.ExperimentalForeignApi internal fun CocoaMessage.toKmpMessage() = Message( message = message, diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt index b85cad3c..73e6d8f3 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryEventExtensions.apple.kt @@ -3,10 +3,7 @@ package io.sentry.kotlin.multiplatform.extensions import cocoapods.Sentry.SentryId import io.sentry.kotlin.multiplatform.CocoaSentryEvent import io.sentry.kotlin.multiplatform.SentryEvent -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun CocoaSentryEvent.applyKmpEvent(kmpEvent: SentryEvent): CocoaSentryEvent { kmpEvent.level?.let { level = it.toCocoaSentryLevel() } kmpEvent.platform?.let { platform = it } diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt index bbd56984..d811f745 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryExceptionExtensions.apple.kt @@ -1,10 +1,7 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaSentryException import io.sentry.kotlin.multiplatform.protocol.SentryException -import kotlinx.cinterop.ExperimentalForeignApi internal fun CocoaSentryException.toKmpSentryException() = SentryException( type = type, diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt index 513ac21b..a6962949 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryLevelExtensions.apple.kt @@ -1,10 +1,6 @@ -@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.SentryLevel -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import kotlinx.cinterop.convert import cocoapods.Sentry.SentryLevel as CocoaSentryLevel diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt index a1352516..34063c1a 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.apple.kt @@ -8,13 +8,10 @@ import io.sentry.kotlin.multiplatform.CocoaSentryOptions import io.sentry.kotlin.multiplatform.SentryEvent import io.sentry.kotlin.multiplatform.SentryOptions import io.sentry.kotlin.multiplatform.nsexception.dropKotlinCrashEvent -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import kotlinx.cinterop.convert import platform.Foundation.NSNumber import NSException.Sentry.SentryEvent as NSExceptionSentryEvent -@OptIn(ExperimentalForeignApi::class) internal fun SentryOptions.toCocoaOptionsConfiguration(): (CocoaSentryOptions?) -> Unit = { it?.applyCocoaBaseOptions(this) } @@ -23,7 +20,6 @@ internal fun SentryOptions.toCocoaOptionsConfiguration(): (CocoaSentryOptions?) * Applies the given options to this CocoaSentryOptions. * This avoids code duplication for init on iOS. */ -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal fun CocoaSentryOptions.applyCocoaBaseOptions(options: SentryOptions) { dsn = options.dsn attachStacktrace = options.attachStackTrace diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt index 29a66990..b2af2f82 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserExtensions.apple.kt @@ -2,9 +2,7 @@ package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaUser import io.sentry.kotlin.multiplatform.protocol.User -import kotlinx.cinterop.ExperimentalForeignApi -@OptIn(ExperimentalForeignApi::class) internal fun User.toCocoaUser() = CocoaUser().apply { val scope = this@toCocoaUser userId = scope.id @@ -13,7 +11,6 @@ internal fun User.toCocoaUser() = CocoaUser().apply { ipAddress = scope.ipAddress } -@OptIn(ExperimentalForeignApi::class) internal fun CocoaUser.toKmpUser() = User().apply { val scope = this@toKmpUser id = scope.userId diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt index c187a3f3..41561b19 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/extensions/UserFeedbackExtensions.apple.kt @@ -1,11 +1,8 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaSentryId import io.sentry.kotlin.multiplatform.CocoaUserFeedback import io.sentry.kotlin.multiplatform.protocol.UserFeedback -import kotlinx.cinterop.ExperimentalForeignApi internal fun UserFeedback.toCocoaUserFeedback(): CocoaUserFeedback { val sentryId = CocoaSentryId(sentryId.toString()) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt index 629667ed..3ea684d8 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/NSException.kt @@ -12,12 +12,8 @@ // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform.nsexception -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import kotlinx.cinterop.convert import platform.Foundation.NSException import platform.Foundation.NSNumber diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt index 96268ea2..29bf096f 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/SentryUnhandledExceptions.kt @@ -34,15 +34,12 @@ import NSException.Sentry.kSentryLevelFatal import NSException.Sentry.prepareEvent import NSException.Sentry.storeEnvelope import NSException.Sentry.threadInspector -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import platform.Foundation.NSException import platform.Foundation.NSNumber /** * Drops the Kotlin crash that follows an unhandled Kotlin exception except our custom SentryEvent. */ -@OptIn(ExperimentalForeignApi::class) internal fun dropKotlinCrashEvent(event: SentryEvent?): SentryEvent? { return event?.takeUnless { it.isCrashEvent && (it.tags?.containsKey(KOTLIN_CRASH_TAG) ?: false) } } @@ -53,7 +50,6 @@ internal fun dropKotlinCrashEvent(event: SentryEvent?): SentryEvent? { * Note: once the exception is logged the program will be terminated. * @see wrapUnhandledExceptionHook */ -@OptIn(ExperimentalForeignApi::class) internal fun setSentryUnhandledExceptionHook(): Unit = wrapUnhandledExceptionHook { throwable -> val envelope = throwable.asSentryEnvelope() // The envelope will be persisted, so we can safely terminate afterwards. @@ -72,7 +68,6 @@ internal const val KOTLIN_CRASH_TAG = "nsexceptionkt.kotlin_crashed" /** * Converts `this` [Throwable] to a [SentryEnvelope]. */ -@OptIn(ExperimentalForeignApi::class) internal fun Throwable.asSentryEnvelope(): SentryEnvelope { val event = asSentryEvent() val preparedEvent = SentrySDK.currentHub().let { hub -> @@ -88,7 +83,6 @@ internal fun Throwable.asSentryEnvelope(): SentryEnvelope { * Converts `this` [Throwable] to a [SentryEvent]. */ @Suppress("UnnecessaryOptInAnnotation") -@OptIn(UnsafeNumber::class, ExperimentalForeignApi::class) private fun Throwable.asSentryEvent(): SentryEvent = SentryEvent(kSentryLevelFatal).apply { isCrashEvent = true @Suppress("UNCHECKED_CAST") @@ -111,7 +105,6 @@ private fun Throwable.asSentryEvent(): SentryEvent = SentryEvent(kSentryLevelFat /** * Converts `this` [NSException] to a [SentryException]. */ -@OptIn(ExperimentalForeignApi::class) private fun NSException.asSentryException( threadId: NSNumber? ): SentryException = SentryException(reason ?: "", name ?: "Throwable").apply { @@ -127,6 +120,5 @@ private fun NSException.asSentryException( } } -@OptIn(ExperimentalForeignApi::class) private val threadInspector: SentryThreadInspector? get() = SentrySDK.currentHub().getClient()?.threadInspector diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt index f708743a..8fec98f7 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/Throwable.kt @@ -14,8 +14,6 @@ package io.sentry.kotlin.multiplatform.nsexception -import kotlin.experimental.ExperimentalNativeApi - /** * Returns a list with all the [causes][Throwable.cause]. * The first element will be the cause, the second the cause of the cause, etc. @@ -37,7 +35,6 @@ internal val Throwable.causes: List get() = buildList { * @param commonAddresses a list of addresses used to drop the last common addresses. * @see getStackTraceAddresses */ -@OptIn(ExperimentalNativeApi::class) internal fun Throwable.getFilteredStackTraceAddresses( keepLastInit: Boolean = false, commonAddresses: List = emptyList() diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt index ee10fd28..8aaf5d35 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt @@ -14,7 +14,6 @@ package io.sentry.kotlin.multiplatform.nsexception -import kotlin.experimental.ExperimentalNativeApi import kotlin.native.concurrent.freeze /** @@ -24,7 +23,6 @@ import kotlin.native.concurrent.freeze * @see setUnhandledExceptionHook * @see terminateWithUnhandledException */ -@OptIn(ExperimentalNativeApi::class) internal fun wrapUnhandledExceptionHook(hook: (Throwable) -> Unit) { val prevHook = kotlin.concurrent.AtomicReference(null) val wrappedHook: ReportUnhandledExceptionHook = { diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt index 473c28cc..9f054bfe 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/protocol/SentryId.apple.kt @@ -1,9 +1,7 @@ package io.sentry.kotlin.multiplatform.protocol import io.sentry.kotlin.multiplatform.CocoaSentryId -import kotlinx.cinterop.ExperimentalForeignApi -@OptIn(ExperimentalForeignApi::class) public actual data class SentryId actual constructor(val sentryIdString: String) { public actual companion object { diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt index c493809a..bb9aac47 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BaseSentryScopeTest.kt @@ -1,8 +1,5 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform -import kotlinx.cinterop.ExperimentalForeignApi import cocoapods.Sentry.SentryScope as CocoaScope actual abstract class BaseSentryScopeTest { diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt index b93d0437..944d7514 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbConfigurator.kt @@ -1,11 +1,8 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions import io.sentry.kotlin.multiplatform.extensions.toKmpBreadcrumb import io.sentry.kotlin.multiplatform.protocol.Breadcrumb -import kotlinx.cinterop.ExperimentalForeignApi actual class BreadcrumbConfigurator { private val cocoaBreadcrumb = CocoaBreadcrumb() diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt index dea1b7df..906f89fd 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/BreadcrumbTestConverter.kt @@ -1,12 +1,8 @@ -@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toCocoaBreadcrumb import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel import io.sentry.kotlin.multiplatform.protocol.Breadcrumb -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber actual data class BreadcrumbTestConverter actual constructor(val breadcrumb: Breadcrumb) { diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt index 5f210f6a..1218677b 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/FoundationTest.kt @@ -1,10 +1,7 @@ -@file:OptIn(UnsafeNumber::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toByteArray import io.sentry.kotlin.multiplatform.extensions.toNSData -import kotlinx.cinterop.UnsafeNumber import platform.Foundation.NSNumber import platform.Foundation.NSString import platform.Foundation.NSUTF8StringEncoding diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt index 90be0f24..9577fd61 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryEventConfigurator.kt @@ -1,9 +1,6 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.applyCocoaBaseOptions -import kotlinx.cinterop.ExperimentalForeignApi actual class SentryEventConfigurator { private val cocoaSentryEvent = CocoaSentryEvent() diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt index 0601c8a4..fbcf2037 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryExceptionTest.kt @@ -1,14 +1,9 @@ -@file:OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toKmpSentryException import io.sentry.kotlin.multiplatform.protocol.SentryException -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber import kotlinx.cinterop.convert import platform.Foundation.NSNumber -import kotlin.experimental.ExperimentalNativeApi import kotlin.test.Test class SentryExceptionTest { diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt index 05824b90..10ffa121 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/SentryLevelTestConverter.kt @@ -1,11 +1,7 @@ -@file:OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - package io.sentry.kotlin.multiplatform import io.sentry.kotlin.multiplatform.extensions.toCocoaSentryLevel import io.sentry.kotlin.multiplatform.extensions.toKmpSentryLevel -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber actual class SentryLevelTestConverter actual constructor() { actual fun convert(sentryLevel: SentryLevel?): SentryLevel? { diff --git a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt index e46f5426..cce236bb 100644 --- a/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt +++ b/sentry-kotlin-multiplatform/src/appleTest/kotlin/io/sentry/kotlin/multiplatform/nsexception/ThrowableCausesTests.kt @@ -12,11 +12,8 @@ // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -@file:OptIn(ExperimentalNativeApi::class) - package io.sentry.kotlin.multiplatform.nsexception -import kotlin.experimental.ExperimentalNativeApi import kotlin.test.Test import kotlin.test.assertEquals diff --git a/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt b/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt index 8b5d32f4..2cd5ff69 100644 --- a/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt +++ b/sentry-kotlin-multiplatform/src/commonTvWatchMacOsMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.tvwatchmacos.kt @@ -1,10 +1,7 @@ -@file:OptIn(ExperimentalForeignApi::class) - package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentrySDK import io.sentry.kotlin.multiplatform.extensions.toCocoaOptionsConfiguration -import kotlinx.cinterop.ExperimentalForeignApi internal actual fun initSentry(configuration: OptionsConfiguration) { val options = SentryOptions() diff --git a/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt index f88965c1..e00d1b02 100644 --- a/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt +++ b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/SentryInit.ios.kt @@ -2,9 +2,7 @@ package io.sentry.kotlin.multiplatform import cocoapods.Sentry.SentrySDK import io.sentry.kotlin.multiplatform.extensions.toIosOptionsConfiguration -import kotlinx.cinterop.ExperimentalForeignApi -@OptIn(ExperimentalForeignApi::class) internal actual fun initSentry(configuration: OptionsConfiguration) { val options = SentryOptions() configuration.invoke(options) diff --git a/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt index 0ee67077..bb7638d1 100644 --- a/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt +++ b/sentry-kotlin-multiplatform/src/iosMain/kotlin/io/sentry/kotlin/multiplatform/extensions/SentryOptionsExtensions.ios.kt @@ -2,9 +2,7 @@ package io.sentry.kotlin.multiplatform.extensions import io.sentry.kotlin.multiplatform.CocoaSentryOptions import io.sentry.kotlin.multiplatform.SentryOptions -import kotlinx.cinterop.ExperimentalForeignApi -@OptIn(ExperimentalForeignApi::class) internal fun SentryOptions.toIosOptionsConfiguration(): (CocoaSentryOptions?) -> Unit = { // Apply base options available to all Cocoa/Apple targets it?.applyCocoaBaseOptions(this) From e283872860c62f15835c43e0d1a4d602469aed2a Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 24 Nov 2023 15:22:40 +0100 Subject: [PATCH 20/31] Update to 1.9.21 --- buildSrc/src/main/java/Config.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 62d509f2..019ec5c4 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,6 +1,6 @@ object Config { val agpVersion = "7.4.2" - val kotlinVersion = "1.9.20" + val kotlinVersion = "1.9.21" val composeVersion = "1.5.10" val gradleMavenPublishPluginVersion = "0.18.0" From 174e9edb0942c0411f2b6f839bbfc4af58136a41 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Fri, 24 Nov 2023 15:24:04 +0100 Subject: [PATCH 21/31] Update compose to 1.5.11 for samples --- buildSrc/src/main/java/Config.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 019ec5c4..e8aa4306 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -1,7 +1,7 @@ object Config { val agpVersion = "7.4.2" val kotlinVersion = "1.9.21" - val composeVersion = "1.5.10" + val composeVersion = "1.5.11" val gradleMavenPublishPluginVersion = "0.18.0" val multiplatform = "multiplatform" From d8e0a24502e742f714e1a9f8f0bd075908933e98 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 15:23:46 +0100 Subject: [PATCH 22/31] remove build.yml --- .github/workflows/build.yml | 62 ------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index b9c63e33..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: "Build" -on: - push: - branches: - - main - - release/** - pull_request: - -jobs: - build: - name: Build Job ${{ matrix.os }} - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - os: [macos-latest-large] - java: ["11"] - - steps: - - name: Git checkout - uses: actions/checkout@v3 - - - name: "Set up Java: ${{ matrix.java }}" - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: "adopt" - - - name: Cache Gradle packages - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - # Clean, build - - name: Make all - run: make all - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - - # We stop gradle at the end to make sure the cache folders - # don't contain any lock files and are free to be cached. - - name: Make stop - run: make stop - - - name: Archive packages - uses: actions/upload-artifact@v3 - with: - name: ${{ github.sha }} - if-no-files-found: error - path: | - ./*/build/distributions/*.zip - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - with: - name: sentry-kotlin-multiplatform From a37ab1f683b3690ab34cbff2b106fd16bdb15a06 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 16:24:43 +0100 Subject: [PATCH 23/31] Fix samples by updating koin --- buildSrc/src/main/java/Config.kt | 6 +++ sentry-samples/README.md | 2 +- .../androidApp/build.gradle.kts | 38 ++++++++++--------- .../sentry/kmp/demo/android/MainActivity.kt | 1 - .../kmp-app-mvvm-di/shared/build.gradle.kts | 2 +- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index e8aa4306..62b6a9cd 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -38,6 +38,12 @@ object Config { val sentryCocoaVersion = "8.4.0" val sentryCocoa = "Sentry" + + object Samples { + val koinVersion = "3.5.2-RC1" + val koinCore = "io.insert-koin:koin-core:$koinVersion" + val koinAndroid = "io.insert-koin:koin-android:$koinVersion" + } } object TestLibs { diff --git a/sentry-samples/README.md b/sentry-samples/README.md index 8b3a547d..53eef8e6 100644 --- a/sentry-samples/README.md +++ b/sentry-samples/README.md @@ -4,7 +4,7 @@ This contains three samples of Kotlin Multiplatform projects showcasing the Sentry Kotlin Multiplatform SDK usage. - Sample 1: Android, iOS with Cocoapods, Desktop with Jetpack Compose - Sample 2: Android, iOS with Swift Package Manager, Desktop with Jetpack Compose -- Sample 3: Android with Jetpack Compose, iOS with Jetpack Compose, MVVM and Dependency Injection with [Koin](https://insert-koin.io/) +- Sample 3: Android and iOS with Compose Multiplatform, MVVM and Dependency Injection with [Koin](https://insert-koin.io/) ## Getting Started > All samples are configured as sub-projects. You need to open the root project in Android Studio and sync the gradle files. diff --git a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts index 0cf4ac08..ca12999d 100644 --- a/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/androidApp/build.gradle.kts @@ -6,11 +6,11 @@ plugins { android { namespace = "sentry.kmp.demo.android" - compileSdk = 33 + compileSdk = 34 defaultConfig { applicationId = "sentry.kmp.demo" minSdk = 21 - targetSdk = 33 + targetSdk = 34 versionCode = 1 versionName = "1.0" } @@ -39,29 +39,33 @@ android { } kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true" + ) } composeOptions { - kotlinCompilerExtensionVersion = "1.5.4" + kotlinCompilerExtensionVersion = "1.5.5" } } dependencies { implementation(rootProject.project(":sentry-samples:kmp-app-mvvm-di:shared")) - implementation("androidx.core:core-ktx:1.10.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation(Config.Libs.Samples.koinAndroid) + implementation("androidx.core:core-ktx:1.12.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") implementation("androidx.appcompat:appcompat:1.6.1") - implementation("com.google.android.material:material:1.8.0") - implementation("androidx.activity:activity-compose:1.7.0") - implementation("androidx.lifecycle:lifecycle-runtime:2.6.1") - implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1") - implementation("androidx.navigation:navigation-compose:2.5.3") - implementation("androidx.navigation:navigation-runtime:2.5.3") - implementation("io.insert-koin:koin-android:3.4.0") - implementation("androidx.compose.compiler:compiler:1.5.4") - implementation("androidx.compose.ui:ui:1.5.0-alpha02") - implementation("androidx.compose.ui:ui-tooling:1.5.0-alpha02") - implementation("androidx.compose.foundation:foundation:1.5.0-alpha02") - implementation("androidx.compose.material:material:1.5.0-alpha02") + implementation("com.google.android.material:material:1.10.0") + implementation("androidx.activity:activity-compose:1.8.1") + implementation("androidx.lifecycle:lifecycle-runtime:2.6.2") + implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.2") + implementation("androidx.navigation:navigation-compose:2.7.5") + implementation("androidx.navigation:navigation-runtime:2.7.5") + implementation("androidx.compose.compiler:compiler:1.5.5") + implementation("androidx.compose.ui:ui:1.6.0-beta02") + implementation("androidx.compose.ui:ui-tooling:1.6.0-beta02") + implementation("androidx.compose.foundation:foundation:1.6.0-beta02") + implementation("androidx.compose.material:material:1.6.0-beta02") } // Prevent Sentry from being included in the Android app through the AGP. diff --git a/sentry-samples/kmp-app-mvvm-di/androidApp/src/main/kotlin/sentry/kmp/demo/android/MainActivity.kt b/sentry-samples/kmp-app-mvvm-di/androidApp/src/main/kotlin/sentry/kmp/demo/android/MainActivity.kt index d66aaab1..68ad571f 100644 --- a/sentry-samples/kmp-app-mvvm-di/androidApp/src/main/kotlin/sentry/kmp/demo/android/MainActivity.kt +++ b/sentry-samples/kmp-app-mvvm-di/androidApp/src/main/kotlin/sentry/kmp/demo/android/MainActivity.kt @@ -11,7 +11,6 @@ import sentry.kmp.demo.models.AuthenticationViewModel import sentry.kmp.demo.models.HomeViewModel class MainActivity : ComponentActivity(), KoinComponent { - private val authenticationViewModel: AuthenticationViewModel by viewModel() private val homeViewModel: HomeViewModel by viewModel() diff --git a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts index eb606bfb..9d5f59fb 100644 --- a/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts +++ b/sentry-samples/kmp-app-mvvm-di/shared/build.gradle.kts @@ -22,7 +22,7 @@ kotlin { sourceSets { commonMain.dependencies { api(project(":sentry-kotlin-multiplatform")) - implementation("io.insert-koin:koin-core:3.5.2-RC1") + implementation(Config.Libs.Samples.koinCore) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") } From aebc5c452890b5885261f777e858eb17a5f296c1 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 16:28:08 +0100 Subject: [PATCH 24/31] Remove dependencies changelog --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09041c40..cef7465f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,6 @@ - Add sample & trace rate configuration ([#144](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/144)) - Remove need for context in Sentry.init for Android ([#117](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/117)) -### Dependencies - -- Bump Java SDK from v6.14.0 to v6.32.0 ([#131](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/131)) - - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#6320) - - [diff](https://github.com/getsentry/sentry-java/compare/6.14.0...6.32.0) - ## 0.2.1 ### Fixes From f8b8272490c01fb3d1116f562aa8fc6772a4cf94 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 16:29:10 +0100 Subject: [PATCH 25/31] Update CHANGELOG --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef7465f..eeb0480f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,7 @@ ### Dependencies -- Bump Kotlin version from v1.8.0 to v1.9.20 ([#146](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/146)) - - v1.9.20 is the first stable version of KMP +- Bump Kotlin version from v1.8.0 to v1.9.21 ([#146](https://github.com/getsentry/sentry-kotlin-multiplatform/pull/146)) ## 0.3.0 From 65dbb4c6518dec53ee302246655b5bb1caf234e7 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 16:33:53 +0100 Subject: [PATCH 26/31] Update import --- .../kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt index 8aaf5d35..d27c1f09 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt @@ -15,6 +15,7 @@ package io.sentry.kotlin.multiplatform.nsexception import kotlin.native.concurrent.freeze +import kotlin.concurrent.AtomicReference /** * Wraps the unhandled exception hook such that the provided [hook] is invoked @@ -24,7 +25,7 @@ import kotlin.native.concurrent.freeze * @see terminateWithUnhandledException */ internal fun wrapUnhandledExceptionHook(hook: (Throwable) -> Unit) { - val prevHook = kotlin.concurrent.AtomicReference(null) + val prevHook = AtomicReference(null) val wrappedHook: ReportUnhandledExceptionHook = { hook(it) prevHook.value?.invoke(it) From f843f35b23e514493bf37c1e1e8421883823090d Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Mon, 4 Dec 2023 15:34:58 +0000 Subject: [PATCH 27/31] Format code --- .../kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt index d27c1f09..4ffa78b7 100644 --- a/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt +++ b/sentry-kotlin-multiplatform/src/appleMain/kotlin/io/sentry/kotlin/multiplatform/nsexception/UnhandledExceptionHook.kt @@ -14,8 +14,8 @@ package io.sentry.kotlin.multiplatform.nsexception -import kotlin.native.concurrent.freeze import kotlin.concurrent.AtomicReference +import kotlin.native.concurrent.freeze /** * Wraps the unhandled exception hook such that the provided [hook] is invoked From e9adcf48a75204a4c839049f2791671b3f5ab14c Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Mon, 4 Dec 2023 16:38:54 +0100 Subject: [PATCH 28/31] Update readme --- sentry-samples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-samples/README.md b/sentry-samples/README.md index 53eef8e6..396b3d20 100644 --- a/sentry-samples/README.md +++ b/sentry-samples/README.md @@ -4,7 +4,7 @@ This contains three samples of Kotlin Multiplatform projects showcasing the Sentry Kotlin Multiplatform SDK usage. - Sample 1: Android, iOS with Cocoapods, Desktop with Jetpack Compose - Sample 2: Android, iOS with Swift Package Manager, Desktop with Jetpack Compose -- Sample 3: Android and iOS with Compose Multiplatform, MVVM and Dependency Injection with [Koin](https://insert-koin.io/) +- Sample 3: Android with Jetpack Composem iOS with SwiftUI and MVVM and Dependency Injection with [Koin](https://insert-koin.io/) ## Getting Started > All samples are configured as sub-projects. You need to open the root project in Android Studio and sync the gradle files. From e8c0752c67cddbc737eacb9808cbe98e31133a5a Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 4 Dec 2023 16:49:31 +0100 Subject: [PATCH 29/31] Update sentry-samples/README.md Co-authored-by: Roman Zavarnitsyn --- sentry-samples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-samples/README.md b/sentry-samples/README.md index 396b3d20..0cc9b428 100644 --- a/sentry-samples/README.md +++ b/sentry-samples/README.md @@ -4,7 +4,7 @@ This contains three samples of Kotlin Multiplatform projects showcasing the Sentry Kotlin Multiplatform SDK usage. - Sample 1: Android, iOS with Cocoapods, Desktop with Jetpack Compose - Sample 2: Android, iOS with Swift Package Manager, Desktop with Jetpack Compose -- Sample 3: Android with Jetpack Composem iOS with SwiftUI and MVVM and Dependency Injection with [Koin](https://insert-koin.io/) +- Sample 3: Android with Jetpack Compose, iOS with SwiftUI and MVVM and Dependency Injection with [Koin](https://insert-koin.io/) ## Getting Started > All samples are configured as sub-projects. You need to open the root project in Android Studio and sync the gradle files. From f00e16595559d8bb7011eaafc94e793732177558 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Tue, 5 Dec 2023 16:36:36 +0100 Subject: [PATCH 30/31] Disable koin sample for now - add it back later when koin supports kotlin 1.9.21 --- settings.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 5001a80e..3e294e97 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,5 +46,6 @@ KMP App with MVVM and Dependency Injection with Koin: - Android with Jetpack Compose - iOS with SwiftUI and SPM */ -include("sentry-samples:kmp-app-mvvm-di:shared") -include("sentry-samples:kmp-app-mvvm-di:androidApp") +// This is currently disabled because Koin does not support Kotlin 1.9.21 yet +// include("sentry-samples:kmp-app-mvvm-di:shared") +// include("sentry-samples:kmp-app-mvvm-di:androidApp") From 59a952624902c9a4f16e6505946a05c5522344e9 Mon Sep 17 00:00:00 2001 From: GIancarlo Buenaflor Date: Tue, 5 Dec 2023 17:03:21 +0100 Subject: [PATCH 31/31] Disable for now --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5ac1c460..5e2de7be 100644 --- a/Makefile +++ b/Makefile @@ -39,12 +39,12 @@ buildProject: buildAppleSamples: ./gradlew build -p sentry-samples cd ./sentry-samples/kmp-app-cocoapods/iosApp/iosApp && touch iosApp.xcconfig - cd ./sentry-samples/kmp-app-mvvm-di/iosApp && touch iosApp.xcconfig + # cd ./sentry-samples/kmp-app-mvvm-di/iosApp && touch iosApp.xcconfig sudo xcode-select --switch /Applications/Xcode.app && /usr/bin/xcodebuild -version ./gradlew ":sentry-samples:kmp-app-cocoapods:shared:podInstall" cd ./sentry-samples/kmp-app-cocoapods/iosApp; pod install xcodebuild -workspace ./sentry-samples/kmp-app-cocoapods/iosApp/iosApp.xcworkspace -scheme iosApp -configuration Debug -sdk iphonesimulator -arch arm64 - xcodebuild -project ./sentry-samples/kmp-app-mvvm-di/iosApp.xcodeproj -scheme iosApp -configuration Debug -sdk iphonesimulator -arch arm64 + # xcodebuild -project ./sentry-samples/kmp-app-mvvm-di/iosApp.xcodeproj -scheme iosApp -configuration Debug -sdk iphonesimulator -arch arm64 # Build all targets, run tests and checks api