TWA 래퍼를 걷어내고 Compose Multiplatform 으로 다시 만들었다. 엔진·UI·모드 전부 commonMain 한 벌이라 Android 와 iOS 가 같은 코드를 쓴다. - engine/: 웹 JS 엔진을 Kotlin 으로 이식 (SRS+180 킥, 7-bag, T-spin, B2B, 콤보, All Clear, 점수·레벨). commonTest 28개 통과 - game/: 모드 규칙 + 중력/락딜레이/DAS/ARR 타이밍 - ui/: 네오브루탈 컴포넌트, 메인/솔로시트/인게임/결과/설정 - ui/Responsive.kt: 고정 해상도를 버리고 가용 크기에서 셀 크기·배율 계산. 폰 세로, 플립 초세로, 플립 커버(소형), 폴드 펼침, 태블릿/아이패드 가로 대응 - androidMain: resizeableActivity + configChanges 로 접기/펴기·회전 시 재시작 없음 - iosMain + iosApp/: MainViewController + SwiftUI 껍데기 + XcodeGen 설정 (실제 iOS 빌드는 macOS + Xcode 필요) - scripts/release.sh: 버전 상승 → 테스트 → 서명 빌드 → 태그 → Gitea 릴리스 자동화
110 lines
3.6 KiB
Kotlin
110 lines
3.6 KiB
Kotlin
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
|
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
import java.util.Properties
|
|
|
|
plugins {
|
|
alias(libs.plugins.kotlinMultiplatform)
|
|
alias(libs.plugins.androidApplication)
|
|
alias(libs.plugins.composeMultiplatform)
|
|
alias(libs.plugins.composeCompiler)
|
|
}
|
|
|
|
// ── 버전 관리 ────────────────────────────────────────────────────
|
|
// 기본값은 gradle.properties. CI/릴리스 스크립트는
|
|
// ./gradlew assembleRelease -PappVersionName=1.2.0 -PappVersionCode=7
|
|
// 처럼 덮어쓴다.
|
|
val appVersionName: String = (findProperty("appVersionName") as String?) ?: "0.0.1"
|
|
val appVersionCode: Int = ((findProperty("appVersionCode") as String?) ?: "1").toInt()
|
|
|
|
kotlin {
|
|
androidTarget {
|
|
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
|
compilerOptions { jvmTarget.set(JvmTarget.JVM_17) }
|
|
}
|
|
|
|
// iOS 타깃 — 실제 컴파일은 macOS + Xcode 에서만 가능하다.
|
|
// 리눅스에서는 설정만 되고 빌드 태스크를 실행하지 않는다.
|
|
listOf(iosX64(), iosArm64(), iosSimulatorArm64()).forEach { iosTarget ->
|
|
iosTarget.binaries.framework {
|
|
baseName = "ComposeApp"
|
|
isStatic = true
|
|
}
|
|
}
|
|
|
|
sourceSets {
|
|
commonMain.dependencies {
|
|
implementation(compose.runtime)
|
|
implementation(compose.foundation)
|
|
implementation(compose.material3)
|
|
implementation(compose.ui)
|
|
implementation(compose.components.resources)
|
|
implementation(libs.androidx.lifecycle.viewmodel)
|
|
}
|
|
commonTest.dependencies {
|
|
implementation(libs.kotlin.test)
|
|
}
|
|
androidMain.dependencies {
|
|
implementation(compose.preview)
|
|
implementation(libs.androidx.activity.compose)
|
|
}
|
|
}
|
|
}
|
|
|
|
android {
|
|
namespace = "kr.tkrmagid.tetrig"
|
|
compileSdk = 36
|
|
|
|
defaultConfig {
|
|
applicationId = "kr.tkrmagid.tetrig"
|
|
minSdk = 24
|
|
targetSdk = 36
|
|
versionCode = appVersionCode
|
|
versionName = appVersionName
|
|
}
|
|
|
|
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
|
sourceSets["main"].res.srcDirs("src/androidMain/res")
|
|
|
|
// keystore.properties 가 있으면 릴리스 서명을 붙인다. 없으면 unsigned.
|
|
val keystorePropsFile = rootProject.file("keystore.properties")
|
|
val keystoreProps = Properties().apply {
|
|
if (keystorePropsFile.exists()) keystorePropsFile.inputStream().use { load(it) }
|
|
}
|
|
if (keystoreProps.isNotEmpty()) {
|
|
signingConfigs {
|
|
create("release") {
|
|
storeFile = file(keystoreProps.getProperty("storeFile"))
|
|
storePassword = keystoreProps.getProperty("storePassword")
|
|
keyAlias = keystoreProps.getProperty("keyAlias")
|
|
keyPassword = keystoreProps.getProperty("keyPassword")
|
|
}
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
getByName("release") {
|
|
isMinifyEnabled = false
|
|
if (keystoreProps.isNotEmpty()) {
|
|
signingConfig = signingConfigs.getByName("release")
|
|
}
|
|
}
|
|
getByName("debug") {
|
|
applicationIdSuffix = ".debug"
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
targetCompatibility = JavaVersion.VERSION_17
|
|
}
|
|
|
|
packaging {
|
|
resources.excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
debugImplementation(compose.uiTooling)
|
|
}
|