iOS App with Kotlin/Native: Getting Started

In this tutorial, you’ll build an iOS app using Kotlin/Native. You’ll also take a look at the AppCode IDE from JetBrains! By Eric Crawford.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Adding a MKMapView to the Storyboard

First you’ll add a MKMapview component to the storyboard. This will show the locations of the Meteorites. Open Main.storyboard and delete the label hello.

Note: You may or may not have heard of a storyboard when it comes to iOS development. If you haven’t, just think of it as a file used to visually create your app’s layout.

Note: You may or may not have heard of a storyboard when it comes to iOS development. If you haven’t, just think of it as a file used to visually create your app’s layout.

In the Xcode toolbar, click on the Library button. When a pop-up appears, search for Map Kit View (which corresponds to MKMapView) like below:

Xcode Objects Library

Next, drag the Map Kit View to the phone scene where you just deleted the label. Then, drag the edges of the Map Kit View to take up the full screen.

In order to show the map correctly on different device screen sizes, you’ll need to adjust the constraints. Since you only have one view to worry about, Xcode will set the constraints for you.

Select the MKMapview component you added. Then, click on the Resolve Auto Layout Issues button on the Xcode bottom toolbar. After that, select Add Missing Constraints.

Fix missing constraints

Now that the Map Kit View scene has been set in the storyboard with some constraints, you’ll next add a ViewController.

Creating the ViewController

ViewControllers are the heart of most iOS apps. They are similar to Activities on Android.

You are going to create a ViewController in Kotlin. Since Xcode does not understand Kotlin source code, you will have to create an empty file for your ViewController.

Right-click on the kotlin folder and select New File…. In the template window, scroll down to Other section and select Empty and click Next. Name the file MeteoriteMapViewController.kt, then click Create.

Fix missing constraints

Add the following code to the new file:

// 1
import kotlinx.cinterop.ExportObjCClass
import kotlinx.cinterop.ObjCObjectBase.OverrideInit
import kotlinx.cinterop.ObjCOutlet
import platform.Foundation.*
import platform.UIKit.*
import platform.MapKit.*

// 2
@ExportObjCClass
class MeteoriteMapViewController : UIViewController, MKMapViewDelegateProtocol {

  // 3
  @OverrideInit
  constructor(coder: NSCoder) : super(coder)
    
  // 4
  override fun viewDidLoad() {
      super.viewDidLoad()
  }
}

Here is what you added:

  1. Imports for Kotlin to interop with Objective-C and some of the Cocoa Touch frameworks.
  2. The class inherits from UIVIewController and conforms to MKMapViewDelegateProtocol. The @ExportObjCClass annotation helps Kotlin create a class that is visible for lookup at runtime.
  3. Overrides the UIViewController initializer with a Kotlin constructor.
  4. Overrides the viewDidLoad() method.

Hold on a second! Something is missing, here. Where is the syntax highlighting and code completions?

Sad face

Luckily, the creators of Kotlin can help you out here via the AppCode IDE.

Using AppCode for Kotlin/Native

AppCode is JetBrains dedicated iOS development IDE. It supports Objective-C, Swift and our friend Kotlin (with a plugin). Head over to the AppCode download site to download and install the latest stable version.

Note: Unfortunately AppCode is not free. There is a 30-day trial of the production version.

Note: Unfortunately AppCode is not free. There is a 30-day trial of the production version.

With AppCode installed, you need to install the Kotlin/Native IDE plugin. Open AppCode, then click Configure ▸ Plugins to show the plugins window.

AppCode plugin from home screen

Now, click on Install JetBrains plugin and then search for kotlin native. The results should include the Kotlin/Native for AppCode plugin:

Kotlin Native Plugin

Go ahead and click Install to install the plugin, and when it’s done installing, restart AppCode. Once restarted, select Open Project and navigate to the root folder of your MeteoriteFinder project (the one that contains the MeteoriteFinder.xcodeproj file) and click Open. Once the project is open, you can expand the folder structure and explore the layout. If you already use Android Studio or IntelliJ IDEA, AppCode will look very familiar.

Fleshing out the ViewController

With AppCode open and ready, it’s time to get back to the project. Double-click on MeteoriteMapViewController.kt and bask in the syntax highlighting provided by the Kotlin/Native plugin and all its glory.

Note: At this point, you may see red underlining under super(coder). This is a false positive, and you may see more through out this tutorial. The Kotlin/Native plugin is in active development and is still in beta. Valid errors will be caught by the compiler when you build/run the project. Also, full syntax highlighting may not show up immediately, but instead only after a short time, once AppCode has fully integrated the Kotlin/Native plugin. The syntax highlighting may also intermittantly not show up fully, due to the beta nature of the plugin.

Note: At this point, you may see red underlining under super(coder). This is a false positive, and you may see more through out this tutorial. The Kotlin/Native plugin is in active development and is still in beta. Valid errors will be caught by the compiler when you build/run the project. Also, full syntax highlighting may not show up immediately, but instead only after a short time, once AppCode has fully integrated the Kotlin/Native plugin. The syntax highlighting may also intermittantly not show up fully, due to the beta nature of the plugin.

Under the constructor, add the following:

@ObjCOutlet
lateinit var mapView: MKMapView

The @ObjCOutlet annotation sets the mapView property as an outlet. This allows you to link the MKMapview from the storyboard to this property. The mapView property will be initialized at a later time than the ViewController is created, so you use the lateinit keyword.

In the viewDidLoad() method, add the following under super.viewDidLoad():

// 1
val center = CLLocationCoordinate2DMake(38.8935754, -77.0847873)
val span = MKCoordinateSpanMake(0.7, 0.7)
val region = MKCoordinateRegionMake(center, span)

// 2
with(mapView){
  delegate = this@MeteoriteMapViewController
  setRegion(region, true)
}

Going through this, step by step:

  1. Create center, span and region properties that will be used to position the viewable area of mapView.
  2. Use the Kotlin standard library with function, to scope and setup a couple of the mapView properties. Inside the scope, you set the mapView delegate equal to this MeteoriteMapViewController and set the region of the mapView.

CLLocationCoordinate2DMake is from a different module, and you will need to import from the CoreLocation module to make the compiler happy. You can write the import at the top of the file:

import platform.CoreLocation.CLLocationCoordinate2DMake

Or instead you can let the IDE add the import for you by setting your cursor on CLLocationCoordinate2DMake and hitting option+return at the same time on your keyboard.

Since MeteoriteMapViewController conforms to MKMapViewDelegateProtocol, setting the mapView delegate to this class allows MeteoriteMapViewController to receive callback events from mapView.

To conform to the protocol, first implement the method mapViewDidFailLoadingMap(), just in case the map fails to load. Add the following under the viewDidLoad() method:

override fun mapViewDidFailLoadingMap(mapView: MKMapView, withError: NSError) {
  NSLog("Error loading map: $withError")
}

Next, you’ll create a method that will insert mock data to be displayed on the map. Add the following method call to the end of viewDidLoad():

createAnnotation()

The method call should display red because it isn’t declared yet. Time to do so! Select the method, then press option+return at the same time. In the context menu, select Create function ‘createAnnotation’.

create function

Inside the new createAnnotation() method, delete the TODO template code and add the following:

// 1
val annotation = MKPointAnnotation().apply {
  setCoordinate(CLLocationCoordinate2DMake(38.8935754, -77.0847873))
  setTitle("My mock meteorite")
  setSubtitle("I'm falling........")
}
        
// 2
mapView.addAnnotation(annotation)

In the above, you:

  1. Create an MKPointAnnotation that will represent a pin on the map. For now, you set up some mock data.
  2. Add the annotation variable to the mapView. This will add a mock data pin on the map.

At this point, you’ve created a ViewController that will display a single pin on a map.

ViewController checkpoint

Build the project to make sure no errors are showing, by selecting Run from the toolbar and then Build.

AppCode Build

The first build in AppCode may take a little time to complete.