2. O que é Kotlin Multiplatform?
• O Kotlin Multiplatform (ou simplesmente KMP) é uma tecnologia
desenvolvida pela Jetbrains para desenvolvimento de aplicações multi-
plataforma.
• Isso signi
fi
ca que é possível compartilhar código entre várias plataformas
(incluindo a parte do servidor)
3.
4. Cross-Platform ou Nativo? E agora?
• Com o KMP você pode ter OS DOIS! Cross-Platform E Nativo. É possível:
1. compartilhar parte da lógica de negócio e deixar a UI nativa;
2. compartilhar toda a lógica de negócio e deixar a UI nativa;
3. ou compartilhar a lógica de negócio E a UI.
10. APIs : Jetpack Compose x Compose Multiplatform
• Compose Multiplatform APIs são quase as mesmas das API de Jetpack
Compose
• Então todo o seu conhecimento em Jetpack Compose pode ser
reaproveitado
13. https://www.jetbrains.com/
fl
eet
• Fleet está disponível para
Windows, Mac and Linux
• Permite criar uma sessão
colaborativa com outro dev.
• Code completion e Refactoring
para código Swift
• Cross-Language navigation
(Kotlin <-> Swift)
• Cross-Language debugging
(Kotlin <-> Swift)
• Free durante o public preview
15. Estrutura do Projeto
• composeApp
• commonMain: código comum compartilhado entre as
plataformas. Ex.: expect declarations, ou de
fi
nição de
interfaces entre plataformas. As únicas dependências são
bibliotecas multi-plataforma.
• androidMain: implementação especí
fi
ca para Android (actual
functions e implementação de interface especí
fi
ca para
Android)
• iosMain: implementação especí
fi
ca para iOS (actual functions
e implementação de interface especí
fi
ca para Android).
• iosApp
18. List of Books
Books List
View Model
https://github.com/nglauber/dominando_android3/
blob/master/livros_novatec.json
19. Dependências
• Ktor para requisições web (https://github.com/ktorio/ktor)
• Voyager implementar View Model e Navegação (https://github.com/
adrielcafe/voyager)
• Kamel para carregamento de imagens (https://github.com/Kamel-Media/
Kamel)
22. O projeto
• Mostrar o JSON que será consumido (https://raw.githubusercontent.com/
nglauber/dominando_android3/master/livros_novatec.json)
23. Data Classes
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class Publisher(
@SerialName("novatec")
val categories: List<Category>
)
@Serializable
data class Category(
@SerialName("categoria")
val name: String,
@SerialName("livros")
val books: List<Book>
)
@Serializable
data class Book(
@SerialName("ano")
val year: Int,
@SerialName("autor")
val author: String,
@SerialName("capa")
val coverUrl: String,
@SerialName("paginas")
val pages: Int,
@SerialName("titulo")
val title: String
)
24. 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()
}
}
override fun onDispose() {
super.onDispose()
httpClient.close()
}
private suspend fun loadPublisher(): Publisher {
return try {
httpClient.get(jsonUrl).body()
} catch (e: NoTransformationFoundException) {
val jsonString = httpClient.get(jsonUrl).body<String>()
Json.decodeFromString(jsonString)
}
}
}
Solução técnica adaptativa…🤭
25. ViewModel e UI State
data class BooksListUiState(
val books: List<Book>
)
class BooksListViewModel : ScreenModel {
private val _uiState = MutableStateFlow(BooksListUiState(emptyList()))
val uiState: StateFlow<BooksListUiState> = _uiState.asStateFlow()
init {
updateBookList()
}
fun updateBookList() {
screenModelScope.launch {
val publisher = loadPublisher()
val books = publisher.categories.flatMap { it.books }
_uiState.update {
it.copy(books = books)
}
}
}
...
}
26. ViewModel e UI State
data class BooksListUiState(
val books: List<Book> = emptyList(),
)
class BooksListViewModel : StateScreenModel<BooksListUiState>(
BooksListUiState(emptyList())
) {
init {
updateBookList()
}
fun updateBookList() {
screenModelScope.launch {
val publisher = loadPublisher()
val books = publisher.categories.flatMap { it.books }
mutableState.update {
it.copy(books = books)
}
}
}
...
}
27. class BooksListScreen : Screen {
@Composable
override fun Content() {
val viewModel = rememberScreenModel {
BooksListViewModel()
}
val uiState by viewModel.state.collectAsState()
LazyColumn {
items(uiState.books) {
Text(it.title)
}
}
}
}
Tela de listagem de livros
@Composable
fun App() {
MaterialTheme {
Navigator(BooksListScreen())
}
}
28. 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}")
}
}
}
29. 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)
categories.flatMap { it.books }
else
categories.filter { it.name == selectedCategory }
.flatMap { it.books }
}
fun updateBookList() {
screenModelScope.launch {
val publisher = loadPublisher()
mutableState.update {
it.copy(publisher = publisher)
}
}
}
fun selectCategory(category: String) {
mutableState.update { state ->
if (state.selectedCategory == category) {
state.copy(selectedCategory = null)
} else {
state.copy(selectedCategory = category)
}
}
}
45. Referências
• The state of Kotlin Multiplatform (https://www.youtube.com/watch?
v=bz4cQeaXmsI)
• 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)