import com.google.protobuf.gradle.* import org.gradle.process.ExecOperations import java.io.ByteArrayOutputStream plugins { id("com.android.application") id("com.google.protobuf") } // Utility function used to get the git version // All the below replaces the following "gladed.androidgitversion" config: // configure { // codeFormat = "MNNPPBBBB" // format = "%tag%%-count%%-branch%%-dirty%" // prefix = "v" // Only tags beginning with v are considered. // untrackedIsDirty = false // } fun ProviderFactory.git(vararg args: String): String { val result = exec { commandLine("git", *args) isIgnoreExitValue = true } return result.standardOutput.asText.get().trim() } val gitTag = providers.git("describe", "--tags", "--match", "v*", "--abbrev=0") .ifEmpty { "v0.0.0" } val commitsSinceTag = providers.git( "rev-list", "$gitTag..HEAD", "--count" ).toIntOrNull() ?: 0 val branchName = providers.git( "rev-parse", "--abbrev-ref", "HEAD" ).replace("/", "-") val isDirty = providers.git("status", "--porcelain") .lineSequence() .any { it.isNotBlank() && !it.startsWith("??") } // untrackedIsDirty = false val versionParts = gitTag .removePrefix("v") .split(".") .mapNotNull { it.toIntOrNull() } // Ensure we have at least 3 components by padding with 0 val major = versionParts.getOrElse(0) { 0 } val minor = versionParts.getOrElse(1) { 0 } val patch = versionParts.getOrElse(2) { 0 } val gitVersionName = if (commitsSinceTag == 0) gitTag else buildString { append(gitTag) append("-") append(commitsSinceTag) append("-") append(branchName) if (isDirty) append("-dirty") } val gitVersionCode = major * 100_000_000 + minor * 1000_000 + patch * 10_000 + commitsSinceTag dependencies { // 1.6.1 is the newest version we can use that won't complain about minSdk version, // and also doesn't collide kotlin versions with com.gladed.androidgitversion. // Will replace with a different plugin soon. implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.documentfile:documentfile:1.1.0") implementation("com.google.protobuf:protobuf-javalite:4.33.5") } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.25.3" } generateProtoTasks { all().forEach { task -> task.builtins { register("java") { option("lite") } } } } } android { flavorDimensions.add("variant") namespace = "org.ppsspp.ppsspp" signingConfigs { getByName("debug") { storeFile = file("debug.keystore") } create("optimized") { storeFile = file("debug.keystore") } if (project.hasProperty("RELEASE_STORE_FILE")) { create("release") { storeFile = file(project.property("RELEASE_STORE_FILE") as String) storePassword = project.property("RELEASE_STORE_PASSWORD") as String keyAlias = project.property("RELEASE_KEY_ALIAS") as String keyPassword = project.property("RELEASE_KEY_PASSWORD") as String } } } compileSdk = 36 ndkVersion = "29.0.14206865" compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } lint { baseline = file("lint-baseline.xml") } defaultConfig { applicationId = "org.ppsspp.ppsspp" // Access the git version info via the extension if (gitVersionName != "unknown") { println("INFO: Overriding Android Version Name, Code: $gitVersionName $gitVersionCode") versionName = gitVersionName versionCode = gitVersionCode } else { println("(not using these:) Android Version Name, Code: $gitVersionName $gitVersionCode") } file("versionname.txt").writeText(gitVersionName) file("versioncode.txt").writeText(gitVersionCode.toString()) minSdk = 21 targetSdk = 36 if (project.hasProperty("ANDROID_VERSION_CODE") && project.hasProperty("ANDROID_VERSION_NAME")) { versionCode = (project.property("ANDROID_VERSION_CODE") as String).toInt() versionName = project.property("ANDROID_VERSION_NAME") as String } } buildTypes { getByName("debug") { isMinifyEnabled = false isJniDebuggable = true signingConfig = signingConfigs.getByName("debug") } create("optimized") { isMinifyEnabled = false isJniDebuggable = true signingConfig = signingConfigs.getByName("debug") } getByName("release") { isMinifyEnabled = false if (project.hasProperty("RELEASE_STORE_FILE")) { signingConfig = signingConfigs.getByName("release") } else { println("WARNING: RELEASE_STORE_FILE is missing. Release builds will be unusable.") } } } externalNativeBuild { cmake { path = file("../CMakeLists.txt") } } packaging { jniLibs.useLegacyPackaging = true } sourceSets { getByName("main") { manifest.srcFile("AndroidManifest.xml") res.directories.add("res") java.directories.add("src") aidl.directories.add("src") resources.directories.add("src") assets.directories.add("../assets") } create("normal") { res.directories.add("normal/res") } create("gold") { res.directories.add("gold/res") } create("vr") { res.directories.add("normal/res") manifest.srcFile("VRManifest.xml") } create("legacy") { res.directories.add("legacy/res") } } productFlavors { create("normal") { applicationId = "org.ppsspp.ppsspp" dimension = "variant" externalNativeBuild { cmake { // **FIXED**: Using simple "listOf" arguments.addAll(listOf( "-DANDROID=true", "-DANDROID_PLATFORM=android-21", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_CPP_FEATURES=", "-DANDROID_STL=c++_shared" )) } } ndk { abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86_64")) // debugSymbolLevel = "FULL" // These don't actually help much in the Google Play crash report. We do still have symbols locally. } } create("gold") { applicationId = "org.ppsspp.ppssppgold" dimension = "variant" externalNativeBuild { cmake { arguments.addAll(listOf( "-DANDROID=true", "-DANDROID_PLATFORM=android-21", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_CPP_FEATURES=", "-DANDROID_STL=c++_shared", "-DGOLD=TRUE" )) } } ndk { abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86_64")) // debugSymbolLevel = "FULL" } } create("legacy") { applicationId = "org.ppsspp.ppsspplegacy" dimension = "variant" targetSdk = 29 // To avoid scoped storage, which is the point of the legacy APK externalNativeBuild { cmake { arguments.addAll(listOf( "-DANDROID=true", "-DANDROID_PLATFORM=android-21", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_CPP_FEATURES=", "-DANDROID_STL=c++_shared", "-DANDROID_LEGACY=TRUE" )) } } ndk { abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a")) // debugSymbolLevel = "FULL" } } create("vr") { applicationId = "org.ppsspp.ppssppvr" dimension = "variant" targetSdk = 29 // To avoid scoped storage, which doesn't work properly on Oculus externalNativeBuild { cmake { arguments.addAll(listOf( "-DANDROID=true", "-DANDROID_PLATFORM=android-21", "-DANDROID_TOOLCHAIN=clang", "-DANDROID_CPP_FEATURES=", "-DANDROID_STL=c++_shared", "-DOPENXR=TRUE", "-DANDROID_LEGACY=TRUE" )) } } ndk { abiFilters.addAll(listOf("arm64-v8a")) } } } buildFeatures { aidl = true buildConfig = true } } androidComponents { beforeVariants(selector().all()) { variantBuilder -> // **FIXED**: Using simple "setOf" val enabledVariants = setOf( "normalDebug", "normalOptimized", "normalRelease", "goldDebug", "goldRelease", "vrDebug", "vrOptimized", "vrRelease", "legacyDebug", "legacyOptimized", "legacyRelease" ) variantBuilder.enable = variantBuilder.name in enabledVariants } } /* afterEvaluate { android.sourceSets.getByName("main").assets.srcDirs.forEach { println(it) } }*/ // Use the below to get a lot of deprecation warnings. // Not really useful to fix most of them though, as the old paths are often needed to support // old Android versions. /* tasks.withType { options.compilerArgs.addAll(listOf("-Xlint:deprecation")) } */