Apakah Kotlin Multiplatform masa depan pengembangan lintas platform? Kiat tentang cara memulai

Diterbitkan: 2021-01-29

Saat ini, kita dapat mengamati tren dalam pengembangan seluler untuk merilis aplikasi lebih cepat. Ada banyak upaya untuk mengurangi waktu pengembangan dengan berbagi bagian kode umum di antara berbagai platform seperti Android dan iOS. Beberapa solusi telah mendapatkan popularitas, sementara yang lain masih dalam pengembangan. Hari ini, saya ingin membahas salah satu pendekatan terbaru dari grup kedua – Kotlin Multiplatform Mobile (disingkat KMM).

Apa itu Kotlin Multiplatform Mobile?

KMM adalah SDK yang terutama bertujuan untuk berbagi logika bisnis di antara platform – bagian yang dalam banyak kasus harus tetap sama. Ini dicapai berkat satu set beberapa kompiler untuk modul bersama. Misalnya, target Android menggunakan varian Kotlin/JVM, dan untuk iOS ada varian Kotlin/Native. Modul bersama kemudian dapat ditambahkan ke proyek aplikasi asli biasa dan pengembang yang bertanggung jawab atas UI dapat fokus untuk memberikan pengalaman terbaik bagi pengguna di lingkungan yang mereka kenal – Android Studio untuk Android dan Xcode untuk iOS.

Kotlin Multiplatform vs Flutter

Saat ini, salah satu solusi paling populer untuk pengembangan aplikasi lintas platform adalah Flutter. Ini difokuskan pada aturan "tulis satu aplikasi dan jalankan di mana saja" – yang berfungsi, tetapi hanya untuk aplikasi sederhana. Dalam skenario kasus nyata, pengembang sering kali harus menulis kode asli untuk setiap platform untuk mengisi kekosongan , misalnya, ketika beberapa plugin tidak ada. Dengan pendekatan ini, aplikasi terlihat sama pada platform yang berbeda, yang terkadang diinginkan, tetapi dalam beberapa kasus, ini dapat melanggar pedoman desain tertentu.

Ikon layanan pengembangan lintas platform

Siap membuat aplikasi Anda sendiri?

Pilih Flutter

Meskipun mungkin terdengar serupa, Kotlin Multiplatform bukanlah solusi lintas platform – ia tidak mencoba untuk menemukan kembali roda. Pengembang masih dapat menggunakan alat yang mereka kenal dan sukai. Itu hanya menyederhanakan proses penggunaan kembali bagian kode yang sebelumnya seharusnya ditulis beberapa kali, seperti membuat permintaan jaringan, menyimpan data, dan logika bisnis lainnya.

Pro dan kontra dari Kotlin Multiplatform

Kelebihan KMM :

  • Aplikasi yang dikembangkan 100% asli untuk setiap platform – mudah diintegrasikan dengan kode yang saat ini digunakan dan perpustakaan pihak ketiga
  • Mudah digunakan – hampir semua developer Android sudah menggunakan Kotlin, jadi mereka hanya membutuhkan sedikit pengetahuan tambahan untuk memulai
  • UI dapat dibagi untuk setiap platform target – aplikasi akan terasa konsisten dengan ekosistem apa pun
  • Logika bersama memungkinkan pengembang untuk menambahkan fitur baru dan memperbaiki bug di kedua sistem operasi secara bersamaan

Kekurangan KMM :

  • Banyak komponen yang masih dalam tahap Alfa/Beta dan berpotensi menjadi tidak stabil atau berubah di masa mendatang

Perusahaan mana yang menggunakan KMM?

Menurut situs resminya, perusahaan semakin tertarik pada teknologi ini dan daftarnya terus bertambah panjang. Di antara mereka, ada merek terkenal seperti Autodesk, VMWare, Netflix atau Yandex.

Bagaimana cara memulai Kotlin Multiplatform?

Tempat terbaik untuk menyelami informasi mendalam adalah panduan resmi, tetapi dalam artikel ini, saya ingin menunjukkan contoh yang cukup sederhana, tetapi lebih menarik dari sekadar "Halo Dunia", yang akan mengambil dan menampilkan aplikasi komik terbaru oleh Randall Munroe (berlisensi di bawah CC BY-NC 2.5) dengan judul dari xkcd.com API.

Fitur yang akan dicakup:

  • Pengaturan proyek
  • Jaringan dalam modul bersama
  • UI sederhana untuk Android dan iOS

Catatan: Saya ingin contoh ini mudah dibaca oleh pengembang Android dan iOS, jadi di beberapa tempat saya sengaja menghilangkan beberapa praktik baik khusus platform hanya untuk memperjelas apa yang sedang terjadi

Pengaturan proyek

Pertama, pastikan Anda telah menginstal Android Studio dan Xcode versi terbaru karena keduanya akan diperlukan untuk membangun proyek ini. Kemudian, di Android Studio, instal plugin KMM. Plugin ini menyederhanakan banyak hal – untuk membuat proyek baru, cukup klik Buat Proyek Baru dan pilih Aplikasi KMM.

Buat proyek Seluler Multiplatform Kotlin baru

Setelah proyek dibuat, navigasikan ke file build.gradle.kts di direktori bersama . Di sini Anda harus menentukan semua dependensi yang diperlukan. Dalam contoh ini, kita akan menggunakan ktor untuk lapisan jaringan, kotlinx.serialization untuk mengurai respons json dari backend, dan kotlin coroutine untuk melakukan semuanya secara asinkron.

Untuk kesederhanaan, di bawah ini saya menyediakan daftar yang menunjukkan semua dependensi yang harus ditambahkan ke yang sudah ada. Saat Anda menambahkan dependensi, cukup Sinkronkan proyek (prompt akan muncul). Pertama, tambahkan plugin serialisasi ke bagian plugins.

 plugin {
   kotlin("plugin.serialization") versi "1.4.0"
}

Kemudian tambahkan dependensi.

 kumpulan sumber {
   val commonMain dengan mendapatkan {
       dependensi {
           implementasi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
           implementasi("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt-2")

           implementasi("io.ktor:ktor-client-core:1.4.1")
           implementasi("io.ktor:ktor-client-json:1.4.1")
           implementasi("io.ktor:ktor-client-serialization:1.4.1")
       }
   }
   val androidMain dengan mendapatkan {
       dependensi {
           implementasi("io.ktor:ktor-client-android:1.4.1")
       }
   }
   val iosMain dengan mendapatkan {
       dependensi {
           implementasi("io.ktor:ktor-client-ios:1.4.1")
       }
   }
}

Perlu disebutkan bahwa pada saat artikel ini ditulis, ada beberapa masalah dengan versi stabil dari perpustakaan coroutine di iOS – itu sebabnya versi yang digunakan memiliki akhiran native-mt-2 (yang merupakan singkatan dari native multithreading). Anda dapat memeriksa status masalah ini saat ini di sini.

Jaringan dalam modul bersama

Pertama, kita membutuhkan kelas yang mewakili respons – bidang tersebut ada di json yang dikembalikan oleh backend.

 impor kotlinx.serialization.Serializable

@Serializable
kelas data XkcdResponse(
   nilai img: String,
   val judul: String,
   hari val: Int,
   bulan val: Int,
   tahun val: Int,
)

Selanjutnya kita perlu membuat kelas yang mewakili API dengan klien HTTP . Jika kami tidak menyediakan semua bidang yang ada di json, kami dapat menggunakan properti ignoreUnknownKeys sehingga pembuat serial dapat mengabaikan yang hilang. Contoh ini hanya memiliki satu titik akhir yang diwakili oleh fungsi yang ditangguhkan. Pengubah ini memberi tahu kompiler bahwa fungsi ini tidak sinkron. Saya akan menjelaskannya lebih lanjut dengan kode khusus platform.

 impor io.ktor.client.*
impor io.ktor.client.features.json.*
impor io.ktor.client.features.json.serializer.*
impor io.ktor.client.request.*

kelas XkcdApi {
   private val baseUrl = "https://xkcd.com"

   private val httpClient = HttpClient() {
       instal(JsonFeature) {
           serializer = KotlinxSerializer(
               kotlinx.serialization.json.Json {
                   abaikanUnknownKeys = true
               }
           )
       }
   }

   menangguhkan kesenangan fetchLatestComic() =
       httpClient.get<XkcdResponse>("$baseUrl/info.0.json")

}

Ketika lapisan jaringan kami siap, kami dapat pindah ke lapisan domain dan membuat kelas yang mewakili model data lokal. Dalam contoh ini, saya melewatkan beberapa bidang lagi dan hanya menyisakan judul komik dan URL ke gambar.

 kelas data ComicModel(
   val imageUrl: String,
   judul val: String
)

Bagian terakhir untuk lapisan ini adalah membuat use case yang akan memicu permintaan jaringan dan kemudian memetakan respons ke model lokal.

 kelas GetLatestComicUseCase(nilai pribadi xkcdApi: XkcdApi) {
   menangguhkan kesenangan run() = xkcdApi.fetchLatestComic()
       .let { ComicModel(it.img, it.title) }
}

UI sederhana untuk Android

Saatnya pindah ke direktori androidApp – di sinilah aplikasi asli Android disimpan. Pertama, kita perlu menambahkan beberapa dependensi khusus Android ke file build.gradle.kts lain yang terletak di sini. Sekali lagi, daftar di bawah ini hanya menunjukkan dependensi yang harus ditambahkan ke yang sudah ada. Aplikasi ini akan menggunakan arsitektur Model-View-ViewModel (dua baris pertama), dan Glide untuk memuat gambar komik dari URL yang dikembalikan (dua baris kedua)

 dependensi {
   implementasi("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
   implementasi("androidx.lifecycle:lifecycle-livedata-ktx:2.2.0")
   implementasi("com.github.bumptech.glide:glide:4.11.0")
   annotationProcessor("com.github.bumptech.glide:compiler:4.11.0")
}

Secara default, proyek yang baru dibuat harus berisi MainActivity dan file layout activity_main.xml . Mari tambahkan beberapa tampilan ke dalamnya – satu TextView untuk judul dan satu ImageView untuk komik itu sendiri.

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:andro
   android:
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android: gravitasi = "pusat"
   android:orientation="vertical">

   <Tampilan Teks
       android:
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

   <Tampilan Gambar
       android:
       android:layout_width="match_parent"
       android:layout_height="wrap_content"/>

</LinearLayout>

Kemudian kita memerlukan beberapa representasi dari status aplikasi – itu bisa berupa memuat komik baru, menampilkannya atau kita mungkin mengalami kesalahan saat memuat.

 kelas tersegel Negara {
   Pemuatan objek : Status()
   kelas Sukses (hasil val: ComicModel) : State()
   Kesalahan objek: Status ()
}

Sekarang mari tambahkan ViewModel minimal menggunakan logika bisnis yang dibuat sebelumnya . Semua kelas dapat diimpor. MutableLiveData adalah bidang yang dapat diamati – tampilan akan mengamati perubahan dan memperbaruinya sendiri. viewModelScope adalah lingkup coroutine yang terikat dengan siklus hidup viewmodel – jika aplikasi ditutup, maka secara otomatis akan membatalkan tugas yang tertunda.

 kelas MainViewModel : ViewModel() {
   private val getLatestComicUseCase = GetLatestComicUseCase(XkcdApi())
   val comic = MutableLiveData<State<ComicModel>>()

   fun fetchComic() {
       viewModelScope.launch {
           komik.nilai = Status.Memuat()
           runCatching { getLatestComicUseCase.run() }
               .onSuccess { comic.value = State.Success(it) }
               .onFailure { comic.value = State.Error() }
       }
   }
}

Satu hal terakhir – MainActivity untuk menghubungkan semuanya.

 kelas MainActivity : AppCompatActivity(R.layout.activity_main) {
   private val viewModel: MainViewModel oleh lazy {
      ViewModelProvider(this).get(MainViewModel::class.java)
   }

   menimpa kesenangan onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      viewModel.comic.observe(ini) {
         kapan itu) {
            adalah Negara.Memuat -> {
               findViewById<TextView>(R.id.titleLabel).text = "Memuat"
            }
            adalah Negara. Sukses -> {
               findViewById<TextView>(R.id.titleLabel).text = it.result.title
               Meluncur.dengan(ini)
                  .load(itu.hasil.img)
                  .into(findViewById(R.id.image))
            }
            adalah Negara.Kesalahan -> {
               findViewById<TextView>(R.id.titleLabel).text = "Kesalahan"
            }
         }
      }
      viewModel.fetchComic()
   }
}

Itu saja, aplikasi Android sudah siap!

Aplikasi Android yang dikembangkan dengan KMM

UI sederhana untuk iOS

Semua hal di atas dilakukan di Android Studio, jadi untuk bagian ini mari beralih ke Xcode agar lebih nyaman. Untuk melakukan ini cukup buka Xcode dan pilih direktori iosApp – ini berisi proyek Xcode yang telah dikonfigurasi sebelumnya. Secara default proyek ini menggunakan SwiftUI untuk GUI jadi mari kita tetap menggunakannya demi kesederhanaan.

Hal pertama yang harus dilakukan adalah membuat logika dasar untuk mengambil data komik. Sama seperti sebelumnya, kita membutuhkan sesuatu untuk mewakili negara.

 enum Negara {
    pemuatan kasus
    kasus sukses(ComicModel)
    kesalahan kasus
}

Selanjutnya, mari kita siapkan ViewModel sekali lagi

 kelas ViewModel: ObservableObject {
    biarkan getLatesteComicUseCase = GetLatestComicUseCase(xkcdApi: XkcdApi())
        
    @Published var comic = State.loading
        
    init() {
        self.comic = .loading
        getLatestComicUseCase.run { fetchedComic, kesalahan dalam
            jika diambilComic != nil {
                self.comic = .success(fetchedComic!)
            } kalau tidak {
                self.comic = .error
            }
        }
    }
}

Dan, akhirnya, pemandangan.

Catatan: untuk mempermudah, saya menggunakan komponen SwiftUI RemoteImage untuk menampilkan gambar, sama seperti saya menggunakan Glide di Android.

 struct ContentView: Lihat {
 
    @ObservedObject private(set) var viewModel: ViewModel
    
    var body: beberapa Tampilan {
        tampilan komik()
    }
    --
    fungsi pribadi comicView() -> beberapa Tampilan {
        beralih viewModel.comic {
        kasus .loading:
            kembalikan AnyView(Teks("Memuat"))
        kasus .hasil (biarkan komik):
            kembalikan AnyView(VStack {
                Teks(comic.title)
                RemoteImage(url: comic.img)
            })
        kasus .kesalahan:
            kembalikan AnyView(Teks("Kesalahan"))
        }
    }
}

Dan hanya itu, aplikasi iOS juga siap!

Aplikasi iOS yang dikembangkan dengan KMM

Ringkasan

Terakhir, untuk menjawab pertanyaan dari judul – Apakah Kotlin Multiplatform adalah masa depan pengembangan lintas platform? - semua tergantung kebutuhan. Jika Anda ingin membuat aplikasi kecil yang identik untuk kedua platform seluler secara bersamaan, maka mungkin tidak, karena Anda harus memiliki pengetahuan yang diperlukan tentang pengembangan untuk kedua platform.

Melepaskan ikon produk

Kembangkan aplikasi Anda berikutnya dengan para ahli kami

Dapatkan penawaran

Namun, jika Anda sudah memiliki tim pengembang Android dan iOS dan ingin memberikan pengalaman pengguna terbaik, maka ini dapat mengurangi waktu pengembangan secara signifikan . Seperti pada contoh yang diberikan, berkat modul bersama, logika aplikasi diimplementasikan hanya sekali dan antarmuka pengguna dibuat dengan cara yang sepenuhnya spesifik untuk platform. Jadi mengapa tidak mencobanya? Seperti yang Anda lihat, mudah untuk memulai.

Ingin tahu tentang pengembangan lintas platform dari perspektif bisnis? Lihat artikel kami tentang Keuntungan Pengembangan Lintas-Platform.