Converting your iOS App to Android Using Kotlin
In this tutorial, you’ll see first-hand how similar these languages are and how simple it is to convert Swift to Kotlin by porting an iOS app to Android. By Lisa Luo.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Converting your iOS App to Android Using Kotlin
25 mins
Manipulating Lists (Map)
First-class list manipulation is another extremely powerful feature of Swift. If you want to double all the values in an integer array, you simply call map
on the array and multiply each value by two. Paste this code in the Swift playground.
let xs = [1, 2, 3]
print(xs.map { $0 * 2 })
In Kotlin, you can do the same! Again, copy and paste the code from the Swift playground to the Kotlin playground. After making changes to make it match Kotlin syntax, you’ll have this:
val xs = listOf(1, 2, 3)
print(xs.map { it * 2 })
To get here, you:
- Change
let
toval
again as you did in the previous example. - Change the way you declare your array of integers by using
listOf()
instead of square brackets. - Change
$0
to reference the value inside the map function toit
.$0
represents the first element of a closure in Swift; in Kotlin, you use the reserved keywordit
in a lambda.
This is so much better than manually having to loop through an array one value at a time to multiply all the integer values by two!
Bonus: See what other functions you can apply to lists in Swift and Kotlin! Doubling integers is a great example. Or one could use filter
to filter for specific values in the list, or flatMap
, another quite powerful, built-in list operator that flattens nested arrays. Here’s an example in Kotlin that you can run in the Kotlin playground:
val xs = listOf(listOf(1, 2, 3))
print(xs.flatMap { it.map { it * 2 }})
You could go on for quite a few tutorials with all of the Swift and Kotlin goodness, but you’d run out of time to write your Poke the Bear app in Kotlin, and you certainly don’t want to leave your Android users hanging with just an iOS app as per usual! :]
Writing the Android App
Open the starter Android app in Android Studio 3.1.4 or higher. Again, you can find this by clicking the Download materials button at the top of bottom of this tutorial. You can open the project by going to File ▸ New ▸ Import Project, and selecting the root folder of the starter project. This project is a bit more bare bones than the completed iOS app — but not to fear! This tutorial will guide you through building the Android version of the app!
Implementing the LoginActivity
Open the app ▸ java ▸ com.raywenderlich.pokethebear ▸ LoginActivity.kt file in the Android project. This mirrors your LoginViewController
in the iOS project. The Android starter project has an XML layout file corresponding to this activity so take a peek at the app ▸ res ▸ layout ▸ activity_login.xml to reference the views you’ll use here, namely the login_button
and password_edit_text
.
Input Validation
The first function you’ll copy over from your Swift project file, LoginViewController.swift, is the function named containsNumbers
:

private func containsNumbers(string: String) -> Bool {
let numbersInString = string.filter { ("0"..."9").contains($0) }
return !numbersInString.isEmpty
}
Again, using your radical cross-platform copy-and-paste approach, copy the function and paste it inside the LoginActivity
class in the LoginActivity.kt file in Android Studio. After making some changes, here’s the Kotlin code you have:
private fun containsNumbers(string: String): Boolean {
val numbersInString = string.filter { ("0".."9").contains(it.toString()) }
return numbersInString.isNotEmpty()
}
- As you previously did in your playground, you change
let
toval
for the immutable declaration of the return value. - For the function declaration, drop the ‘c’ from
func
and have somefun
! You declare Kotlin methods usingfun
rather thanfunc
. - The return value of the function in Kotlin is denoted by a colon
:
rather than a lambda symbol->
. - Also, in Kotlin a boolean is called
Boolean
instead ofBool
. - To have a closed
Range
in Kotlin, you need to use two dots instead of 3, so"0"..."9"
changes to"0".."9"
. - Just as you did with the
map
example in the playground, you also have to convert$0
toit
. Also, convertit
to a String for thecontains
comparison in Kotlin. - Finally, you do a little cleanup in Kotlin with the return statement. Instead of using
!
to negate an empty check, you simply use the KotlinString
functionisNotEmpty
.
Now, the code syntax is changed from Swift to Kotlin.
Copy over the passwordIsValid
function from the LoginViewController
in the iOS project and paste it into the
private func passwordIsValid(passwordInput: String) -> Bool {
return passwordInput.count >= 6 && self.containsNumbers(string: passwordInput)
}
Make the appropriate changes to translate the code from Swift to Kotlin again; you should end up with something like this:
private fun passwordIsValid(passwordInput: String): Boolean {
return passwordInput.length >= 6 && this.containsNumbers(string = passwordInput)
}
Some differences here is that you’re using:
-
length
instead ofcount
, -
this
instead ofself
, and -
string =
instead ofstring:
.
Note that the string =
param label is not required in Kotlin. It helps with keeping the similarity between both languages for this tutorial. In practice, labels are a wonderful detail that Kotlin included to make default function parameters reachable from Java code. Read up more on @JvmOverloads
functions here to learn more about default params!
Showing Errors
Copy the showLengthError
and showInvalidError
functions over from the LoginViewController
in the iOS project to the body of the LoginActivity
class in the Android project.
The showLengthError
function determines whether or not the password entered by the user contains six or more characters, and displays an appropriate alert message if it is not:
private func showLengthError() {
let alert = UIAlertController(title: "Error",
message: "Password must contain 6 or more characters",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Okay",
style: UIAlertActionStyle.default,
handler: nil))
self.present(alert, animated: true, completion: nil)
}
The showInvalidError
function determines whether or not the password entered by the user contains at least one numeric character, and the it displays an appropriate alert message if it does not:
private func showInvalidError() {
let alert = UIAlertController(title: "Error",
message: "Password must contain a number (0-9)",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Okay",
style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
Now, you must translate the newly copied functions’ code syntax from Swift to Kotlin in your Android app. Your new showError
functions will require a reach back into the knowledge of the good ol’ Android API! You’ll now implement the equivalent of UIAlertController
using an AlertDialog.Builder
. You can see more information about common design patterns such as AlertDialog in this tutorial. The dialog’s title, message and positive button strings are already included in your strings.xml
, so go ahead and use those! Replace showLengthError
with this code:
private fun showLengthError() {
AlertDialog.Builder(this)
.setTitle(getString(R.string.error))
.setMessage(getString(R.string.length_error_body))
.setPositiveButton(getString(R.string.okay), null)
.show()
}
Use the same format to create your showInvalidError
AlertDialog. Replace the copied method with the following:
private fun showInvalidError() {
AlertDialog.Builder(this)
.setTitle(getString(R.string.error))
.setMessage(getString(R.string.invalid_error_body))
.setPositiveButton(getString(R.string.okay), null)
.show()
}
Handling Button Taps
Now that you have written the validation and error display functions, put it all together by implementing your loginButtonClicked
function! An interesting difference to note between Android and iOS is that your Android view is created and set explicitly in your first lifecycle callback, onCreate()
, whereas your Main.storyboard in the iOS app is implicitly linked in Swift. You can learn more about the Android lifecycle in this tutorial here.
Here is the loginButtonTapped
function from the iOS project.
@IBAction func loginButtonTapped(_ sender: Any) {
let passwordInput = passwordEditText.text ?? ""
if (passwordIsValid(passwordInput: passwordInput)) {
self.performSegue(withIdentifier: "pushBearViewController", sender: self)
} else if (passwordInput.count < 6) {
self.showLengthError()
} else if (!containsNumbers(string: passwordInput)) {
self.showInvalidError()
}
}
Copy and paste the body of the loginButtonTapped
function from the iOS project into the body of the loginButtonClicked
function in the Android project and make the small changes you have now mastered to change the syntax from Swift to Kotlin.
val passwordInput = this.password_edit_text.text.toString()
if (passwordIsValid(passwordInput = passwordInput)) {
startActivity(Intent(this, BearActivity::class.java))
} else if (passwordInput.length < 6) {
this.showLengthError()
} else if (!containsNumbers(string = passwordInput)) {
this.showInvalidError()
}
Two differences here are the method of extracting the string from the EditText and the means of displaying the new activity. You use the statement this.password_edit_text.text.toString()
to get the text from the passwordInput
view. Then, make a call to the startActivity
function passing in an Intent
to launch the BearActivity
activity. The rest should be pretty straightforward.
Your LoginActivity
is now done. Build and run the app in Android Studio to see your first implemented activity displayed on a device or in the emulator. Enter any string value for the username and play around with valid and invalid password combinations to ensure that your error dialogs show as expected.
A successful login in will reveal the bear screen, which you’ll implement right now!