feat(android): T-AND-001 工程骨架(AGP 8.7.3 + Gradle 8.9 + Compose)
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import java.util.Properties
|
||||
|
||||
// OpenDance Studio —— Android 辅助 App(应用模块)
|
||||
//
|
||||
// 契约:contracts/websocket-keypoints.md v0.1.0(本端为**发送方**)
|
||||
// contracts/skeleton-topology.md v0.1.0(MediaPipe 33 点)
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("org.jetbrains.kotlin.plugin.compose")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.opendance.studio"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.opendance.studio"
|
||||
minSdk = 29 // Android 10(文档 T-AND-009 验收要求 Android 10+)
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "0.1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
// 契约版本,供关于页与日志显示
|
||||
buildConfigField("String", "CONTRACT_VERSION", "\"0.1.0\"")
|
||||
buildConfigField("String", "WS_SUBPROTOCOL", "\"opendance.pose.v1\"")
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名配置:优先读取 keystore.properties(已被 .gitignore 忽略),
|
||||
* 否则读取环境变量;两者都没有时回退到 debug 签名。
|
||||
*
|
||||
* 这样 `./gradlew assembleRelease` 在没有任何私密文件的情况下也能产出**已签名**的
|
||||
* APK(用 debug key),便于 CI 与验收;正式发布必须提供自己的 keystore
|
||||
* (见 build/gen-keystore.sh 与 README.txt)。
|
||||
*/
|
||||
val keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
val keystoreProperties = Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystorePropertiesFile.inputStream().use { keystoreProperties.load(it) }
|
||||
}
|
||||
|
||||
fun signingValue(key: String, env: String): String? =
|
||||
keystoreProperties.getProperty(key) ?: System.getenv(env)
|
||||
|
||||
val releaseStoreFile = signingValue("storeFile", "KEYSTORE_PATH")
|
||||
val hasReleaseKeystore = releaseStoreFile != null && file(releaseStoreFile).exists()
|
||||
|
||||
signingConfigs {
|
||||
if (hasReleaseKeystore) {
|
||||
create("release") {
|
||||
storeFile = file(releaseStoreFile!!)
|
||||
storePassword = signingValue("storePassword", "KEYSTORE_PASSWORD")
|
||||
keyAlias = signingValue("keyAlias", "KEY_ALIAS")
|
||||
keyPassword = signingValue("keyPassword", "KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
isMinifyEnabled = false
|
||||
// debug 保留全部 ABI,方便在模拟器(x86_64)上调试
|
||||
ndk {
|
||||
abiFilters.clear()
|
||||
abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"))
|
||||
}
|
||||
}
|
||||
release {
|
||||
// 发布包只打包真实手机用得到的 ABI。
|
||||
// x86/x86_64 仅供模拟器使用,却占掉约 27 MB(几乎是发布包的一半),
|
||||
// 对真机用户纯属浪费。
|
||||
ndk {
|
||||
abiFilters.clear()
|
||||
abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a"))
|
||||
}
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro",
|
||||
)
|
||||
signingConfig = if (hasReleaseKeystore) {
|
||||
signingConfigs.getByName("release")
|
||||
} else {
|
||||
// 回退:用 debug 签名,保证 CI 上 assembleRelease 也能产出已签名 APK
|
||||
signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
packaging {
|
||||
resources {
|
||||
excludes += setOf(
|
||||
"/META-INF/{AL2.0,LGPL2.1}",
|
||||
"/META-INF/DEPENDENCIES",
|
||||
"/META-INF/LICENSE*",
|
||||
"/META-INF/NOTICE*",
|
||||
)
|
||||
}
|
||||
// MediaPipe 的 .task 模型必须保持不压缩,否则运行时按文件路径读取会失败
|
||||
androidResources {
|
||||
noCompress += "task"
|
||||
}
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests.isReturnDefaultValues = true
|
||||
}
|
||||
|
||||
lint {
|
||||
abortOnError = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// ---- Android 基础 ----
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.6")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6")
|
||||
implementation("androidx.activity:activity-compose:1.9.2")
|
||||
|
||||
// ---- Compose ----
|
||||
val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
|
||||
implementation(composeBom)
|
||||
androidTestImplementation(composeBom)
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
|
||||
// ---- CameraX(T-AND-002)----
|
||||
val cameraX = "1.4.0"
|
||||
implementation("androidx.camera:camera-core:$cameraX")
|
||||
implementation("androidx.camera:camera-camera2:$cameraX")
|
||||
implementation("androidx.camera:camera-lifecycle:$cameraX")
|
||||
implementation("androidx.camera:camera-view:$cameraX")
|
||||
|
||||
// ---- MediaPipe Pose 端侧推理(T-AND-003)----
|
||||
implementation("com.google.mediapipe:tasks-vision:0.10.35")
|
||||
|
||||
// ---- WebSocket 推流(T-AND-005)----
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
|
||||
// ---- 权限 ----
|
||||
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
|
||||
|
||||
// ---- 单元测试(T-AND-004 等纯逻辑,跑在 JVM 上,无需设备)----
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test:2.0.21")
|
||||
|
||||
androidTestImplementation("androidx.test.ext:junit:1.2.1")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
}
|
||||
Reference in New Issue
Block a user