J2ObjC and KMM

Skip to first unread message

Kiwi Wilkinson

May 5, 2023, 7:23:15 AM5/5/23
to j2objc-discuss
I've been using J2ObjC for years now for my Android/iOS app, and it's working really well. Thanks Tom!

I'm now dipping my toes into KMM, sharing Kotlin classes between Android Studio (on Windows) and XCode (on Mac). The Kotlin classes are converted to a Framework for XCode. That's working fine for standalone classes.

But I'm not sure whether the Kotlin classes can be accessed from the Java/J2ObjC code. As a transitionary approach, I'd like my Java/J2ObjC to be able to call methods on my Kotlin classes in the Framework.

Any pointers on doing this?

Tom Ball

May 5, 2023, 2:56:49 PM5/5/23
to j2objc-...@googlegroups.com
I'm not sure whether the Kotlin classes can be accessed from the Java/J2ObjC code.

Java -> Kotlin, I don't know, but you'll need to refer to the Kotlin docs. 

The good news is that since both j2objc and KMM generate normal Objective-C static libraries and frameworks, native Objective-C code in one can access APIs in the other. The KMM framework has (or should have) a Headers directory in it, with a <Framework-name>.h header file. So to access the framework from Objective-C, just #include that header and update your project so the compiler can find it. Since I know nothing about KMM, if you run into problems consult the KMM docs on accessing a framework.

On the Java side, you need to define native methods and implement them in Objective-C, either with embedded text or JNI. The advantage of embedding is it's easy for short functions and keeps both code sets next to each other; the disadvantage is that there's no IDE checking of that code, and if overused, is difficult to maintain. The advantage of JNI is that if the implementing functions can be written in C or C++, they can be shared with your Android app; the disadvantages with JNI are that it can be a lot of boilerplate and requires more build tweaking for those separate files.

This sounds like a lot of extra work, and if poorly designed, will be. The secret to success here is to keep the two code bases litely coupled, using as small a subset of the available APIs between them as possible. An example is how j2objc's java.util.regex.Pattern uses the ICU4C native library. The ICU API is *huge*, but all these JNI functions are doing is accessing the few necessary ICU functions to get the task done. The Pattern class doesn't know about ICU nor vice versa, and that's why we haven't touched these classes in years.

You received this message because you are subscribed to the Google Groups "j2objc-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to j2objc-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/j2objc-discuss/b31f2cc4-28a1-4288-9d8a-6e61553012cbn%40googlegroups.com.

Kiwi Wilkinson

May 8, 2023, 3:17:50 PM5/8/23
to j2objc-discuss
  Thanks Tom. You're comment about the framework header was enough for me to explore and work out how to do that. 

On iOS, before looking at Kotlin, I had Java/J2ObjC and Swift. Using embedding to allow the Java to call Swift, and using the bridging header to allow swift to call Java. Java Interface definitions, converted using J2Objc, are used to pass some data around

Now, I've added Kotlin, with the intention of moving gradually from J2ObjC to Kotlin. The compile sequence is Kotlin; J2ObjC; Swift. 

Using the framework header as you suggest, I can now call from Java/J2ObjC to Kotlin using ObjC embedding. My intention is to use manual dependency injection to allow Kotlin to call Java (and Swift). 

However, there's a problem. The interfaces/protocols would need to be defined in Kotlin, as it's compiled first. However the protocols are then not available to the Java, so it won't compile (they're in the .h file, which I understand Java can't import). So this might be a blocker.

If you have any suggestions regarding this then they'd be welcome.
Reply all
Reply to author
0 new messages