Hi there, my team has been working on a multiplatf...
# multiplatform
d
Hi there, my team has been working on a multiplatform app for around a year now. We've run into a bit of a limitation that we can't seem to overcome. Was wondering if someone might be able to point us in the right direction. We're using Firebase for our authentication layer (using the respective cocoapod and java packages for the iOS and JVM targets) and have an expect/actual in front of the SDK to provide a common interface between the platforms. Inside of the Firebase library for iOS there's a few places where an NSException can be raised and it doesn't seem like there's a way to "catch" that exception either in the iosMain code or propagate the error out to the Swift side of our codebase outside of our shared Kotlin framework. Are we missing something simple here or is there a gap in Kotlin Native where NSException can't be implicitly wrapped into a Kotlin exception type that can be caught and re-thrown as needed?
r
I'm not sure why you wouldn't be able to catch from the Kotlin side, but you can add a
@Throws
annotation to the relevant methods, and they'll be exported as
throws
so you can try/catch from Swift.
d
Yeah I tried that with
@Throws(Throwable::class)
but our app is crashing inside of the try/catch block. Seems like the NSException isn't being captured as an exception in Kotlin?
r
yeah, sounds like something isn't wired up right but I couldn't guess at what the issue is without being in the codebase
d
I'm currently trying to opt into foreign exceptions to see if that could solve this? Seems like there's a beta api that needs to be opted into for wrapping NSExceptions in a ForeignException object?
Copy code
extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
j
NSException
isn't possible to catch in Kotlin. It's also not possible in Swift.
NSError
can be propagated though.
NSError
is more commonly used for non-fatal errors in Objective-C, which can be handled in Kotlin.
d
Right I think the issue here though is that we're using an external SDK so I don't necessarily have control over whether the NSException is thrown. From the issue you posted it seems like these should still be propagated if marked with
@Throws
?
I can confirm that the following opt in works
Copy code
extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
This allows me to do the following in kotlin iosMain module:
Copy code
try {
  // some code that throws NSException
} catch (e: ForeignException) {
  // Catch!
}
👀 1
Seems like this is an api that's in Beta though. Not sure if it's just newer or if there's some known issues with it. Seems like it does exactly what I'm looking for
j
Annotating a Kotlin function with
@Throws
will create an Objective-C header with an
NSError
parameter. But you're working in the opposite direction, needing to handle an Objective-C error in Kotlin. The typical pattern for this is for the Objective-C code to similarly allow for passing an
NSError
reference to propagate any error with.
d
Yeah I can't change the objective-c code though as it's a library owned by Google: https://github.com/firebase/firebase-ios-sdk Ideally yeah that makes sense that NSError would be easier to work with, just in this circumstance I don't have that flexibility
j
That's great if the
objc-wrap
opt-in works around this for your use case here. It'd be good to communicate this on YouTrack so JetBrains is aware of your experience.
👍 1
Maybe Google wraps the Objective-C
NSException
throwing code to handle as
NSError
in Swift somehow. Otherwise this would similarly be an issue using the APIs from Swift.
Note that the opposite reversed translation is not implemented yet: Swift/Objective-C error-throwing methods aren't imported to Kotlin as exception-throwing.
To adapt Objective-C
NSError
producing code, for APIs that handle errors this way, I created this useful wrapper that converts
NSError
results into a Kotlin
Exception
and throws. Example usage.
👍 1
j
hey guys, where do I put the
extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
? if it's crashing from ios code directly, not from cocoapod 3rd party lib
d
@Jiri Bruchanov I put this into the build gradle for the shared module inside the pod definition. Here's an example from our codebase:
Copy code
pod("FirebaseAuth") {
    version = libs.versions.cocoapods.firebase.get()
    extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
}
🙌 1
j
@Deniz Tumer yeah that would work for your case... but I don't have any 3rd party cocoapod lib
d
Oh apologies yeah that is if the code breaks in external lib. If it's in code that you own I would probably use @Jeff Lockhart's suggestion above and replace usages of NSException with NSError
^ @Jiri Bruchanov
j
@Deniz Tumer Thanks, but I dont control the code. Its just regular ios api, not 3rd party lib.
d
Oh whoa yeah that's tough maybe there's a way to add something into the
iosMain
module to capture this? I'm not experienced enough with this yet to know where it goes. Are there compiler options we can use when setting up a kotlin source set?
j
I was wondering, if
objc_begin_catch
and
objc_end_catch
functions could be somehow useful, but I'm terrible with the cinterop, so not sure what, how to create argument for the begin_catch
1
blob shrug 1