Π¨Π°Π³ Π·Π° шагом: настройка окруТСния для Kotlin Multiplatform Mobile

Π¨Π°Π³ Π·Π° шагом: настройка окруТСния для Kotlin Multiplatform Mobile

03.04.2023
# Для_Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ²
Author avatar
АмСт Π₯Ρ‹Ρ€Ρ…Π°Ρ€Π°Android Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ

ΠŸΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π΅ Π½Π° Kotlin Multiplatform Mobile (КММ), Ρƒ Android Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° ΠΌΠΎΠ³ΡƒΡ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ трудности с быстрой настройкой окруТСния, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ сайт Kotlin Π½Π΅ прСдоставляСт ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹Ρ… инструкций. Π’ Π΄Π°Π½Π½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ рассмотрим этапы настройки ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. 

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ KMM

Кotlin Multiplatform Mobile (KMM) – это тСхнология кроссплатформСнной Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, которая позволяСт ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒ ΠΎΠ±Ρ‰ΡƒΡŽ бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ прилоТСния (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, запросы Π½Π° сСрвСр, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Ρ€Π°Π±ΠΎΡ‚Ρƒ с Π‘Π”) Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΈ ΠΏΡ€ΠΈ этом ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ UI.

Настройка Π½Π° Windows

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ КММ-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΉΡ‚ΠΈ Π² Android Studio, Π΄Π°Π»Π΅Π΅ ΠΏΡ€ΠΎΠΉΡ‚ΠΈ ΠΏΠΎ ΠΏΡƒΡ‚ΠΈ: File -> Settings -> Plugins, Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Marketplace ΠΈ ввСсти Π² ΠΏΠΎΠΈΡΠΊΠΎΠ²ΡƒΡŽ строку Π½Π°Π·Π²Π°Π½ΠΈΠ΅ инструмСнта. ПослС этого ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ»Π°Π³ΠΈΠ½.

KMM Для Windows

Когда ΠΏΠ»Π°Π³ΠΈΠ½ установлСн, ΠΏΡ€ΠΈ создании ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π²Π°ΠΌ Π±ΡƒΠ΄ΡƒΡ‚ доступны ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹. Π’Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ.

плагин KMM для Windows

ΠŸΡ€ΠΈ создании Π² ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ ios framework distribution Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ Regular Framework.

На этом этапС Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ΡΡ процСсс настройки, ΠΈ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ написанию ΠΊΠΎΠ΄Π°. Однако простота установки ΠΈΠ½ΠΎΠ³Π΄Π° ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ затруднСниям Π² Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ всСго Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Π° Π² КММ-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ….

MacOS

Для ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠΉ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с КММ Π½Π° macOS, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ спСцифичного ΠΊΠΎΠ΄Π° для ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹ iOS ΠΈ ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ ΠΎΡ‚Π»Π°Π΄ΠΊΡƒ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠΌΠ΅Ρ‚ΡŒ устройство ΠΎΡ‚ Apple.
Для Π½Π°Ρ‡Π°Π»Π° установки Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Homebrew – package manager, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ Π½Π΅Π΄ΠΎΡΡ‚Π°ΡŽΡ‰ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π½Π° macOS ΠΈ Linux. Для этого ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π½Π° ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ сайт ΠΈ ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ согласно инструкции, Π° Π·Π°Ρ‚Π΅ΠΌ Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π΅Ρ‘ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» – Π°Π½Π°Π»ΠΎΠ³ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки.

KMM Π½Π° MacOS

ПослС установки Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ввСсти ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ: brew install kdoctor. Π­Ρ‚ΠΎ инструмСнт ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ провСряСт Π½Π°Π»ΠΈΡ‡ΠΈΠ΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈ ΠΈΡ… ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½Ρ‹Π΅ вСрсии для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с КММ.

ПослС установки Π²Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ “kdoctor” ΠΈ Π΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ΡΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°. ΠžΡ‚Π²Π΅Ρ‚ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊΠΎΠ³ΠΎ Π²ΠΈΠ΄Π°:

KMM установка Π½Π° MacOS

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, инструмСнт провСряСт:

1) БистСму. Если ΠΎΠ½Π° Π½Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚, Ρ‚ΠΎ, ΡƒΠ²Ρ‹, Π½Π΅ ΡΡƒΠ΄ΡŒΠ±Π°.

2) НаличиС JDK.

3) НаличиС Android Studio ΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π° КММ (устанавливаСм, ΠΊΠ°ΠΊ Π² Windows).

4) НаличиС xCode.

5) НаличиС Cocoapods ΠΈ Π΅Π³ΠΎ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ с Ruby.

Π—Π΄Π΅ΡΡŒ описаны ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹, связанныС с ΠΏΠ΅Ρ€Π²Ρ‹ΠΌΠΈ Ρ‡Π΅Ρ‚Ρ‹Ρ€ΡŒΠΌΡ ΠΏΡƒΠ½ΠΊΡ‚Π°ΠΌΠΈ. Π― столкнулся с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°ΠΌΠΈ совмСстимости Cocoapods ΠΈ Ruby, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π΅ Π±Ρ‹Π»ΠΈ освСщСны Π² ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ. ΠŸΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ, ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ настройкС, Π΄Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ Cocoapods, Ruby, Π° Ρ‚Π°ΠΊΠΆΠ΅ инструмСнты rvm ΠΈ rbenv.

Ruby – это язык программирования, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для написания Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅.

Cocoapods – это ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ зависимостСй (dependency manager), написанный Π½Π° Ruby. Он позволяСт ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ зависимости ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° (ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎ gradle), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΏΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»ΡΡŽΡ‚ΡΡ Π² Podfile.

rvm ΠΈ rbenv – инструмСнты, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄Π°ΡŽΡ‚ Π½Π°ΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ вСрсиями Ruby, ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΠΈΠ»ΠΈ Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΡ‚ΠΊΠ°Ρ‚Ρ‹.

ПослС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ kdoctor ΠΏΡ€ΠΎΠ°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π» систСму, ΠΎΠ½ подскаТСт, ΠΊΠ°ΠΊΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ Ruby Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ (подсказки Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‚ΡΡ с *).

Для установки Π½ΡƒΠΆΠ½ΠΎΠΉ вСрсии Ruby Π²Π²Π΅Π΄ΠΈΡ‚Π΅ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ brew install ruby@2.7.

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ cocoapods, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ sudo gem install cocoapods ΠΈ sudo gem install cocoapods-generate.

ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Ссли ваша вСрсия Kotlin мСньшС 1.7.0, Ρ‚ΠΎ cocoapods-generate Π½Π΅ установится Π½Π° вСрсиях Ruby 3.0.0 ΠΈ Π²Ρ‹ΡˆΠ΅.

На Π΄Π°Π½Π½ΠΎΠΌ этапС Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ ошибки, связанныС с Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ вСрсий. Kotlin Multiplatform Mobile ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π° Π±ΠΎΠ»Π΅Π΅ Ρ€Π°Π½Π½ΠΈΡ… вСрсиях, Π° вСрсия Ruby, установлСнная ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠΉ (Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ Ruby, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ ruby -v).

Установка искомой вСрсии Ruby. Π—Π΄Π΅ΡΡŒ Ρƒ нас Π΅ΡΡ‚ΡŒ Π΄Π²Π° ΠΏΡƒΡ‚ΠΈ: rbenv ΠΈ rvm.

rbenv

1) УстанавливаСм с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Homebrew brew install rbenv ruby-build

2) Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ rbenv install –list, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ список доступных вСрсий, Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ Π½ΡƒΠΆΠ½ΡƒΡŽ

3) УстанавливаСм Π²Π΅Ρ€ΡΠΈΡŽ rbenv install <вСрсия>

4) Π‘Ρ‚Π°Π²ΠΈΠΌ Π΅Ρ‘ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ rbenv global <вСрсия>

rvm

1) Установка \curl -sSL https://get.rvm.io | bash -s stable

2) Бписок вСрсий rvm list known

3) Установка ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ вСрсии rvm install <вСрсия>

4) Установка вСрсии ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ rvm use <вСрсия> –default

Когда kdoctor ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ, Π²Ρ‹ ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅ ΠΆΠ΅Π»Π°Π½Π½ΡƒΡŽ надпись: “Your system is ready for Kotlin Multiplatform Mobile Development!”. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠ°Ρ‚ΡŒ ΠΊ созданию ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.

ИспользованиС Kotlin Multiplatform Wizard

Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Kotlin Multiplatform Wizard для создания КММ-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Π­Ρ‚ΠΎΡ‚ инструмСнт позволяСт автоматичСски ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π±Π°Π·ΠΎΠ²Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹ ΠΈ Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ (ΠΏΡ€ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌ создании ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° доступны Ρ‚ΠΎΠ»ΡŒΠΊΠΎ androidApp ΠΈ iosApp). ПослС создания ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ инструмСнта, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΊΠ°Ρ‡Π°Ρ‚ΡŒ Π°Ρ€Ρ…ΠΈΠ² ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Π΅Π³ΠΎ.

ΠžΠ±Π·ΠΎΡ€ созданного ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ с Ρ€Π΅ΠΆΠΈΠΌΠ° просмотра Android Π½Π° Ρ€Π΅ΠΆΠΈΠΌ просмотра Project послС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ всСх ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ доступ ΠΊΠΎ всСй Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.

ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ KMM

На Π΄Π°Π½Π½ΠΎΠΌ этапС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ отличаСтся ΠΎΡ‚ стандартного. ВмСсто ΠΎΠ΄Π½ΠΎΠ³ΠΎ модуля app Π±Ρ‹Π»ΠΎ создано Ρ‚Ρ€ΠΈ модуля: androidApp, iosApp ΠΈ shared. Если ΠΌΡ‹ ΠΎΡ‚ΠΊΡ€ΠΎΠ΅ΠΌ shared/src, Ρ‚ΠΎ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ Π΅Ρ‰Ρ‘ Ρ‚Ρ€ΠΈ модуля: androidMain, commonMain, iosMain.

Π”Π°Π²Π°ΠΉΡ‚Π΅ разбСрёмся, Ρ‡Ρ‚ΠΎ прСдставляСт ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ.

ΠœΠΎΠ΄ΡƒΠ»ΡŒ androidApp ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса (UI) ΠΈ Π»ΠΎΠ³ΠΈΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ…Π°Ρ€Π°ΠΊΡ‚Π΅Ρ€Π½Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Android ΠΈ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Ρ‹ Π½Π° Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ…. НапримСр, элСмСнты ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса Android View ΠΈΠ»ΠΈ Jetpack Compose, Π° Ρ‚Π°ΠΊΠΆΠ΅ Activity ΠΈΠ»ΠΈ Broadcast Receiver – Ρ‚Π°ΠΊΠΈΠ΅ сущности ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π² iOS Π² ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠΌ Π²ΠΈΠ΄Π΅. Π’ Ρ„Π°ΠΉΠ»Π΅ build.gradle.kts ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ зависимости, спСцифичныС Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Android, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Ρ‹, навигация ΠΈ Ρ‚.Π΄. Π’Π°ΠΊΠΆΠ΅ ΠΌΡ‹ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ shared ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ рассмотрСн Π΄Π°Π»Π΅Π΅: implementation(project(“:shared”)).

ΠœΠΎΠ΄ΡƒΠ»ΡŒ iosApp являСтся Π°Π½Π°Π»ΠΎΠ³ΠΎΠΌ androidApp для iOS. Для рСдактирования ΠΊΠΎΠ΄Π° Π² этом ΠΌΠΎΠ΄ΡƒΠ»Π΅ потрСбуСтся xCode. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π² xCode, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ срСду Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ “Open a project or file”, Π·Π°Ρ‚Π΅ΠΌ Π² Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Π² iosApp ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ„Π°ΠΉΠ» iosApp.xcodeproj.

Если Π²Ρ‹ создали ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π½Π° Windows, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΡˆΠ»ΠΈ Π½Π° macOS, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΡ‚ΠΎΠ»ΠΊΠ½ΡƒΡ‚ΡŒΡΡ с ошибкой “gradlew Permission denied”. Π§Ρ‚ΠΎΠ±Ρ‹ Π΅Ρ‘ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ, Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ Android Studio Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ: chmod +x gradlew.

Π’ ΠΌΠΎΠ΄ΡƒΠ»Π΅ shared ΠΌΡ‹ описываСм бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ прилоТСния, начиная ΠΎΡ‚ запросов ΠΊ сСрвСру Π΄ΠΎ вью-ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ. Основная Ρ‡Π°ΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ Π² commonMain.

созданиС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π° KMM

ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ, Π½ΠΎ ΠΈΠΌΠ΅Π΅Ρ‚ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ отличия Π² Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ.

НапримСр, ΠΏΡ€ΠΈ использовании вью-ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π² Android ΠΌΡ‹ наслСдуСмся ΠΎΡ‚ класса ViewModel(), Π½ΠΎ это Π½Π΅ трСбуСтся Π² iOS. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ ΠΌΡ‹ создаём Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ presentation Π² commonMain ΠΈ Π² Π½Π΅ΠΉ – абстрактный класс CommonViewModel. ΠœΡ‹ добавляСм ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово “expect” ΠΏΠ΅Ρ€Π΅Π΄ “abstract”, Ρ‡Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ каТдая ΠΈΠ· ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ (Π² Π΄Π°Π½Π½ΠΎΠΌ случаС androidMain ΠΈ iosMain) Π΄ΠΎΠ»ΠΆΠ½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ этот класс.

commonMain:

expect abstract class CommonViewModel()

Π’ этих модулях ΠΌΡ‹ Ρ‚ΠΎΠΆΠ΅ создаём ΠΏΠ°ΠΏΠΊΡƒ presentation ΠΈ абстрактный класс CommonViewModel, Π½ΠΎ expect замСняСм Π½Π° actual, ΠΎΠ·Π½Π°Ρ‡Π°ΡŽΡ‰Π΅Π΅, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹ΠΉ класс Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½. ΠŸΠ΅Ρ€Π΅Π΄ конструктором Ρ‚Π°ΠΊΠΆΠ΅ придётся ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово actual constructor. Π’ iosMain ΠΌΡ‹ оставим Ρ‚Π°ΠΊ, Π° Π² Android пронаслСдуСмся ΠΎΡ‚ ViewModel(). 

iosMain:

expect abstract class CommonViewModel() actual constructor()

androidMain:

actual abstract class CommonViewModel actual constructor() : ViewModel()

Π”ΠΎΠ»ΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ Ρ‚Π°ΠΊ:

Kotlin Multiplatform Mobile ΠΏΡ€ΠΎΠ΅ΠΊΡ‚

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ создаём вью-модСль, ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΎΡ‚ CommonViewModel ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ для ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ эту модСль.

ΠœΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ expect-actual ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΊΠ°ΠΊ интСрфСйсы. Expect – это интСрфСйс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ “Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ” (actual) Π² зависимости ΠΎΡ‚ контСкста.

Π’ shared ΠΌΠΎΠ΄ΡƒΠ»Π΅ Ρ‚Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ свой build.gradle.kts, Π³Π΄Π΅ ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ ΠΎΠ±Ρ‰ΠΈΠ΅ зависимости. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° sourceSets – здСсь ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ Π·Π½Π°ΠΊΠΎΠΌΡ‹Π΅ Π½Π°ΠΌ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ ΠΈ ΠΈΡ… ΠΊΠΎΠΏΠΈΠΈ с суффиксом Test.

созданиС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π° KMM

Зависимости, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π² commonMain, Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒΡΡ ΠΊΠΎ всСм ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°ΠΌ. Если ΠΌΡ‹ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°Π΅ΠΌ зависимости Π² androidMain, Ρ‚ΠΎ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ Android, Π° Ссли Π² iosMain, Ρ‚ΠΎ ΠΊ iosX64Main, iosArm64Main ΠΈ iosSimulatorArm64Main (ΠΊΠ°ΠΊ ΡƒΠΊΠ°Π·Π°Π½ΠΎ Π² ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ dependsOn()). ΠŸΡ€ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ Π½Π΅Ρ‚ ΠΏΡƒΡ‚Π°Π½ΠΈΡ†Ρ‹, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ всСгда ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚, ΠΊΠ°ΠΊ ΠΈΡ… слСдуСт ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ. Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ этапС ΠΌΡ‹ рассмотрим ΡƒΠ΄ΠΎΠ±Π½ΡƒΡŽ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΡŽ управлСния зависимостями Π² КММ.

По ΠΌΠ΅Ρ€Π΅ роста ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ увСличСния числа ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΡ‹Ρ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π² ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π΅ вСрсий ΠΈ ΠΈΠ·Π±Π΅ΠΆΠ°Π½ΠΈΠΈ дублирования. РСшСниСм этой Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΡ‚Π°Ρ‚ΡŒ созданиС ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ модуля для всСх зависимостСй. Π’ качСствС Ρ‚Π°ΠΊΠΎΠ³ΠΎ модуля ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΡΡ‚ΡƒΠΏΠ°Ρ‚ΡŒ buildSrc – ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Π°Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°, которая ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΊ Gradle-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ (само Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Ρ‚Π°ΠΊΠΆΠ΅ Π·Π°Ρ€Π΅Π·Π΅Ρ€Π²ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ Gradle-ΠΎΠΌ) ΠΈ ΠΏΡ€ΠΈ сборкС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° компилируСтся ΠΏΠ΅Ρ€Π²ΠΎΠΉ.

Для создания модуля buildSrc Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΠ°ΠΏΠΊΡƒ с ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΈ Π²Π½ΡƒΡ‚Ρ€ΠΈ Π½Π΅Ρ‘ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» build.gradle.kts с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΌ ΠΊΠΎΠ΄ΠΎΠΌ, послС Ρ‡Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, Π½Π°ΠΆΠ°Π² sync.

repositories {
    mavenCentral()
}

plugins {
    `kotlin-dsl`
}

Π—Π°Ρ‚Π΅ΠΌ Π² ΠΌΠΎΠ΄ΡƒΠ»Π΅ buildSrc Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ src/main/kotlin, которая появится Π² спискС доступных, Ссли синхронизация ΠΏΡ€ΠΎΡˆΠ»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ. ПослС этого Π²Π½ΡƒΡ‚Ρ€ΠΈ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ kotlin создайтС Ρ„Π°ΠΉΠ» с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Dependencies.kt. Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ всС зависимости ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.

Π’ Ρ„Π°ΠΉΠ»Π΅ создаём Ρ‚Ρ€ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°: Plugins, Versions, Deps (Π²Π½ΡƒΡ‚Ρ€ΠΈ Π½Π΅Π³ΠΎ для удобства ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Android ΠΈ Multiplatform) ΠΈ вставляСм ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄:

Π’ Plugins ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Π±Π°Π·ΠΎΠ²Ρ‹Π΅ ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹:

object Plugins {
   const val androidApp = "com.android.application"
   const val android = "android"
   const val multiplatform = "multiplatform"
   const val androidLib = "com.android.library"
}

Π’ Versions ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ вСрсии SDK, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΡ‹Ρ… ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ:

object Versions {

   // SDK
   const val compileSdk = 32
   const val targetSdk = 32
   const val minSdk = 21

   // Plugins
   const val android_version = "7.3.1"
   const val kotlin_version = "1.7.10"
   const val compose_version = "1.2.1"
   const val compose_activity_version = "1.5.1"

   // Coroutines
   const val coroutines_version = "1.6.4"
}

Π’ Deps прописываСм зависимости для Π½Π°ΡˆΠΈΡ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Ρ€Π°Π½Π΅Π΅ Π²Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ вСрсии:

Gradle-ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹ для Kotlin ΠΈ Android:

const val kotlin_gradle_plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin_version}"
const val android_gradle_plugin = "com.android.tools.build:gradle:${Versions.android_version}"

Зависимости для Android:

object Android {
    // Compose
    const val compose_ui = "androidx.compose.ui:ui:${Versions.compose_version}"
    const val compose_ui_tooling = "androidx.compose.ui:ui-tooling:${Versions.compose_version}"
    const val compose_ui_tooling_preview = "androidx.compose.ui:ui-tooling-preview:${Versions.compose_version}"
    const val compose_foundation = "androidx.compose.foundation:foundation:${Versions.compose_version}"
    const val compose_material = "androidx.compose.material:material:${Versions.compose_version}"
    const val compose_activity = "androidx.activity:activity-compose:${Versions.compose_activity_version}"
    // Coroutines
    const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines_version}"
}

Зависимости для КММ:

object Multiplatform {
    // Coroutines
    const val coroutines_core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines_version}"
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ зависимости, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈ создании ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, ΠΊΡ€ΠΎΠΌΠ΅ ΠΊΠΎΡ€ΡƒΡ‚ΠΈΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ взяты для дСмонстрации ΠΈΡ… Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π² shared ΠΌΠΎΠ΄ΡƒΠ»ΡŒ.

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ шаг – ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ build.gradle.kts Ρ„Π°ΠΉΠ»Ρ‹ нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. ΠžΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ Ρ„Π°ΠΉΠ» ΠΈ замСняСм строки Π½Π° наши ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅.

buildscript {
   repositories {
       gradlePluginPortal()
       google()
       mavenCentral()
   }
   dependencies {
       classpath(Deps.android_gradle_plugin)
       classpath(Deps.kotlin_gradle_plugin)
   }
}
Π’ build.gradle.kts (:shared) обновляСм ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹:

plugins {
    kotlin(Plugins.multiplatform)
    id(Plugins.androidLib)
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово kotlin ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для автоматичСского добавлСния прСфикса org.jetbrains.kotlin Π² Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°. Π’ΠΎ Π΅ΡΡ‚ΡŒ, выраТСния id(org.jetbrains.kotlin.multiplatform) ΠΈ kotlin(multiplatform) тоТдСствСнны.

Зависимости:

sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(Deps.Multiplatform.coroutines_core)
            }
        }
        ...
}

Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΊΠΎΡ€ΡƒΡ‚ΠΈΠ½ Π² commonMain, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π΅Ρ‘ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ для Android, Ρ‚Π°ΠΊ ΠΈ для iOS.

SDK: 

android {
   namespace = "com.example.newkmm"
   compileSdk = Versions.compileSdk
   defaultConfig {
       minSdk = Versions.minSdk
       targetSdk = Versions.targetSdk
   }
}

Π’ build.gradle.kts (:android):

plugins {
   id(Plugins.androidApp)
   kotlin(Plugins.android)
}

android {
    namespace = "com.example.newkmm.android"
    compileSdk = Versions.compileSdk
    defaultConfig {
        applicationId = "com.example.newkmm.android"
        minSdk = Versions.minSdk
        targetSdk = Versions.targetSdk
        versionCode = 1
        versionName = "1.0"
    }
    ...
}
dependencies {
    implementation(project(":shared"))
    implementation(Deps.Android.compose_ui)
    implementation(Deps.Android.compose_ui_tooling)
    implementation(Deps.Android.compose_ui_tooling_preview)
    implementation(Deps.Android.compose_foundation)
    implementation(Deps.Android.compose_material)
    implementation(Deps.Android.compose_activity)
}

Π‘ΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚. Π’ΠΎ Π²ΠΊΠ»Π°Π΄ΠΊΠ΅ Build убСТдаСмся, Ρ‡Ρ‚ΠΎ сначала Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ таски, связанныС с buildSrc, Π° Π·Π°Ρ‚Π΅ΠΌ таски основного ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. 

KMM ΠΏΡ€ΠΎΠ΅ΠΊΡ‚

КММ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ собираСтся дольшС, Ρ‡Π΅ΠΌ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Android ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, поэтому ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Π΅ΠΌ Π² gradle.properties ΠΈ добавляСм ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ строки:

org.gradle.caching=true   // 1

org.gradle.parallel=true  // 2

org.gradle.daemon=true    // 3

  1. Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅.
  2.  Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΡƒΡŽ сборку Π½Π΅ взаимосвязанных Π·Π°Π΄Π°Ρ‡, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Gradle выполняСт ΠΎΠ΄Π½Ρƒ Π·Π°Π΄Π°Ρ‡Ρƒ Π·Π° Ρ€Π°Π·. Π€ΠΈΡ‡Π° особСнно ΠΏΠΎΠ»Π΅Π·Π½Π° Π² КММ.
  3.  Gradle Daemon ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π²ΠΊΠ»ΡŽΡ‡Ρ‘Π½, Π½ΠΎ ΠΆΠ΅Π»Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π΅Π³ΠΎ явно. Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ занимаСтся ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ, ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³ΠΎΠΌ Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмы для опрСдСлСния Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… для Π±ΠΈΠ»Π΄Π° Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈ Π΄Π΅Ρ€ΠΆΠΈΡ‚ JVM Π² Β«ΠΏΡ€ΠΎΠ³Ρ€Π΅Ρ‚ΠΎΠΌΒ» состоянии.

Π’ процСссС ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠΈ систСмы ΠΊ кроссплатформСнной Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΡ‡Π΅ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ для Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅Π² macOS это ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π½ΡΡ‚ΡŒ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ большС Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, Ρ‡Π΅ΠΌ для ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Windows. Π’ Π΄Π°Π½Π½ΠΎΠΌ тСкстС ΠΎΠΏΠΈΡΡ‹Π²Π°ΡŽΡ‚ΡΡ инструмСнты, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для достиТСния Ρ†Π΅Π»ΠΈ, ΠΈ устраняСтся возмоТная ΠΏΡƒΡ‚Π°Π½ΠΈΡ†Π° с Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ вСрсий.

ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Π½Π° стартС ΠΈΠΌΠ΅Π΅Ρ‚ Π±ΠΎΠ»Π΅Π΅ ΡΠ»ΠΎΠΆΠ½ΡƒΡŽ Ρ„Π°ΠΉΠ»ΠΎΠ²ΡƒΡŽ структуру ΠΈ состоит ΠΈΠ· большСго числа ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ. Π’ shared ΠΌΠΎΠ΄ΡƒΠ»Π΅ описываСтся общая Π»ΠΎΠ³ΠΈΠΊΠ°, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ expect/actual Π² случаС отличия Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ сущностСй ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹.

Для Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ управлСния зависимостями ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Gradle Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ buildSrc, Π³Π΄Π΅ всС зависимости ΠΈ вСрсии хранятся Π² ΠΎΠ΄Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅, Ρ€Π°Π·Π±ΠΈΡ‚ΠΎΠΌ Π½Π° Π³Ρ€ΡƒΠΏΠΏΡ‹ для ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΡ Ρ‡ΠΈΡ‚Π°Π±Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΊΠΎΠ΄Π°. ΠŸΡ€ΠΈ сборкС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° этот ΠΌΠΎΠ΄ΡƒΠ»ΡŒ компилируСтся ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ, Ρ‡Ρ‚ΠΎ ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ процСсс.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ этап Π·Π°Π²Π΅Ρ€ΡˆΡ‘Π½, ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΊ написанию Π»ΠΎΠ³ΠΈΠΊΠΈ самого ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.

ΠŸΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°ΠΉΡΡ Π½Π° нас Π½Π° VC, Ρ…Π°Π±Ρ€Π΅, Π’Πš, Ρ‚Π°ΠΌ ΠΌΡ‹ ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ΅ΠΌ Π΅Ρ‰Π΅ большС ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠ³ΠΎ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Π°!
А Ссли Ρ…ΠΎΡ‡Π΅ΡˆΡŒ ΠΊΡ€ΡƒΡ‚ΠΎΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, напиши Π½Π°ΠΌ, ΠΈ ΠΌΡ‹ вмСстС ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π΅ΠΌ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅.

Author avatar
АмСт Π₯Ρ‹Ρ€Ρ…Π°Ρ€Π°Android Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ
ПодСлись ΡΡ‚Π°Ρ‚ΡŒΠ΅ΠΉ Π² соцмСдиа:
Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΡ‹Π΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ
Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Бколько стоит заказная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мобильного прилоТСния

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

Joy Dev Π² Ρ‚ΠΎΠΏΠ΅ Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³Π° Tagline 2023 срСди Π»ΡƒΡ‡ΡˆΠΈΡ… IT-ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΉ России

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

ΠŸΡ€ΠΈΠ·ΠΎΠ²ΠΎΠ΅ мСсто β€œReal Cosmetology” Π² конкурсС Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π—ΠΎΠ»ΠΎΡ‚ΠΎ Π² конкурсС Workspace Digital Awards 2023

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

Π₯Ρ€ΠΎΠ½ΠΎΡ„Π°Π³ΠΈ ΠΈ ΠΊΠ°ΠΊ ΠΈΡ… ΡƒΡΠΌΠΈΡ€ΠΈΡ‚ΡŒ

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

CΠΎΡ„Ρ‚ скилы: ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ большС Π·Π° красивыС Π³Π»Π°Π·Π°

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС

ΠŸΠ»ΠΎΡ‰Π°Π΄ΠΊΠΈ для видСостриминга: ΠΎΠ±Π·ΠΎΡ€-сравнСниС