Este Kotlin Multiplatform viitorul dezvoltării multiplatforme? Sfaturi despre cum să începeți

Publicat: 2021-01-29

În zilele noastre, putem observa o tendință în dezvoltarea mobilă de a lansa mai rapid aplicațiile. Au existat multe încercări de a reduce timpul de dezvoltare prin partajarea părților comune de cod între diferite platforme, cum ar fi Android și iOS. Unele soluții au câștigat deja popularitate, în timp ce altele sunt încă în curs de dezvoltare. Astăzi, aș dori să discut una dintre cele mai noi abordări din al doilea grup – Kotlin Multiplatform Mobile (KMM pe scurt).

Ce este Kotlin Multiplatform Mobile?

KMM este un SDK care urmărește în primul rând să partajeze logica de afaceri între platforme – partea care în majoritatea cazurilor trebuie să fie oricum aceeași. Acest lucru se realizează datorită unui set de compilatoare multiple pentru un modul partajat. De exemplu, Android target folosește o variantă Kotlin/JVM, iar pentru iOS există una Kotlin/Native. Un modul partajat poate fi apoi adăugat la proiectele tipice de aplicații native, iar dezvoltatorii responsabili pentru UI se pot concentra pe oferirea celei mai bune experiențe pentru utilizatori într-un mediu familiar pentru ei – Android Studio pentru Android și Xcode pentru iOS.

Kotlin Multiplatform vs Flutter

În prezent, una dintre cele mai populare soluții pentru dezvoltarea de aplicații multiplatformă este Flutter. Este axat pe regula „scrie o aplicație și rulează-o peste tot” – care funcționează, dar numai pentru aplicații simple. În cazuri reale, dezvoltatorii trebuie să scrie oricum cod nativ pentru fiecare platformă pentru a umple golurile , de exemplu, atunci când lipsește un plugin. Cu această abordare, aplicația arată la fel pe diferite platforme, ceea ce uneori este de dorit, dar în unele cazuri, poate încălca anumite linii directoare de proiectare.

Pictograma serviciilor de dezvoltare multiplatformă

Sunteți gata să vă creați propria aplicație?

Alege Flutter

Deși pot suna similar, Kotlin Multiplatform nu este o soluție multiplatformă - nu încearcă să reinventeze roata. Dezvoltatorii pot folosi în continuare instrumentele pe care le cunosc și le plac. Pur și simplu simplifică procesul de reutilizare a părților de cod care anterior ar fi trebuit scrise de mai multe ori, cum ar fi efectuarea de solicitări de rețea, stocarea datelor și a altor logici de afaceri.

Avantaje și dezavantaje ale Kotlin Multiplatform

Avantajele KMM :

  • Aplicația dezvoltată este 100% nativă pentru fiecare platformă – este ușor de integrat cu codul utilizat în prezent și bibliotecile terțelor părți
  • Ușor de utilizat – aproape toți dezvoltatorii Android folosesc deja Kotlin, așa că sunt necesare foarte puține cunoștințe suplimentare pentru ca aceștia să înceapă
  • Interfața de utilizare poate fi împărțită pentru fiecare platformă țintă – aplicația se va simți în concordanță cu orice ecosistem dat
  • Logica partajată permite dezvoltatorilor să adauge noi funcții și să repare erori pe ambele sisteme de operare în același timp

Contra KMM :

  • Multe componente sunt încă în stadiul Alpha/Beta și pot fi instabile sau se pot schimba în viitor

Ce companii folosesc KMM?

Potrivit site-ului oficial, companiile câștigă din ce în ce mai mult interes pentru această tehnologie, iar lista este din ce în ce mai lungă. Printre acestea, există mărci atât de cunoscute precum Autodesk, VMWare, Netflix sau Yandex.

Cum să începeți cu Kotlin Multiplatform?

Cel mai bun loc de scufundare pentru informații aprofundate este ghidul oficial, dar în acest articol, aș dori să arăt un exemplu destul de simplu, dar mai interesant decât doar un „Hello World”, care ar fi preluarea și afișarea aplicației. cea mai recentă benzi desenate de Randall Munroe (licențiat sub CC BY-NC 2.5) cu titlul de la xkcd.com API.

Caracteristici care trebuie acoperite:

  • Configurarea proiectului
  • Conectarea în rețea în modulul partajat
  • Interfață de utilizare simplă atât pentru Android, cât și pentru iOS

Notă: am vrut ca acest exemplu să fie la fel de ușor de citit atât pentru dezvoltatorii Android, cât și pentru iOS, așa că în unele locuri am omis în mod intenționat unele bune practici specifice platformei doar pentru a clarifica ce se întâmplă

Configurarea proiectului

În primul rând, asigurați-vă că aveți instalate cele mai recente versiuni de Android Studio și Xcode , deoarece ambele vor fi necesare pentru construirea acestui proiect. Apoi, în Android Studio, instalați pluginul KMM. Acest plugin simplifică o mulțime de lucruri – pentru a crea un proiect nou, faceți clic pe Creare proiect nou și selectați Aplicație KMM.

Creați un nou proiect Kotlin Multiplatform Mobile

După ce proiectul este creat, navigați la fișierul build.gradle.kts din directorul partajat . Aici trebuie să specificați toate dependențele necesare. În acest exemplu, vom folosi ktor pentru stratul de rețea, kotlinx.serialization pentru analizarea răspunsurilor json din backend și coroutine kotlin pentru a face totul asincron.

Pentru simplitate, mai jos ofer liste care arată toate dependențele care trebuie adăugate la cele deja prezente. Când adăugați dependențe, trebuie doar să sincronizați proiectul (va apărea o solicitare). Mai întâi, adăugați pluginul de serializare la secțiunea de pluginuri.

 pluginuri {
   kotlin ("plugin.serialization") versiunea "1.4.0"
}

Apoi adăugați dependențe.

 sourceSets {
   val commonMain prin obținerea {
       dependențe {
           implementare ("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
           implementare ("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt-2")

           implementare ("io.ktor:ktor-client-core:1.4.1")
           implementare ("io.ktor:ktor-client-json:1.4.1")
           implementare ("io.ktor:ktor-client-serialization:1.4.1")
       }
   }
   val androidMain obținând {
       dependențe {
           implementare ("io.ktor:ktor-client-android:1.4.1")
       }
   }
   val iosMain prin obținerea {
       dependențe {
           implementare ("io.ktor:ktor-client-ios:1.4.1")
       }
   }
}

De menționat că la momentul scrierii acestui articol, există unele probleme cu versiunea stabilă a bibliotecii coroutines pe iOS – de aceea versiunea folosită are sufixul native-mt-2 (care înseamnă native multithreading). Puteți verifica starea actuală a acestei probleme aici.

Conectarea în rețea în modulul partajat

În primul rând, avem nevoie de o clasă care să reprezinte răspunsul - acele câmpuri sunt prezente în json returnat de backend.

 import kotlinx.serialization.Serializable

@Serializabil
clasa de date XkcdResponse(
   img val: șir,
   titlu val: șir,
   ziua val: int,
   luna val: Int,
   anul val: int,
)

În continuare trebuie să creăm o clasă reprezentând API cu un client HTTP . În cazul în care nu am furnizat toate câmpurile prezente în json, putem folosi proprietatea ignoreUnknownKeys , astfel încât serializatorul să le poată ignora pe cele lipsă. Acest exemplu are un singur punct final reprezentat de o funcție suspendată. Acest modificator îi spune compilatorului că această funcție este asincronă. O voi descrie mai mult cu cod specific platformei.

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

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

   val privat httpClient = HttpClient() {
       instalați(JsonFeature) {
           serializator = KotlinxSerializer(
               kotlinx.serialization.json.Json {
                   ignoreUnknownKeys = adevărat
               }
           )
       }
   }

   suspendă distracția fetchLatestComic() =
       httpClient.get<XkcdResponse>(„$baseUrl/info.0.json”)

}

Când stratul nostru de rețea este gata, putem trece la nivelul de domeniu și putem crea o clasă reprezentând modelul local de date. În acest exemplu, am sărit mai multe câmpuri și am lăsat doar titlul benzii desenate și URL-ul imaginii.

 clasa de date ComicModel(
   val imageUrl: șir,
   titlu val: String
)

Ultima parte pentru acest strat este crearea unui caz de utilizare care va declanșa o solicitare de rețea și apoi va mapa răspunsul la modelul local.

 clasa GetLatestComicUseCase(val privat xkcdApi: XkcdApi) {
   suspend fun run() = xkcdApi.fetchLatestComic()
       .let { ComicModel(it.img, it.title) }
}

Interfață de utilizare simplă pentru Android

Este timpul să treceți la directorul androidApp - aici este stocată aplicația nativă Android. Mai întâi, trebuie să adăugăm câteva dependențe specifice Android la celălalt fișier build.gradle.kts aflat aici. Din nou, lista de mai jos arată doar dependențe care ar trebui adăugate celor deja prezente. Această aplicație va folosi arhitectura Model-View-ViewModel (primele două linii) și Glide pentru a încărca o imagine comică de la adresa URL returnată (al doilea rând)

 dependențe {
   implementare ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
   implementare ("androidx.lifecycle:lifecycle-livedata-ktx:2.2.0")
   implementare ("com.github.bumptech.glide:glide:4.11.0")
   annotationProcessor ("com.github.bumptech.glide:compiler:4.11.0")
}

În mod implicit, un proiect nou creat ar trebui să conțină MainActivity și fișierul său de aspect activity_main.xml . Să îi adăugăm câteva vizualizări – un TextView pentru titlu și unul ImageView pentru benzi desenate în sine.

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

   <TextView
       android:
       android:layout_width="wrap_content"
       android:layout_height="wrap_content”/>

   <ImageView
       android:
       android:layout_width="match_parent"
       android:layout_height="wrap_content"/>

</LinearLayout>

Apoi vom avea nevoie de o reprezentare a stării aplicației – poate fi fie încărcarea unei benzi desenate noi, fie afișarea acesteia, fie putem întâlni o eroare în timpul încărcării.

 clasă sigilată stat {
   Încărcare obiect: Stare()
   clasa Succes(rezultatul val: ComicModel) : State()
   Eroare obiect: Stare()
}

Acum să adăugăm un ViewModel minim folosind logica de afaceri creată anterior . Toate clasele pot fi importate. MutableLiveData este un câmp observabil – vizualizarea va observa modificările aduse acestuia și se va actualiza în consecință. viewModelScope este un domeniu de aplicare corelat legat de ciclul de viață al modelului de vizualizare - în cazul în care aplicația este închisă, aceasta va anula automat sarcinile în așteptare.

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

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

Un ultim lucru – MainActivity pentru a conecta totul.

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

   suprascrie distracție onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      viewModel.comic.observe(this) {
         atunci când) {
            este State.Loading -> {
               findViewById<TextView>(R.id.titleLabel).text = „Se încarcă”
            }
            este State.Success -> {
               findViewById<TextView>(R.id.titleLabel).text = it.result.title
               Glide.with(this)
                  .load(it.result.img)
                  .into(findViewById(R.id.image))
            }
            este State.Error -> {
               findViewById<TextView>(R.id.titleLabel).text = „Eroare”
            }
         }
      }
      viewModel.fetchComic()
   }
}

Gata, aplicația pentru Android este gata!

O aplicație Android dezvoltată cu KMM

Interfață de utilizare simplă pentru iOS

Totul de mai sus a fost făcut în Android Studio, așa că pentru această parte să trecem la Xcode pentru a o face mai convenabilă. Pentru a face acest lucru, deschideți Xcode și selectați directorul iosApp - acesta conține un proiect Xcode preconfigurat. În mod implicit, acest proiect folosește SwiftUI pentru GUI, așa că, de dragul simplității, să rămânem la el.

Primul lucru de făcut este să creați o logică de bază pentru a prelua date despre benzi desenate. La fel ca înainte, avem nevoie de ceva care să reprezinte statul.

 stare enumerare {
    încărcarea cazului
    caz de succes (ComicModel)
    eroare de caz
}

În continuare, să pregătim încă o dată un ViewModel

 clasa ViewModel: ObservableObject {
    let getLatesteComicUseCase = GetLatestComicUseCase(xkcdApi: XkcdApi())
        
    @Published var comic = State.loading
        
    init() {
        self.comic = .încărcare
        getLatestComicUseCase.run { fetchedComic, eroare în
            ifchedComic != nil {
                self.comic = .succes(fechedComic!)
            } altfel {
                self.comic = .eroare
            }
        }
    }
}

Și, în sfârșit, priveliștea.

Notă: pentru simplitate, am folosit componenta SwiftUI RemoteImage pentru a afișa imaginea, la fel cum am folosit Glide pe Android.

 struct ContentView: View {
 
    @ObservedObject private(set) var viewModel: ViewModel
    
    var body: some View {
        comicView()
    }
    --
    funcția privată comicView() -> unele View {
        comutați viewModel.comic {
        caz .încărcare:
            returnează AnyView(Text(„Se încarcă”))
        caz .rezultat(lasă comic):
            returnează AnyView(VStack {
                Text(comic.title)
                RemoteImage(url: comic.img)
            })
        caz .eroare:
            returnează AnyView(Text(„Eroare”))
        }
    }
}

Și gata, aplicația iOS este și ea gata!

O aplicație iOS dezvoltată cu KMM

rezumat

În cele din urmă, pentru a răspunde la întrebarea din titlu – Este Kotlin Multiplatform viitorul dezvoltării multiplatforme? – totul depinde de nevoi. Dacă doriți să creați o aplicație mică, identică pentru ambele platforme mobile în același timp, atunci probabil că nu, deoarece trebuie să aveți cunoștințele necesare privind dezvoltarea pentru ambele platforme.

Se lansează pictograma produsului

Dezvoltați-vă următoarea aplicație cu experții noștri

Obțineți o cotație

Cu toate acestea, dacă aveți deja o echipă de dezvoltatori Android și iOS și doriți să oferiți cea mai bună experiență de utilizare, atunci poate reduce semnificativ timpul de dezvoltare . Ca și în exemplul oferit, datorită unui modul partajat, logica aplicației a fost implementată o singură dată, iar interfața cu utilizatorul a fost creată într-un mod complet specific platformei. Deci de ce să nu încerci? După cum puteți vedea, este ușor să începeți.

Ești curios despre dezvoltarea multiplatformă din perspectiva afacerii? Consultați articolul nostru despre Avantajele dezvoltării pe mai multe platforme.