Seu Primeiro App Android e iOS Com Compose Multiplatform
Seu Primeiro App Android e iOS Com Compose Multiplatform
Seu Primeiro App Android e iOS Com Compose Multiplatform
Nelson Glauber
Android GDE
@nglauber
O que é Kotlin Multiplatform?
• Cross-Language navigation
(Kotlin <-> Swift)
• Cross-Language debugging
(Kotlin <-> Swift)
• iosApp
fi
fi
fi
fi
fi
Estrutura do Projeto
https://github.com/nglauber/dominando_android3/
blob/master/livros_novatec.json
Dependências
[versions]
...
ktor = "2.3.6"
voyager = "1.0.0"
kamel = "0.8.3"
[libraries]
...
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
cafe-adriel-voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
cafe-adriel-voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
kamel = { module = "media.kamel:kamel-image", version.ref = "kamel" }
[plugins]
...
kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}
composeApp/build.gradle.kts
plugins {
...
alias(libs.plugins.kotlinxSerialization)
}
kotlin {
...
sourceSets {
androidMain.dependencies {
...
implementation(libs.ktor.client.okhttp)
}
iosMain.dependencies {
implementation(libs.ktor.client.darwin)
}
commonMain.dependencies {
...
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.cafe.adriel.voyager.navigator)
implementation(libs.cafe.adriel.voyager.screenmodel)
implementation(libs.kamel)
}
}
}
O projeto
• Mostrar o JSON que será consumido (https://raw.githubusercontent.com/
nglauber/dominando_android3/master/livros_novatec.json)
Data Classes
import kotlinx.serialization.SerialName @Serializable
import kotlinx.serialization.Serializable data class Book(
@SerialName("ano")
@Serializable val year: Int,
data class Publisher( @SerialName("autor")
@SerialName("novatec") val author: String,
val categories: List<Category> @SerialName("capa")
) val coverUrl: String,
@SerialName("paginas")
val pages: Int,
@Serializable @SerialName("titulo")
data class Category( val title: String
@SerialName("categoria") )
val name: String,
@SerialName("livros")
val books: List<Book>
)
ViewModel e Networking
class BooksListViewModel: ScreenModel {
private val jsonUrl = "https://raw.githubusercontent.com/nglauber/dominando_android3/master/
livros_novatec.json"
private val httpClient = HttpClient {
install(ContentNegotiation) {
json()
}
}
init {
updateBookList()
}
fun updateBookList() {
screenModelScope.launch {
val publisher = loadPublisher()
val books = publisher.categories.flatMap { it.books }
_uiState.update {
it.copy(books = books)
}
}
}
...
}
ViewModel e UI State
data class BooksListUiState(
val books: List<Book> = emptyList(),
)
fun updateBookList() {
screenModelScope.launch {
val publisher = loadPublisher()
val books = publisher.categories.flatMap { it.books }
mutableState.update {
it.copy(books = books)
}
}
}
...
}
Tela de listagem de livros
class BooksListScreen : Screen {
@Composable
override fun Content() {
val viewModel = rememberScreenModel {
BooksListViewModel()
}
val uiState by viewModel.state.collectAsState()
LazyColumn {
items(uiState.books) {
Text(it.title)
}
}
}
}
@Composable
fun App() {
MaterialTheme {
Navigator(BooksListScreen())
}
}
Tela de listagem de livros
@Composable
fun BookListItem(book: Book) {
Row(Modifier.padding(8.dp)) {
KamelImage(
resource = asyncPainterResource(book.coverUrl),
contentDescription = "Capa do livro ${book.title}",
modifier = Modifier.weight(.3f).aspectRatio(3 / 4f)
)
Spacer(Modifier.width(8.dp))
Column(Modifier.weight(.7f)) {
Text(book.title, style = MaterialTheme.typography.h6)
Text(book.author)
Text("Ano: ${book.year} | Pages: ${book.pages}")
}
}
}
Filtrando os resultados
data class BooksListUiState(
val publisher: Publisher = Publisher(emptyList()),
val selectedCategory: String? = null,
) {
val categories: List<Category> = publisher.categories
val books: List<Book> =
if (selectedCategory == null) fun updateBookList() {
categories.flatMap { it.books } screenModelScope.launch {
else val publisher = loadPublisher()
categories.filter { it.name == selectedCategory } mutableState.update {
.flatMap { it.books } it.copy(publisher = publisher)
} }
}
}
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
Column {
Text(book.title)
Text(book.author)
Button(onClick = {
navigator.pop()
}) {
Text("Voltar") @Composable
} fun BookListItem(book: Book) {
} val navigator = LocalNavigator.currentOrThrow
} Row(
} Modifier.padding(8.dp).clickable {
navigator.push(BooksDetailsScreen(book))
},
) { ...
Google Libs
• Annotations
• Collections
• Paging
github.com/terrakok/kmp-awesome
Navigation
• Voyager (https://github.com/adrielcafe/voyager)
• PreCompose (https://github.com/Tlaster/PreCompose)
Resource Management and more…
• Permissions (https://github.com/icerockdev/moko-permissions)
• MVVM (https://github.com/icerockdev/moko-mvvm)
• Resources (https://github.com/icerockdev/moko-resources)
• Biometry (https://github.com/icerockdev/moko-biometry)
• Media (https://github.com/icerockdev/moko-media)
• Geolocation (https://github.com/icerockdev/moko-geo)
Image Loading
• Kamel (https://github.com/Kamel-Media/Kamel)
• Ktor (https://github.com/ktorio/ktor)
• Ktor t (https://github.com/Foso/Ktor t)
fi
fi
Persistence
• SQLDelight (https://github.com/cashapp/sqldelight)
• Kstore (https://github.com/xxfast/kstore)
• Getting Started With KMP: Build Apps for iOS and Android With Shared Logic
and Native UIs (https://www.youtube.com/watch?v=zE2LIAUisRI)
• Build Apps for iOS, Android, and Desktop With Compose Multiplatform
(https://www.youtube.com/watch?v=IGuVIRZzVTk)
• Build an iOS & Android app in 100% Kotlin with Compose Multiplatform
(https://www.youtube.com/watch?v=5_W5YKPShZ4)
Obrigado! Nelson Glauber
Android GDE
Dúvidas? @nglauber