https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
p

Piasy

12/10/2019, 4:27 AM
Hello guys, I have a question: I want to compile my commonMain and iosMain kotlin code into a static library, I achieve this target with gradle plugin, but my problem is, I don't know how to implement an abstract kotlin class in Objective-C and pass it to kotlin, because when I compile kotlin code to static library, all stuff are C struct. Here is my kotlin abstract class:
Copy code
abstract class ConfEvents {
  open fun onPeerJoined(uid: String) {}
}
Here is the generated C header:
Copy code
struct {
  libAvConf_KType* (*_type)(void);
  libAvConf_kref_com_piasy_avconf_ConfEvents (*ConfEvents)();
  void (*onPeerJoined)(libAvConf_kref_com_piasy_avconf_ConfEvents thiz, const char* uid);     
} ConfEvents;
If I compile kotlin code into framework, then
ConfEvents
would have a Objective-C interface, then I can extend it and pass it to kotlin.
c

Cristián Arenas

12/10/2019, 6:59 PM
What I’m doing right now is building a wrapper around the C API
so it woud have a private property of type
libAvConf_kref_com_piasy_avconf_ConfEvents
, which it would get by calling
privateInstance = ConfEvents.ConfEvents()
on the wrapper’s constructor, and then I would reimplement every method, like
-(void)onPeerJoined(const char* uid)
and it would call the correct one inside
ConfEvents.onPeerJoined(privateInstance, uid)
horrible, but I don’t know a better way
I don’t know why it exports it as C instead of Objective-C
p

Piasy

12/11/2019, 2:49 AM
@Cristián Arenas Thanks for your reply, but I may not explain myself clearly, what I want to do is create a sub class of the kotlin
ConfEvents
class in Objective-C, and its method will be called at kotlin code, and I need pass that Objective-C object to a kotlin method which receive a
ConfEvents
object. That kotlin method is:
Copy code
fun create(
      uid: String,
      events: ConfEvents
    ): AvConf
And the generated C API is:
Copy code
libAvConf_kref_com_piasy_avconf_AvConf (*create)(libAvConf_kref_com_piasy_avconf_AvConf_Companion thiz, const char* uid,  libAvConf_kref_com_piasy_avconf_ConfEvents events);
In your description, it seems to wrap a kotlin object with an Objective-C object, and use it in Objective-C, am I right?
c

Cristián Arenas

12/11/2019, 12:56 PM
In your description, it seems to wrap a kotlin object with an Objective-C object, and use it in Objective-C, am I right?
Yes, that’s the idea. I do not yet know how to create an Objective-C header when creating a static library, so wrapping the C API in an Objective-C class would solve some of your problems. After wrapping all the methods, you can subclass that class in Objective-C, the only difference would be that if any function requires a pointer to the original
ConfEvents
class, you would have to pass it the inner private instance (of type
libAvConf_kref_com_piasy_avconf_ConfEvents
). The better solution would be to ask how to generate the static library with an Objective-C API, I have no idea how to do that
p

Piasy

12/11/2019, 1:01 PM
Sorry I still have doubt about your suggestion: if the
onPeerJoined
function of
ConfEvents
is called in kotlin code, how could the Objective-C code be called?
c

Cristián Arenas

12/11/2019, 1:02 PM
I’m not sure what you mean
p

Piasy

12/11/2019, 1:10 PM
Okay, let me explain it.
so wrapping the C API in an Objective-C class
You mean I can create an Objective-C class, e.g.
ObjCConfEvents
, it will own a pointer of
libAvConf_kref_com_piasy_avconf_ConfEvents
, and its
onPeerJoined
method will call
void (*onPeerJoined)(libAvConf_kref_com_piasy_avconf_ConfEvents thiz, const char* uid);
, then I can create subclass of
ObjCConfEvents
, e.g.
SpecialConfEvents
, and doing the real logic in its
onPeerJoined
method, right?
the only difference would be that if any function requires a pointer to the original
ConfEvents
class, you would have to pass it the inner private instance (of type
libAvConf_kref_com_piasy_avconf_ConfEvents
)
You mean I need pass the
libAvConf_kref_com_piasy_avconf_ConfEvents
of
ObjCConfEvents
to kotlin code (the
create
function), right? If my understanding is correct, when kotlin code call
onPeerJoined
of
libAvConf_kref_com_piasy_avconf_ConfEvents
, how could the
ObjCConfEvents
get called? Sorry if my understanding is wrong, and please correct me if so. Thank you very much!
c

Cristián Arenas

12/11/2019, 1:13 PM
ah
I get your problem now
what I describe solves the “call kotlin code from obj-c” problem
but you want to “call obj-c code from kotlin”
p

Piasy

12/11/2019, 1:14 PM
yeah I understand that
c

Cristián Arenas

12/11/2019, 1:15 PM
I would think that that is not possible using subclasses
I would personally go with closures/blocks to do that
but maybe it does work if you can generate an Objective-C static library
but this wrapper idea breaks communication in the other direction
p

Piasy

12/11/2019, 1:18 PM
okay, if so, then that's bad 😞 but fortunately we can compile kotlin code as framework, although the naming is out of our control, but we can create another wrapper framework over it.
c

Cristián Arenas

12/11/2019, 1:19 PM
I’m in the same boat as you
❤️ 1
also, I haven’t been able to make static libraries with bitcode
p

Piasy

12/11/2019, 1:21 PM
yeah, the gradle plugin doesn't have bitcode option when compiling static lib
c

Cristián Arenas

12/11/2019, 1:22 PM
that means I have to disable bitcode in the iOS app, which is not an option for me (used by external clients), so I can only make frameworks
I’ve been trying the umbrella framework approach
and it turns out that Apple explicitly tells you in the documentation that you should avoid them
and Xcode does not support them, so they don’t get codesigned and the apps don’t compile
p

Piasy

12/11/2019, 1:24 PM
I haven't use umbrella framework before, I haven't even hard about it, lol
c

Cristián Arenas

12/11/2019, 1:25 PM
umbrella framework = framework with frameworks inside, it’s what you suggested
Apple docs: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/CreationGuidelines.html
Don’t Create Umbrella Frameworks
While it is possible to create umbrella frameworks using Xcode, doing so is unnecessary for most developers and is not recommended. Apple uses umbrella frameworks to mask some of the interdependencies between libraries in the operating system. In nearly all cases, you should be able to include your code in a single, standard framework bundle. Alternatively, if your code was sufficiently modular, you could create multiple frameworks, but in that case, the dependencies between modules would be minimal or nonexistent and should not warrant the creation of an umbrella for them.
p

Piasy

12/11/2019, 1:26 PM
oh, I didn't mean that, by saying wrapper framework, I mean another separate framework, which just contains classes that wrap API of the original framework's classes.
c

Cristián Arenas

12/11/2019, 1:27 PM
so you would need to install both on the iOS app?
p

Piasy

12/11/2019, 1:28 PM
yes, not perfect, but it works
I mean, the app project need depend on both of them.
c

Cristián Arenas

12/11/2019, 1:29 PM
well, if you go the wrapping framework route as I did: The way to fix this codesigning problem, is to add a Run Script build phase, where you can use the
codesign
command line tool.
Copy code
f="$CODESIGNING_FOLDER_PATH/Frameworks/YourOuterFrameworkName.framework/Frameworks/YourInnerFrameworkName.framework"

codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY_NAME" --preserve-metadata=identifier,entitlements --timestamp=none "$f"
That way the app project only needs to depend on the outer one
p

Piasy

12/11/2019, 1:31 PM
great! thanks for sharing
c

Cristián Arenas

12/11/2019, 1:31 PM
just in case you ever try that
I would’ve killed for someone to tell me all of this 3 weeks ago
p

Piasy

12/11/2019, 1:32 PM
😂
c

Cristián Arenas

12/11/2019, 1:32 PM
and if someone had said this 2 months ago, I would’ve never chosen kotlin as a way to share code
it’s been probably harder than maintaining 2 codebases 😅
p

Piasy

12/11/2019, 1:33 PM
long way to go for kotlin mpp
1
c

Cristián Arenas

12/11/2019, 1:35 PM
If you figure anything else out, please share it with me 🙏
p

Piasy

12/11/2019, 1:38 PM
Sure I will
a

Artyom Degtyarev [JB]

12/12/2019, 8:37 AM
Just a word on static libs with bitcode - please try this approach(https://kotlinlang.slack.com/archives/C3SGXARS6/p1575971172220200?thread_ts=1575913985.211900&cid=C3SGXARS6), and tell if this is not working.
3 Views