- Converting your iOS App to Android Using Kotlin
- Original author: Lisa Luo
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: iWeslie
- Proofreader: LoneyIsError, Phxnirvana
Through this tutorial, you’ll see for yourself the language similarities and see how easy it is to convert Swift to Kotlin by porting an iOS application to Android.
Mobile devices are your daily companion, carrying them in your backpack and pockets wherever you go. As technology continues to adapt to your mobile device, mobile development will become more common as a hobby or profession.
Usually developers will choose a development platform, the most common being Android or iOS. This choice is generally based on the resources available to the individual (for example, her or his personal devices) or the current market environment. Many developers tend to build applications only for the platform of their choice. Android and iOS engineers have historically used completely different languages and ides, and while there are many similarities between the two mobile platforms, cross-platform development between the two platforms is daunting and rare.
But the languages and tools for Android and iOS development have improved dramatically in the past few years, mainly with the advent of Kotlin and Swift, which ease the barriers between cross-platform learning. Once you know the language basics, you can easily convert your code from Swift to Kotlin.
In this tutorial, you’ll see for yourself how similar these languages are and how easy it is to convert From Swift to Kotlin. First open Xcode and you’ll explore writing an iOS application using Swift, then you’ll rewrite the same application using Kotlin in Android Studio.
Note: Familiarity with the basics of Swift and iOS or Kotlin and Android will help you complete this tutorial. You can learn about Swift for iOS through these tutorials or Kotlin for Android through these tutorials.
start
Download the test items to start the tutorial.
The iOS APP architecture
Open the ios-Finished sample application in Xcode and run it on the emulator, which will prompt you to log in. Enter a user name and any sum password that is at least six characters long and contains at least one numeric character to log in to the application.
Log in the APP with your user name and password and enter the main page of the project: Bears, attention! Poke it and see what happens…
Now you can focus on the two ViewControllers in this simple application architecture, one for each interactive page.
LoginViewController
和BearViewController
Finding these controllers in the project, the application first loads the LoginViewController, which holds the UI components of TextField and Button defined in Main.storyboard. Also note that the LoginViewController contains two helper functions for validating passwords and two helper functions for displaying invalid password errors, which are the two Swift functions you will override in Kotlin.
The BearViewController also holds UI components from Main.storyboard. Typically in iOS development, each ViewController has its own storyboard page. In this tutorial you will focus on the ViewController logic components rather than the UI. In the BearViewController, you keep a reference to a variable called tapCount, which updates every time you click a pokeButton, triggering a different state for the bear.
Swift to Kotlin: The basics
Now that you have a general idea of the application, it’s time to take a technical twist on Playground and dive into some of the language details. For Swift, click File ▸ New ▸ Playground in Xcode to create a New Blank Playground and then write some code!
Variables and options
In Swift there is a concept called optionality. Optional values contain a value or are nil. Paste this code into Swift Playground:
var hello = "world"
hello = "ok"
let hey = "world"
hey = "no"
Copy the code
Swift uses var and let to define variables, and the two prefixes define variability. Let variables cannot be modified after they are declared, which is why the compiler reports an error, whereas var variables can be changed at run time.
Add a type declaration to the code in playground, which now looks like this:
var hello: String? = "world"
hello = "ok"
let hey: String = "world"
hey = "no"
Copy the code
By adding type annotations to these two variables, you’ve set Hello to a nullable String, specified by String? In the? Hey is a non-empty String. Nullable variables are called optional in Swift.
Why is this detail important? Null values can often lead to nasty crashes in your application, especially if your data source is not always defined in the client (for example, if you expect the server to get a value and it doesn’t return it). Using simple prefixes like let and var allows you to do built-in dynamic checking to prevent programs from compiling when the value is null. For more information, see the related tutorial on functional programming in Swift.
But what about Android? Nullability is often considered one of the biggest pain points in Java development. NPE (or null pointer exception) is usually the cause of program crashes due to improper handling of null values. The most effective thing you can do in Java is to use the @nonNULL or @nullable annotation to warn if the value is Nullable. But these warnings don’t stop you from compiling and running your application. Luckily, Kotlin saved it! See Kotlin’s introduction for more information.
Open Kotlin Playground at try.kotlinlang.org and paste the code just written in Swift Playground to replace the body of the main function:
Isn’t that great? You can copy code from one playground to another, even if the two playgrounds use different languages. Of course, the syntax is not exactly the same. Kotlin uses val instead of let, so now change the keyword to the way Kotlin declares immutable variables, as follows:
fun main(args: Array<String>) {
var hello: String? = "world"
hello = "ok"
val hey: String = "world"
hey = "no"
}
Copy the code
Now that you have made the change, you now redirect let to Val, and you have Kotlin code!
Click on Run in the upper right corner and you’ll see a meaningful error:
This is the same thing you see on Swift Playground. Just like let, you can’t reassign to val.
Operation array (Map)
Arrays are very powerful to operate as first-class citizens in Swift. If you want to double all the values in the integer array, you simply call the map function and multiply each value by 2. Paste this code into Swift Playground.
let xs = [1.2.3]
print(xs.map{$0 * 2 })
Copy the code
In Kotlin, you can do the same! Once again, copy and paste the code from Swift Playground into Kotlin Playground. After you modify it to match Kotlin syntax, you get the following:
val xs = listOf(1.2.3)
print(xs.map { it * 2 })
Copy the code
To get to this point, you need to:
- Again, as in the previous example
let
Instead ofval
. - use
listOf()
Instead of square brackets, change the way you declare an integer array. - In the map function
$0
Instead ofit
To reference the value.$0
Represents the first element of the closure in Swift, whereas in Kotlin you use reserved keywords in lambda expressions.
This is much better than manually iterating through each value of the array and multiplying all integers by 2!
Bonus: Now see what functions you can apply to arrays in Swift and Kotlin! Doubling an integer is a good example. Or you can use a filter to filter specific values in an array, or flatMap (another very powerful built-in array operator) to flatten nested arrays. Here’s an example of Kotlin, you can now run Kotlin Playground:
val xs = listOf(listOf(1.2.3))
print(xs.flatMap { it.map { it * 2 }})
Copy the code
You can keep using all the good things about Swift and Kotlin, but you don’t have time to write your Poke the Bear app in Kotlin, and you don’t want to throw your Android users an iOS app and overwhelm them as usual!
Write Android applications
Open the Android Starter app in Android Studio 3.1.4 or later. You can Import the Project by clicking File ▸ New ▸ Import Project, and then select the root folder of the Kotlin-Starter Project to open the Project. This project is much simpler than the previously completed iOS app, but fear not! This tutorial will guide you through building the Android version of your application!
Implement LoginActivity
Open the app ▸ Java ▸ com. Raywenderlich. Pokethebear ▸ LoginActivity. Kt file. This is similar to the LoginViewController in the iOS project. The Android Getting Started project has an XML layout file corresponding to this activity. Open app ▸ res ▸ Layout ▸ activity_login. XML to reference the view you will use here. Login_button and password_edit_text.
Input validation
Now you will project files from Swift LoginViewController. Swift copy of the first function called containsNumbers: 
private func containsNumbers(string: String) -> Bool {
let numbersInString = string.filter{("0"."9").contains($0)}return! numbersInString.isEmpty }Copy the code
Again, you can use your aggressive cross-platform copy-and-paste approach by copying this function and pasting it into the LoginActivity class in the LoginActivity.kt file in Android Studio. With a few changes, here’s your Kotlin code now:
private fun containsNumbers(string: String): Boolean {
val numbersInString = string.filter { ("0"."9").contains(it.toString()) }
return numbersInString.isNotEmpty()
}
Copy the code
- As you did earlier on playground, will
let
Change toval
To declare an immutable return value. - For function declarations, you can see that from
func
Delete the ‘c’ in get some fun! Do you usefun
Rather thanfunc
To declare the function in Kotlin. - The return value of a function in Kotlin is a colon
:
Represents instead of lambda notation->
. - Also, in Kotlin, Boolean values are called
Boolean
Rather thanBool
. - You want to declare a closed interval in Kotlin
Range
You need to use two points instead of three, so"0"..." 9"
To change to"0".." 9"
. - Like you use in playground
map
Again, you have to be$0
convertit
. Also, called in Kotlincontain
To compare what needs to beit
Convert to String. - Finally, you use the return statement to do some cleanup in Kotlin. You just use Kotlin
String
The function ofisNotEmpty
To check if it’s empty instead of using!
.
The code statement is now changed from Swift to Kotlin.
Copy the passwordIsValid function from the iOS project LoginViewController and paste it into the Android project class:
private func passwordIsValid(passwordInput: String) -> Bool {
return passwordInput.count> =6 && self.containsNumbers(string: passwordInput)
}
Copy the code
This also requires appropriate changes to convert the code from Swift to Kotlin. You should get code like this:
private fun passwordIsValid(passwordInput: String): Boolean {
return passwordInput.length >= 6 && this.containsNumbers(string = passwordInput)
}
Copy the code
There are also some details that differ:
- with
length
Rather thancount
- with
this
Rather thanself
- with
string =
Rather thanstring:
Note that the string = method is not required in Kotlin, which helps maintain similarities between the two languages in this tutorial. Tags in other practices are more details that Kotlin includes to make default function arguments accessible to Java code. Read more about the @jvMoverloads function to learn more about the default parameters!
Mistakes show
Copy the showLengthError and showInvalidError functions from the iOS project LoginViewController to the Android project LoginActivity class.
The showLengthError function determines whether the password entered by the user contains six or more characters and displays the appropriate alert message if it does not:
private func showLengthError(a) {
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)}Copy the code
The showInvalidError function is used to check whether the password entered by the user contains at least one numeric character. If not, the corresponding warning message will be displayed:
private func showInvalidError(a) {
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)}Copy the code
Now, you must convert the code of the newly copied function from Swift to Kotlin in the Android app. Your new showError function needs to reintroduce the Android API. You will now use AlertDialog.Builder to do something similar to UIAlertController. You can see more information about common design patterns, such as AlertDialog, in this tutorial. The dialog’s title, message, and ok button strings are already included in strings.xml, so go ahead and use them! Replace showLengthError with the following code:
private fun showLengthError(a) {
AlertDialog.Builder(this)
.setTitle(getString(R.string.error))
.setMessage(getString(R.string.length_error_body))
.setPositiveButton(getString(R.string.okay), null)
.show()
}
Copy the code
Create an AlertDialog that displays showInvalidError using the same format. Replace the copied method with the following:
private fun showInvalidError(a) {
AlertDialog.Builder(this)
.setTitle(getString(R.string.error))
.setMessage(getString(R.string.invalid_error_body))
.setPositiveButton(getString(R.string.okay), null)
.show()
}
Copy the code
Handles button click events
Now that you have the validation and error display capabilities, you can put them together by implementing the loginButtonClicked function. One interesting difference to note between Android and iOS is that your Android view is explicitly created and set in the first lifecycle callback onCreate(), whereas main.storyboard in iOS apps is implicitly linked in Swift. You can learn more about the Android life cycle in this tutorial here.
This is the loginButtonTapped function in 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 the code
Copy and paste the body of the iOS (loginButtonTapped) function into the Android (loginButtonClicked) function body, and make some minor changes to the code based on what you know. 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()
}
Copy the code
The two differences here are the way to extract the string from the EditText and the way to display the new activity. You can get text from the passwordInput view using the statement this.password_edit_text.text.tostring (). The startActivity function is then called to start the BearActivity by passing in the Intent. The rest should be pretty simple.
Your LoginActivity is now complete. Now compile and run the application in Android Studio to see the first implemented activity displayed on your device or in the built-in emulator. Enter any string values for the user name and use valid and invalid password combinations to make sure your error dialog displays as expected.
Successful login will show a bear on the screen, you can now implement it!
Implement bear activities
Open the app ▸ Java ▸ com. Raywenderlich. Pokethebear ▸ BearActivity. Kt, your BearViewController. Swift file will become Kotlin version. You will start modifying the Activity by implementing the helper functions bearAttack and reset. You’ll see in the Swift file that bearAttack is responsible for setting up the UI state, hiding the Poke button for five seconds, and then resetting the screen:
private func bearAttack(a) {
self.bearImageView.image = imageLiteral(resourceName: "bear5")
self.view.backgroundColor = .red
self.pokeButton.isHidden = true
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(5),
execute: { self.reset() })
}
Copy the code
Copy this function from the iOS project and paste it into the body of the bearAttack function in the Android project, then make some minor syntactic changes to make the body of the bearAttack function in Kotlin look like this:
private fun bearAttack(a) {
this.bear_image_view.setImageDrawable(getDrawable(R.drawable.bear5))
this.bear_container.setBackgroundColor(getColor(R.color.red))
this.poke_button.visibility = View.INVISIBLE
this.bear_container.postDelayed({ reset() }, TimeUnit.SECONDS.toMillis(5))}Copy the code
You need to make the following changes:
- call
setImageDrawable
Function willbear_image_view
Image resource set tobear5.pngDrawable resource that is already contained inApp ▸ res ▸ drawableDirectory. - And then call
setBackgroundColor
Function willbear_container
The background of the view is set to a predefined colorR.color.red
. - will
isHidden
Property changed tovisibility
Instead of switching the button’s visibility toView.INVISIBLE
. - Perhaps the least intuitive change you can make to code is rewrite
DispatchQueue
But fear not! The AndroidasyncAfter
It’s a simple onepostDelayed
Action, you arebear_container
View.
It’s almost done! There is another feature to convert from Swift to Kotlin. Duplicate the transformation process by copying the body of the Swift Reset function and pasting it into the Android project’s BearActivity class reset:
self.tapCount = 0
self.bearImageView.image = imageLiteral(resourceName: "bear1")
self.view.backgroundColor = .white
self.pokeButton.isHidden = false
Copy the code
Then make similar changes:
this.tapCount = 0
this.bear_image_view.setImageDrawable(getDrawable(R.drawable.bear1))
this.bear_container.setBackgroundColor(getColor(R.color.white))
this.poke_button.visibility = View.VISIBLE
Copy the code
The final step is to copy the body of the pokeButtonTapped function from the iOS project and paste it into the Android project. Due to the similarity between Swift and Kotlin, this if/else statement will also need to be changed to Android, albeit very slightly. This ensures that your Kotlin pokeButtonClicked function body looks like this:
this.tapCount = this.tapCount + 1
if (this.tapCount == 3) {
this.bear_image_view.setImageDrawable(getDrawable(R.drawable.bear2))
} else if (this.tapCount == 7) {
this.bear_image_view.setImageDrawable(getDrawable(R.drawable.bear3))
} else if (this.tapCount == 12) {
this.bear_image_view.setImageDrawable(getDrawable(R.drawable.bear4))
} else if (this.tapCount == 20) {
this.bearAttack()
}
Copy the code
Additional disclaimer: This if/else step statement can easily be replaced with a more expressive control flow statement, such as switch, or when in Kotlin.
If you want to simplify logic, try it.
All functionality has now been ported from iOS apps and converted from Swift to Kotlin. Compile, run the app on a real machine or emulator and start using it, and now you can have your furry friend appear behind the login screen.
Congratulations, you’ve converted Swift to Kotlin and your iOS app to a brand new Android app. You’ve gone cross-platform by moving Swift code from iOS projects in Xcode to Android apps in Android Studio, converting Swift to Kotlin! Not many people and developers will say anything, and implementing it is really easy.
What’s next?
Use the link at the top of this tutorial to download the completed project to see how it works.
If you’re a Swift developer or new to Kotlin, check out the official Kotlin documentation to learn more about these languages. You already know how to run Kotlin Playground to try out snippets, and you can write working code widgets in your documentation. If you are already a Kotlin developer, try writing applications in Swift.
If you like Swift and Kotlin’s side-by-side comparison, check out more in this article. Your trusty author also had a quick discussion about Swift and Kotlin with his iOS colleagues at UIConf, which you can watch here.
We hope you enjoyed this tutorial on how to turn an iOS app written by Swift into a brand new Android app created with Kotlin. We also want you to continue to explore both languages and platforms.
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.