قالب وردپرس درنا توس
Home / Apple / IOS App with Kotlin / Native: Get started

IOS App with Kotlin / Native: Get started



Kotlin has seen huge growth on Java Virtual Machine (JVM). Having about 100% interoperability with Java allows developers to work without giving up the rich ecosystem for libraries and tools. But Java developers are not the only ones who can benefit from the language; Kotlin has spread his tentacles outside JVM with two other variations:

  1. Kotlin / JS for JavaScript Development.
  2. Kotlin / Native for C and iOS Development.

Kotlin / Native comes with a friendly API for the iOS platform, enabling developers to call quite a bit of the Cocoa Touch framework. This means that Kotlin developers can transfer their development skills to create iOS apps (assuming you have an additional MacOS device located).

In this tutorial you will build a map based iOS app showing where meteorites have fallen to earth. The whole app will focus on using Kotlin / Native . We keep the references of iOS classes and frames easy in this tutorial, giving you just a taste of the possibilities without overwhelming you if you've never developed for iOS.

Note : This tutorial assumes that you are already familiar with the basics of Kotlin programming. If you are new to Kotlin, check out our Kotlin For Android training. If you're new to Android development, check out our introductory Android tutorials first. If you're ready to learn iOS development, check out our way to learn the iOS guide on the site.

Getting Started

Prerequisites : This tutorial uses Kotlin / Native 0.9.3, Kotlin 1

.3.0, Xcode 10.0 (CLI) and iOS 12.0. The available versions may be higher as you read this guide.

As a first step, download the materials for this tutorial by clicking the Download Materials button at the top or bottom of the page. After downloading the materials, open the startup project in Xcode by double clicking the MeteoriteFinder.xcodeproj file and then running the app by clicking the triangle button shown below:

Since this is the first time running the app, Kotlin / Native compiler, named Konan will download itself. Depending on your network speed, this may take 5-20 minutes or so. Subsequent building of the app will be much faster. Once the download is complete and the building is completed, Xcode will start the simulator and you will be greeted by a basic Hello screen.

Nice! You have just run your first iOS app from Kotlin, without any Objective-C or Swift source code in this project.

Now that you have the Project running, it is useful to talk about individual elements of the project.

Using Kotlin / Native

It may seem like magic to press a button and have Kotlin code running on an iOS device. However, there are several tools and scripts behind the scenes that help to withdraw this illusion.

As mentioned earlier, the Kotlin / Native platform has its own compiler, but manually running it every time you want to build your project would not be an effective use of time. Kotlin / Native uses Gradle Build Tool to automate the entire Kotlin / Native process within Xcode . ]. The use of Gradle means that the developer can take advantage of his internal incremental architecture, just build and download what it takes and save a precious time for a developer.

Build Phase Script

This is done from the Build Phases panel in Xcode, which you can reach by clicking the MeteoriteFinder project ▸ MeteoriteFinder under TARGETS ▸ Build Phases . Expand Compile Kotlin / Native .

 Code Building Phase

The script calls the gradual tool that is part of the Gradle Build System and passes in the building environment and troubleshooting options. Then gradlew calls a custom task called copyExecutable which copies items like gradlew builds (a .kexe file) to the iOS project directory. Finally, the script contains artifact in iOS executable.

Gradle Build Script

Gradle uses a building script (called build.gradle ) to configure the project. You can find the file build.gradle under the Support Files folder in Xcode.

View build.gradle file:

  // 1
plugins {
id "org.jetbrains.kotlin.platform.native" version "1.3.0"
}

components.main {
// 2
def productsDir = new file (""). absolutePath
// 3
goal = ['ios_arm64', 'ios_x64']
// 4
outputKinds = [EXECUTABLE]
// 5
all targets {
leftOpts & # 39; -rpath & # 39 ;, & # 39; @ executable_path / Frameworks & # 39;
leftOpt "-F $ {productsDir}"
}
}

// 6
Task Copy Executable () {
doLast {
def srcFile = tasks ['compileDebugIos_x64KotlinNative'] .outputFile
def targetDir = getProperty ("konan.configuration.build.dir")
copy {
from srcFile.parent
into targetDir
}
}
}

In more detail:

  1. The block plugs contain id and version of the Kotlin / Native Gradle plugin that you want to use .
  2. Saves the absolute path of this project in the productsDir variable you want to use later.
  3. Displays the goals of the iOS architectures. ios_x64 is the architecture used for the iOS simulators. There are many other goals, such as ios_arm64 that target a physical iOS device.
  4. outputKinds is a list of items that you want to produce. EXECUTABLE will produce a standalone executable that can be used to run the app. If you wanted to create a framework you will use RAMME output stroke.
  5. In the allTargets block, you pass link options to the compiler.
  6. The block copyExecutable is the task you saw in the Construction Phase section of Xcode. This script copies the generated runtime from the Gradle building folder to the iOS build folder.

Required iOS classes

The construction phase script and Gradle script Gradle script ] is required to build and upload the Kotlin aspect of the project.

There are a few files that an iOS project must have. I Xcode is the following folder structure: MeteoriteFinder project ▸ MeteoriteFinder ▸ src ▸ head ▸ kotlin . Expand these folders and you will see two files:

  • AppDelegate.kt : Works with the app object to ensure that the app interacts properly with the system and with other apps.
  • main.kt : Just have the main method to start the app.

You will not touch AppDelegate.kt or main.kt but it's good to know that you have these Kotlin files to run the app.

Now that you know how the project is built, time to start finding some Meteorites!

Adding a MKMapView to Storyboard

First you want to add a MKMapview component to the storyboard. This will show the locations of the meteorites. Open Main.storyboard and delete the label hey .

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

In the Xcode toolbar, click the Library button. When a popup appears, search for Map Package View (corresponding to MKMapView ) as below:

 Xcode Objects Library

Next, drag Map Kit View to the phone line where you just deleted the label. Then drag the edges to Map Package View to record the entire screen.

To view the map correctly on different screen sizes on a device, you must adjust the limitations. Since you only have a certain worry, Xcode will set the limitations for you.

Select the component MKMapview you added. Then click Solve Auto Setup Issues on Xcode Bottom Toolbar. Then select Add Missing Limits .

 Solve missing constraints

Now as the scene Map Kit View is put in the storyboard with some limitations, you want to add a ViewController .

Create ViewController

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

You must create a ViewController in Kotlin. Since Xcode does not understand the Kotlin source code, you must create an empty file for ViewController .

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

 Resolve missing restrictions

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.UIT. *
import platform.MapKit. *

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

// 3
@OverrideInit
designer (codes: NSCoder): super (codes)

// 4
override fun viewDidLoad () {
super.viewDidLoad ()
}
}

Here's what you added:

  1. Import for Kotlin to interop with Objective-C and some of the Cocoa Touch frames.
  2. The class inherits from UIVIewController and complies with MKMapViewDelegateProtocol . @ExportObjCClass The annotation helps Kotlin create a class that is visible for posting when driving.
  3. Overrides UIViewController the initialiser with a Kotlin constructor.
  4. Overrides viewDidLoad () method.

Hold in a second! Something is missing here. Where are syntax highlighting and code execution?

 Sad face

Fortunately, the creators of Kotlin can help you here via 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). Switch to AppCode Download Center to download and install the latest stable version.

Note : Unfortunately, AppCode is not available. It is a 30-day trial version of the production version.

With AppCode installed, you must install Kotlin / Native IDE plugin. Open AppCode then click Configure ▸ Plugins to display the plug-in.

 AppCode Plugin from Home Screen

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

 Kotlin Native Plugin

Go ahead and click Install to install the plugin and when installing Completed, start AppCode again. Once you've restart, select Open Project and navigate to the root directory of your MeteoriteFinder project (the one containing the MeteoriteFinder.xcodepro file and Open file. When the project is open, expand the folder structure and explore the layout. If you already use Android Studio or IntelliJ IDEA AppCode will look very familiar.

Merge ViewController

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

Note : At this time see red underline under super (codes) . This is a false positive and you can see more through this tutorial. Kotlin / Native plugin is in active development and is still in beta. Valid errors will be captured by the compiler when building / running the project. Also full syntax highlighting can not be displayed instantly, but instead only shortly after AppCode has fully integrated Kotlin / Native plugin. Syntax highlighting can also not be displayed intermittently due to the beta nature of the plugin.

Under the designer, add the following:

  @ObjCOutlet
sentinit was mapView: MKMapView

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

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

  // 1
drop center = CLLocationCoordinate2DMake (38.8935754, -77.0847873)
fall span = MKCoordinateSpanMake (0.7, 0.7)
choice region = MKCoordinateRegionMake (center, team)

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

Go through this step by step:

  1. Create center span and region properties that will be used to place the visible area of ​​ mapView .
  2. Use the Kotlin Standard Library with the function, to scale and setup a few mapView features. Within the scope you have put mapView delegated similar to this MeteoriteMapViewController and set the region to mapView .

CLLocationCoordinate2DMake is from another module, and you must import from the CoreLocation module to make the compiler happy. You can type the import at the top of the file:

  import platform.CoreLocation.CLLocationCoordinate2DMake

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

Since MeteoriteMapViewController corresponds to MKMapViewDelegateProtocol and sets mapView delegate to this class allows MeteoriteMapViewController to receive revocation events from mapView mapView ].

To comply with the protocol, first implement the map mapViewDidFailLoadingMap () only if the map does not load. Add the following under viewDidLoad () method:

  override funny mapViewDidFailLoadingMap (mapView: MKMapView, withError: NSError) {
NSLog ("Map loading error: $ withError")
}

Then create a method that will insert data to display on the map. Add the following method call to the end of viewDidLoad () :

  createAnnotation ()

The method call should appear red because it is not yet declared. Time to do it! Select the method, and then press option + return at the same time. Select Create function createAnnotation & # 39; .

  •   create function

    In the new createAnnotation () method, delete ] TODO milking code and add the following:

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

    In the above:

    1. Create a MKPointAnnotation which will represent a stick on the map. At the moment you have set up some spot data.
    2. Add annotation variable to mapView .

    At this time you have created a ViewController that shows a single stick on a map.

     ViewController Control Point ]

    Build the project to make sure that no errors appear by selecting Run from the toolbar and then Build .

     AppCode Build

    ] The first building in AppCode may take some time to complete.

    Connecting Storyboard

    Congratulations! No construction defects.

    Then you must connect ViewController to the layout defined in the storyboard. This means that you must add a reference to ViewController in the storyboard.

    AppCode does not support editing of storyboards, so this task must be done in Xcode . Double-click Main.storyboard to open in Xcode IDE. Then click the ViewController icon of the simulated phone:

     ViewController Focus

    Then select Identity Inspector and enter MeteoriteMapViewController in the class field.

     Identity Inspector

    Finally, link MKMapView view from the storyboard to mapView property in the MeteoriteMapViewController class.

    Note : In objective C and Swift files, Xcode allows you to drag a line from the storyboard view directly to the code and make the connection automatically. However, since Xcode does not understand Kotlin, you must do this task manually in XML .

    I Xcode Right-click Main.storyboard then select Open as ▸ Source Code .

     Open as Source

    In XML you will find the closing tag and add the following link directly above it:

      
    <outlet property = "mapView" destination = "" id = "rPX-AH-rma" />
    
    

    The above code shows how the storyboard knows what the views belong to your outlets. The attributes of the expiration mark do all the mapping.

    • property points to the name of the actual property in your code. In this case, it is mapView . For this mapping to work, you also needed to provide a hint that mapView can be used as a withdrawal as you did with @ObjCOutlet the annotation in ViewController ] .
    • destination points to id of the mapView connection. Generally, these id s are randomly generated by Xcode when you connect an output to a property defined in a ViewController . Under the section, find the tag and look for the id attribute. This is id for use in the destination attribute.
    • id is a randomly generated ID. You do not want to use this directly.

    Note : To return to the storyboard setup, right-click Main.storyboard then select Open as ▸ Interface Builder - Storyboard . Also, Xcode is used only for editing the storyboard. You are welcome to close Xcode before proceeding to the next section.

    With these changes, you can now run the app from either Xcode or AppCode.

    Runs in Xcode:
      Running in Xcode

    Running in AppCode:
      Running in AppCode

    After you have built and run, The simulator show your mock meteorite on the map.

     Simulator for the first time

    Add a library from Objective-C Third party

    Now that you have a mock data stick that shows on the map, what about the map with some real data ?

    Thanks to NASA you have access to a rich collection of historical meteorite data. You can see the table format here, but your app will consume the JSON API located here.

    Now that you can find historical meteorite data, how do you make a network call to get it? You want to use a popular third-party Objective-C library called AFNetworking. The frame is already included in the project as AFNetworking.framework ; you just need to make it kotlin friendly.

    Kotlin / Native provides headlines for the iOS platforms outside the box, but how do you call third party iOS libraries?

    Create your own headlines for interoperability done using a tool called cinterop ]. This tool converts C and Objective-C headings to a Kotlin API that your code can use.

    Before running this utility, you must create a .def file that describes which frames to convert and how to convert them. Return to AppCode . Right-click the main menu then select New ▸ Group . Name the folder c_interop .

  • Note : This is the default location as the tool cinterop will look for def files.

     AppCode New Group

     AppCode New Group Name

    Then right-click on the c_interop [1945901010] folder and select New ▸ File for to create a new file. Name the file avnetworking.def . Add the following to the file:

      language = Objective-C
    headlines = AFURLSessionManager.h AFURLResponseSerialization.h AFHTTPSessionManager.h
    compilerOpts = -framework AFNetworking
    linkerOpts = -framework AFNetworking
    

    Gives the code above:

    • language informs the tool of the framing language.
    • headings is the list of headlines to generate Kotlin APIs. Here you enter three headlines that your app will use from AFNetworking .
    • compilerOpts and linkerOpts are compiler and link options sent to the tool.

    It is all configuration needed to run the tool cinterop . Gradle provides support that allows you to automate cinterop tasks when building the project.

    Open build.gradle and by the end of components.main section add the following:

      // 1
    addictions {
    // 2
    cinterop (& # 39; AFNetworking & # 39;) {
    package name & # 39; com.afnetworking & # 39;
    compilerOpts "-F $ {productsDir}"
    leftOpt "-F $ {productsDir}"
    // 3
    includeDirs {
    allHeaders "$ {productsDir} /AFNetworking.framework/Headers"
    }
    }
    }
    

    Review of this in turn:

    1. The block addiction shows the libraries the app depends on.
    2. cinterop is the block that will call into the cinterop tool. Passes a string that in cinterop (& # 39; AFNetworking & # 39;) will use AFNetworking to name Gradle tasks and the generated Kotlin file. You also give the library a package name so the code is named. Finally, you send compiler and linker options that define where to find the library.
    3. I includes Dirs allows cinterop to search for header files in AFNetworking.framework / Headers .

    Next time you build the project, the cinterop tool will create a Kotlin-friendly API around AFNetworking your library your project can use.

    ] Make Network Requests

    With AFNetworking ready to make network calls on your behalf, you can begin to retrieve some real data. But first you want to make a model for the data. Under the folder kotlin you create a new file named Meteorite.kt and add the following:

      // 1
    Class Meteorite (Val Json: Map ) {
    
    // 2
    choice name: String by json
    fall fall: String by json
    fall reclat: String by json
    Choice reclong: String by json
    Valmasse: String by json
    election year: String by json
    
    // 3
    companion object {
    Fun from JonList (jsonList: List <HashMap >): List  {
    fall meteoriteList = mutableListOf  ()
    for (jsonObject in jsonList) {
    fall newMeteorite = Meteorite (jsonObject)
    if (newMeteorite.name! = null
    && newMeteorite.fall! = null
    && newMeteorite.reclat! = null
    && newMeteorite.reclong! = null
    && newMeteorite.mass! = null
    && newMeteorite.year! = null) {
    meteoriteList.add (newMeteorite)
    }
    }
    return meteorite list
    }
    }
    }
    

    Review the code above:

    1. Create a class that model the JSON data you want to receive.
    2. Add more properties that use Map Delegation from Kotlin to get their values. The name of each property is key on the map.
    3. Add fromJsonList () the inside of a companion object so that it can be called by class type. This feature takes a list of map objects and returns a list of valid Meteorite objects. A valid Meteorite object is one where none of the properties are null.

    You will now configure a network request to retrieve real meteorite data. Return to MeteoriteMapViewController.kt . Begin importing the package AFNetworking so that you can use it in the class:

      import com.afnetworking. *
    

    Next, under mapView property declaration adds properties to hold collections of Meteorite and MKPointAnnotation objects:

      was meteoriteList = listOf  ( )
    fall meteoriteAnnotations = mutableListOf  ()
    

    Then add the following method that will load the data:

      private funny loadData () {
    choice baseURL = "https://data.nasa.gov/"
    choice path = "resource / y77d-th95.json"
    fall params = "?  $ where = within_circle (GeoLocation, 38.8935754, -77.0847873, 50000)"
    
    // 1
    Select url = NSURL.URLWithString ("$ baseURL $ path $ params")
    
    // 2
    fall manager = AFHTTPSessionManager.manager ()
    
    // 3
    manager.responseSerializer = AFJSONResponseSerializer.serializer ()
    
    // 4
    manager.GET (url? .absoluteString !!, null, null, {_: NSURLSessionDataTask?, responseObject: Any? ->
    // 5
    drop listOfObjects = responseObject as? List <HashMap >
    listOfObjects? .let {
    meteoriteList = Meteorite.fromJsonList (it)
    for (meteorite in meteorite list) {
    meteoriteAnnotations.add (createAnnotation (meteorite))
    }
    mapView.addAnnotations (meteoriteAnnotations)
    }
    }, {_: NSURLSessionDataTask?, Error: NSError? ->
    // 6
    NSLog ("Got an error $ {error}")
    })
    }
    

    Partially extracting the extract part:

    1. NSURL.URLWithString creates an NSURL object to ask requests. params passed will limit our response to around 300 kilometers from Arlington, VA.
    2. AFHTTPSessionManager.manager () is your first call to the AFNetworking framework.
    3. Set manager to send all responses back to the app as JSON using AFJSONResponseSerializer .
    4. Call a GET request on manager . You passed in absolute url, two null values ​​and a lambda block to handle a successful or erroneous response, respectively.
    5. Successful response is returned in this lambda. The answer is thrown into a list of HashMaps. Then, the list is converted to a list of Meteorite . Finally create map annotations for each Meteorite and add it to mapView .
    6. This lambda will be called if there are any network errors; You just log the error.

      Change the change call from createAnnotation () in viewDidLoad () the method to instead be loadData () ] and update the method createAnnotation () to be the following:

        private fun createAnnotation (meteorite: Meteorite) = MKPointAnnotation ()
      fall latitude = meteorite.reclat.toDouble ()
      fall longitude = meteorite.reclong.toDouble ()
      
      setCoordinate (CLLocationCoordinate2DMake (latitude, longitude))
      setTitle (meteorite.name)
      setSubtitle ("Enter $ {meteorite.year.substringBefore (" - ")}" +
      "with a lot of $ {meteorite.mass} grams")
      }
      

      Med disse endringene passerer du Meteorite objekter og dynamisk legger pins til kartet ved hjelp av MKPointAnnotation . Du bruker også Kotlins Single Expression Function-format kombinert med gjelder -funksjonen for å lette prosessen med å instansiere MKPointAnnotation objekter og fylle sine verdier.

      Bygg og kjøre appen igjen

       Simulator med data

      For å zoome inn / ut i iOS-simulatoren, hold nede Alternativ -tasten for å oppdage de fallne meteorittene. and drag across the map.

      Note: As stated earlier, Kotlin/Native is in beta and there are still some rough edges. If you are still seeing your mock meteorite, you may need to delete the build folder to force a clean build of the project.

      Where to Go From Here?

      Download the fully finished projects using the Download materials button at the top or bottom of this tutorial to see how it went.

      Kotlin/Native has opened the doors to interoperability with more platforms. You’ve seen how it works on iOS, but you can also target platforms like Linux with C and Web with WebAssembly. You can even target both Android and iOS in the same project using Kotlin Multi-Platform Modules.

      In this tutorial, you have only scratched the surface of how Kotlin/Native works on iOS and what it offers. More information can be found on the Kotlin website and on Github.

      Please add your thoughts, comments, and questions to the discussion below, and have fun exploring Kotlin/Native!


    Source link