2

I am learning KMM. I am now designing a common Location fetching in iOSMain and Android main

My problem is , I don't know to map Swift to Kotlin in iOSMain

For example,

The Swift code for , getting location is

var locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
var currentLoc: CLLocation!
if(CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways) {
   currentLoc = locationManager.location
   print(currentLoc.coordinate.latitude)
   print(currentLoc.coordinate.longitude)
} 

Kotlin side implementation:

kotlin

In the above code:

  1. How to use the Swift's .authorizedWhenInUse and .authorizedAlways in Kotlin Code ?

  2. And the in currentLoc.coordinate.longitude , the longitude and latitude is not resolving . Why ?

Please help me

RagAnt
  • 1,064
  • 2
  • 17
  • 35

1 Answers1

3

Mapping Swift (Objective-C) to Kotlin

  1. How to use the Swift's .authorizedWhenInUse and .authorizedAlways in Kotlin Code ?

According to Kotlin's documentation on interoperability, Kotlin/Native provides bidirectional interoperability with Objective-C, not Swift, so my first recommendation would be to reference Apple's Objective-C documentation over the Swift documentation.

If you pull up the Swift documentation for .authorizedWhenInUse, you'll see you can switch the language to Objective-C:

authorizedWhenInUse Swift reference documentation


Switch this to the Objective-C documentation to see how to reference this in Objective-C:

authorizedWhenInUse Objective-C reference documentation


Given this, you should be able to use kCLAuthorizationStatusAuthorizedWhenInUse in your Kotlin code.

Referencing iOS Frameworks

Since you already have some reference code, you could also simply Command+Click (or Command+B) one of the objects (for example, CLLocationManager) which should open up the compiled Kotlin code.

Manually you can also access all iOS frameworks from the "Project" View of Android Studio → "External Libraries" and then search for the iOS framework that you are searching for.

enter image description here

Here, you can dig through the frameworks to find what you're looking for. Not knowing the equivalent Objective-C API, you could just search for "authorizedWhenInUse" and can find it:

Kotlin CoreLocation framework reference code

Dealing with C-structs

  1. currentLoc.coordinate.longitude , the longitude and latitude is not resolving

This is more complicated...

The location property is of type CLLocationCoordinate2D and (the important part!) is that it is contained within a CValue:

@kotlinx.cinterop.ExternalObjCClass public open class CLLocation : platform.darwin.NSObject, platform.Foundation.NSCopyingProtocol, platform.Foundation.NSSecureCodingProtocol {

    ...

    public final val coordinate: kotlinx.cinterop.CValue<platform.CoreLocation.CLLocationCoordinate2D> /* compiled code */

Note that in Objective-C, CLLocationCoordinate2D is a C struct:

typedef struct CLLocationCoordinate2D {
    ...
} CLLocationCoordinate2D;

The Kotlin documentation here is thin, but it shows the methods available for CValue includes the .useContents() method.

CValue.useContents() method definition

Therefore, your code could be written as follows (compiled and confirmed that this runs and generates a location on a physical device):

val locationManager = CLLocationManager()

val currentLoc: CLLocation?
if (locationManager.authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse ||
    locationManager.authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
    currentLoc = locationManager.location

    currentLoc?.coordinate?.useContents {
        println("latitude = ${latitude}")
        println("longitude = ${longitude}")
    }
}

[Update September 2022] If you want to dig deeper, I also published a blog post on writing iOS-platform-dependent code using Kotlin with KMM's expect/actual: artandscienceofcoding.com/science/avoid-this-kmm-technique

Derek Lee
  • 3,452
  • 3
  • 30
  • 39
  • 1
    [Subjective Editorial] This kind of complexity is the reason why I (as an experienced iOS engineer) prefer to write native code in Swift and avoid writing "Kotlin-ified" Objective-C code in my KMM projects. – Derek Lee Aug 09 '22 at 17:16
  • Wow. Awesome answer that cleared my future doubts also. Thanks very much for detailed answer with images @DerekLee – RagAnt Aug 10 '22 at 06:48
  • 1
    My pleasure! I'll keep an eye out for any other KMM questions you may have. – Derek Lee Aug 10 '22 at 17:27
  • Do all 3rd Party iOS libraries and Frameworks (excluding Swift UI wrappers) exported to objc, so they are supported by gradle cocopods to use in iOSMain ? – RagAnt Aug 11 '22 at 15:01
  • 1
    @RagAnt, I'm not so sure I understand your question. From what I can see in Android Studio, iOS frameworks (that I assume are historically Objective-C) are exposed to Kotlin, as you can verify under External Libraries -> "Kotlin/Native 1.6.20 - Framework", e.g. CoreGraphics, HealthKit, MediaPlayer, UIKit, etc. Cocoapods is a separate tool for integrating 3rd-party open source frameworks, however, I do not use Cocoapods, so I'm sorry I cannot comment on how that integration works with Kotlin/Native. – Derek Lee Aug 11 '22 at 19:23
  • If you want to dig deeper, I also published a blog post on writing iOS-platform-dependent code using Kotlin with KMM's expect/actual: https://artandscienceofcoding.com/science/avoid-this-kmm-technique/ – Derek Lee Sep 22 '22 at 04:41
  • 1
    Wow. Great article. Waiting for part II (since already tried that approach in Swift and it's better). Thanks very much for remembering me and notifying me since my company asked me to conduct a class in KMM for the colleagues . Got some good source materials in right time via you . Thanks @DerekLee – RagAnt Sep 22 '22 at 05:24