skip icon indicating copy to clipboard operation
skip copied to clipboard

Crash when calling a Closure vended from Kotlin from Swift

Open piercifani opened this issue 1 month ago • 4 comments

Given:

#if os(Android)
public typealias AsyncVoidCallback = () async -> ()
public typealias VoidCallback = () -> ()
public typealias StringCallback = (String) -> ()
#else
public typealias AsyncVoidCallback = @MainActor () async -> ()
public typealias VoidCallback = @MainActor () -> ()
public typealias StringCallback = @MainActor (String) -> ()
#endif

public struct Callbacks: @unchecked Sendable {
  
  // SKIP @nobridge
  public let didLogin: AsyncVoidCallback
  // SKIP @nobridge
  public let didCancel: AsyncVoidCallback
  // SKIP @nobridge
  public let didSelectEmail: VoidCallback
  // SKIP @nobridge
  public let didSelectSettings: VoidCallback

  public init(
    didLogin: @escaping AsyncVoidCallback = {},
    didCancel: @escaping AsyncVoidCallback = {},
    didSelectEmail: @escaping VoidCallback = {},
    didSelectSettings: @escaping VoidCallback = {},
  ) {
    self.didLogin = didLogin
    self.didCancel = didCancel
    self.didSelectEmail = didSelectEmail
    self.didSelectSettings = didSelectSettings
  }
}

And a class:

@MainActor
public class SomeViewModel {
  public static let shared = SomeViewModel()
  private var callbacks: Callbacks!
  public func setCallbacks(_ callbacks: Callbacks) {
    self.callbacks = callbacks
  }
  
  public func doSomeWOrk() async {
    try? await Task.sleep(for: .seconds(2))
    await callbacks.didLogin()
  }
}

When from Kotlin we call:

// Required to initialize SkipFoundation
skip.foundation.ProcessInfo.launch(this)
SomeViewModel.shared.setCallbacks(callbacks = Callbacks(didLogin = {
            print("")
        }, didCancel = {}, didSelectSettings = {}, didSelectEmail = {}))

lifecycleScope.launch {
  SomeViewModel.shared.doSomeWOrk()
}

It crashes with:

Abort message: 'JNI DETECTED ERROR IN APPLICATION: can't call java.lang.Object kotlin.jvm.functions.Function0.invoke() on instance of tools.skip.travelposters.MainActivity$onCreate$1
    in call to CallObjectMethodA
    from void android.os.MessageQueue.nativePollOnce(long, int)'
      #09 pc 000000000007ae38  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI12JConvertiblePA2A15JObjectProtocolRzrlE4call_2on7options4argsxAA12JavaMethodIDV_SvAA0C7OptionsVSaySo6jvalueVGtKFZSvSgSo18JNINativeInterfaceV_SpySPyARGSgGtXEfU_+268) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #10 pc 000000000007dd8c  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI12JConvertiblePA2A15JObjectProtocolRzrlE4call_2on7options4argsxAA12JavaMethodIDV_SvAA0C7OptionsVSaySo6jvalueVGtKFZSvSgSo18JNINativeInterfaceV_SpySPyARGSgGtXEfU_TA+28) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #11 pc 000000000008e47c  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI0B0C7withEnvyxxSo18JNINativeInterfaceV_SpySPyAFGSgGtKXEKlF+768) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #12 pc 000000000008e60c  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI0B0C15withEnvThrowing7options_xAA19JConvertibleOptionsV_xSo18JNINativeInterfaceV_SpySPyAIGSgGtKXEtKlF+152) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #13 pc 0000000000090074  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI12JConvertiblePA2A15JObjectProtocolRzrlE4call_2on7options4argsxAA12JavaMethodIDV_SvAA0C7OptionsVSaySo6jvalueVGtKFZ+400) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #14 pc 000000000007b440  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($sxSg8SwiftJNI12JConvertibleA2bCRzlAbCP4call_2on7options4argsxAB12JavaMethodIDV_SvAB0C7OptionsVSaySo6jvalueVGtKFZTW+20) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #15 pc 00000000000926a0  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI7JObjectC4call6method7options4argsxAA12JavaMethodIDV_AA19JConvertibleOptionsVSaySo6jvalueVGtKAA0K0RzlF+116) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #16 pc 00000000000a5aac  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2b00000) ($s10SkipBridge17JavaBackedClosureC6invokexyKFxyKXEfU_+156) (BuildId: bd2233d95e170dbb45695b64f069997bd23f0f89)
      #17 pc 00000000000a5b28  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2b00000) ($s10SkipBridge17JavaBackedClosureC6invokexyKFxyKXEfU_TA+16) (BuildId: bd2233d95e170dbb45695b64f069997bd23f0f89)
      #18 pc 000000000008d9cc  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2850000) ($s8SwiftJNI10jniContextyxxyKXEKlF+804) (BuildId: d35c9d2320980b483b6cd9299ec65ed1f9e58f2b)
      #19 pc 00000000000ae794  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2b00000) ($s10SkipBridge17JavaBackedClosureC6invokexyKF+80) (BuildId: bd2233d95e170dbb45695b64f069997bd23f0f89)
      #20 pc 00000000000a7790  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2b00000) ($s10SkipBridge13SwiftClosure0C7closure13forJavaObject7optionsxyYbcSgSvSg_0C3JNI19JConvertibleOptionsVtlFZxyYbcfU0_+48) (BuildId: bd2233d95e170dbb45695b64f069997bd23f0f89)
      #21 pc 0000000000059cd4  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x34a0000) ($sytIeghr_Iegh_TR+16) (BuildId: 75548efcc20702dba61d94d01f72a0b64b6f5c90)
      #22 pc 0000000000059cfc  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x34a0000) ($sIegh_IegH_TR+24) (BuildId: 75548efcc20702dba61d94d01f72a0b64b6f5c90)
      #23 pc 00000000000957e0  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libswift_Concurrency.so (offset 0x2994000) (swift::runJobInEstablishedExecutorContext(swift::Job*)+384) (BuildId: 2d101391dcbcc79589bd34cf02e0e8a5beee6542)
      #24 pc 00000000000964ec  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libswift_Concurrency.so (offset 0x2994000) (swift_job_run+160) (BuildId: 2d101391dcbcc79589bd34cf02e0e8a5beee6542)
      #25 pc 000000000003e844  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libdispatch.so (offset 0x2f34000) (_dispatch_main_queue_callback_4CF+500) (BuildId: 4d2f67b08e52299f862d8f694d06077377cc0d34)
      #26 pc 000000000044f444  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libFoundation.so (offset 0x1fa4000) (__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__+12) (BuildId: 617fc1e0282c6605ede0a59aaac99d5e571ff611)
      #27 pc 000000000044b4c8  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libFoundation.so (offset 0x1fa4000) (__CFRunLoopRun+1544) (BuildId: 617fc1e0282c6605ede0a59aaac99d5e571ff611)
      #28 pc 000000000044ac48  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk!libFoundation.so (offset 0x1fa4000) (CFRunLoopRunSpecific+448) (BuildId: 617fc1e0282c6605ede0a59aaac99d5e571ff611)
      #29 pc 00000000001759b4  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2f9c000) ($s13AndroidLooper0A9MainActorC21installGlobalExecutor012_6DC549295C4I19CDA0E56858B8A0F7E72LLSbyFZs5Int32VAG_AGSvSgtcfU_+76) (BuildId: 298d293372485272a8dd7ce43c12abcd3edc43a0)
      #30 pc 0000000000175a94  /data/app/~~UhxnI5pQuVsXyl117OYWhQ==/tools.skip.travelposters-VUoCFakth33ZDPYm5ZlZAA==/base.apk (offset 0x2f9c000) ($s13AndroidLooper0A9MainActorC21installGlobalExecutor012_6DC549295C4I19CDA0E56858B8A0F7E72LLSbyFZs5Int32VAG_AGSvSgtcfU_To+8) (BuildId: 298d293372485272a8dd7ce43c12abcd3edc43a0)
---------------------------- PROCESS ENDED (5528) for package tools.skip.travelposters ----------------------------

Find the attached project to repro: closure-crash.zip

piercifani avatar Nov 10 '25 15:11 piercifani

This feature currently blocks certain functionalities from being developed.

piercifani avatar Nov 10 '25 17:11 piercifani

This will be fixed in the next version of Skip. You won't need to special-case Android, and you'll be able to specify:

public typealias AsyncVoidCallback = @MainActor () async -> ()

marcprux avatar Nov 11 '25 21:11 marcprux

We've fixed this in Skip 1.6.29. Please try with that version and if the issue persists, update/reopen this issue.

marcprux avatar Nov 11 '25 23:11 marcprux

Unfortunately it's still happening:

java_vm_ext.cc:616] JNI DETECTED ERROR IN APPLICATION: can't call java.lang.Object kotlin.jvm.functions.Function0.invoke() on instance of com.polymarket.android.ui.activities.account.states.WelcomeScreenKt$WelcomeScreen$viewModel$1$1

piercifani avatar Nov 12 '25 15:11 piercifani