From c88acf7405034997b85affacca92f2a21a12a868 Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Sun, 2 Jul 2023 04:08:27 -0400 Subject: [PATCH] Android: Gradle updates (#6653) * android: Migrate to Kotlin DSL Includes updates to all android dependencies/ndk (minus billing) and adds support for Kotlin, Android 13, and view binding. * android: Remove unused tests * android: Remove unused dependencies --- src/android/app/build.gradle | 192 ----------------- src/android/app/build.gradle.kts | 203 ++++++++++++++++++ .../citra_emu/ExampleInstrumentedTest.java | 26 --- src/android/app/src/main/AndroidManifest.xml | 3 +- .../org/citra/citra_emu/ExampleUnitTest.java | 17 -- src/android/build.gradle | 28 --- src/android/build.gradle.kts | 14 ++ src/android/settings.gradle | 1 - src/android/settings.gradle.kts | 23 ++ 9 files changed, 241 insertions(+), 266 deletions(-) delete mode 100644 src/android/app/build.gradle create mode 100644 src/android/app/build.gradle.kts delete mode 100644 src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java delete mode 100644 src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java delete mode 100644 src/android/build.gradle create mode 100644 src/android/build.gradle.kts delete mode 100644 src/android/settings.gradle create mode 100644 src/android/settings.gradle.kts diff --git a/src/android/app/build.gradle b/src/android/app/build.gradle deleted file mode 100644 index df7e43b5e..000000000 --- a/src/android/app/build.gradle +++ /dev/null @@ -1,192 +0,0 @@ -apply plugin: 'com.android.application' - -/** - * Use the number of seconds/10 since Jan 1 2016 as the versionCode. - * This lets us upload a new build at most every 10 seconds for the - * next 680 years. - */ -def autoVersion = (int) (((new Date().getTime() / 1000) - 1451606400) / 10) -def buildType -def abiFilter = "arm64-v8a" //, "x86" - -android { - compileSdkVersion 33 - ndkVersion "25.1.8937393" - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - lintOptions { - // This is important as it will run lint but not abort on error - // Lint has some overly obnoxious "errors" that should really be warnings - abortOnError false - - //Uncomment disable lines for test builds... - //disable 'MissingTranslation'bin - //disable 'ExtraTranslation' - } - - defaultConfig { - // TODO If this is ever modified, change application_id in strings.xml - applicationId "org.citra.citra_emu" - minSdkVersion 28 - targetSdkVersion 31 - versionCode autoVersion - versionName getVersion() - ndk.abiFilters abiFilter - } - - def keystoreFile = System.getenv('ANDROID_KEYSTORE_FILE') - if (keystoreFile != null) { - signingConfigs { - release { - storeFile file(keystoreFile) - storePassword System.getenv('ANDROID_KEYSTORE_PASS') - keyAlias System.getenv('ANDROID_KEY_ALIAS') - keyPassword System.getenv('ANDROID_KEYSTORE_PASS') - } - } - } - - applicationVariants.all { variant -> - buildType = variant.buildType.name // sets the current build type - } - - // Define build types, which are orthogonal to product flavors. - buildTypes { - - // Signed by release key, allowing for upload to Play Store. - release { - signingConfig keystoreFile != null ? signingConfigs.release : signingConfigs.debug - } - - // builds a release build that doesn't need signing - // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. - relWithDebInfo { - initWith release - applicationIdSuffix ".debug" - versionNameSuffix '-debug' - signingConfig signingConfigs.debug - minifyEnabled false - testCoverageEnabled false - debuggable true - jniDebuggable true - } - - // Signed by debug key disallowing distribution on Play Store. - // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. - debug { - // TODO If this is ever modified, change application_id in debug/strings.xml - applicationIdSuffix ".debug" - versionNameSuffix '-debug' - debuggable true - jniDebuggable true - } - } - - flavorDimensions "version" - productFlavors { - canary { - dimension "version" - applicationIdSuffix ".canary" - } - nightly { - dimension "version" - } - } - - externalNativeBuild { - cmake { - version "3.22.1" - path "../../../CMakeLists.txt" - } - } - namespace 'org.citra.citra_emu' - - defaultConfig { - externalNativeBuild { - cmake { - arguments "-DENABLE_QT=0", // Don't use QT - "-DENABLE_SDL2=0", // Don't use SDL - "-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work - - abiFilters abiFilter - } - } - } -} - -dependencies { - implementation "androidx.activity:activity:1.5.1" - implementation "androidx.fragment:fragment:1.5.5" - implementation 'androidx.appcompat:appcompat:1.5.1' - implementation 'androidx.exifinterface:exifinterface:1.3.4' - implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation "androidx.documentfile:documentfile:1.0.1" - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1' - implementation 'androidx.fragment:fragment:1.5.3' - implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0" - implementation 'com.google.android.material:material:1.6.1' - implementation 'androidx.core:core-splashscreen:1.0.0' - implementation "androidx.work:work-runtime:2.8.1" - - // For loading huge screenshots from the disk. - implementation 'com.squareup.picasso:picasso:2.71828' - - // Allows FRP-style asynchronous operations in Android. - implementation 'io.reactivex:rxandroid:1.2.1' - implementation 'org.ini4j:ini4j:0.5.4' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - - // Please don't upgrade the billing library as the newer version is not GPL-compatible - implementation 'com.android.billingclient:billing:2.0.3' - - // To use the androidx.test.core APIs - androidTestImplementation "androidx.test:core:1.5.0" - androidTestImplementation "androidx.test.ext:junit:1.1.5" -} - -def getVersion() { - def versionName = '0.0' - - try { - versionName = 'git describe --always --long'.execute([], project.rootDir).text - .trim() - .replaceAll(/(-0)?-[^-]+$/, "") - } catch (Exception) { - logger.error('Cannot find git, defaulting to dummy version number') - } - - if (System.getenv("GITHUB_ACTIONS") != null) { - def gitTag = System.getenv("GIT_TAG_NAME") - versionName = gitTag ?: versionName - } - - return versionName -} - -// Add task to each variant for copying output APKs to bundle directory. -android.applicationVariants.all { variant -> - def capitalizedName = variant.name.capitalize() - def copyTask = tasks.register("copyBundle${capitalizedName}") { - doLast { - project.copy { - from variant.outputs[0].outputFile.parentFile - include '*.apk' - into layout.buildDirectory.dir("bundle") - } - project.copy { - from layout.buildDirectory.dir("outputs/bundle/${variant.name}") - include '*.aab' - into layout.buildDirectory.dir("bundle") - } - } - } - tasks.named("bundle${capitalizedName}").get().configure { finalizedBy copyTask } -} diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts new file mode 100644 index 000000000..f92ce0301 --- /dev/null +++ b/src/android/app/build.gradle.kts @@ -0,0 +1,203 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +import android.databinding.tool.ext.capitalizeUS + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +/** + * Use the number of seconds/10 since Jan 1 2016 as the versionCode. + * This lets us upload a new build at most every 10 seconds for the + * next 680 years. + */ +val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toInt() +val abiFilter = listOf("arm64-v8a"/*, "x86", "x86_64"*/) + +@Suppress("UnstableApiUsage") +android { + namespace = "org.citra.citra_emu" + + compileSdkVersion = "android-33" + ndkVersion = "25.2.9519653" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + } + + buildFeatures { + viewBinding = true + } + + lint { + // This is important as it will run lint but not abort on error + // Lint has some overly obnoxious "errors" that should really be warnings + abortOnError = false + } + + defaultConfig { + // TODO If this is ever modified, change application_id in strings.xml + applicationId = "org.citra.citra_emu" + minSdk = 28 + targetSdk = 33 + versionCode = autoVersion + versionName = getGitVersion() + + ndk { + //noinspection ChromeOsAbiSupport + abiFilters += abiFilter + } + + externalNativeBuild { + cmake { + arguments( + "-DENABLE_QT=0", // Don't use QT + "-DENABLE_SDL2=0", // Don't use SDL + "-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work + ) + } + } + } + + val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE") + if (keystoreFile != null) { + signingConfigs { + create("release") { + storeFile = file(keystoreFile) + storePassword = System.getenv("ANDROID_KEYSTORE_PASS") + keyAlias = System.getenv("ANDROID_KEY_ALIAS") + keyPassword = System.getenv("ANDROID_KEYSTORE_PASS") + } + } + } + + // Define build types, which are orthogonal to product flavors. + buildTypes { + // Signed by release key, allowing for upload to Play Store. + release { + signingConfig = if (keystoreFile != null) { + signingConfigs.getByName("release") + } else { + signingConfigs.getByName("debug") + } + } + + // builds a release build that doesn't need signing + // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. + register("relWithDebInfo") { + initWith(getByName("release")) + applicationIdSuffix = ".debug" + versionNameSuffix = "-debug" + signingConfig = signingConfigs.getByName("debug") + isMinifyEnabled = false + isDebuggable = true + isJniDebuggable = true + } + + // Signed by debug key disallowing distribution on Play Store. + // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. + debug { + // TODO If this is ever modified, change application_id in debug/strings.xml + applicationIdSuffix = ".debug" + versionNameSuffix = "-debug" + isDebuggable = true + isJniDebuggable = true + } + } + + flavorDimensions.add("version") + productFlavors { + create("canary") { + dimension = "version" + applicationIdSuffix = ".canary" + } + + create("nightly") { + dimension = "version" + } + } + + externalNativeBuild { + cmake { + version = "3.22.1" + path = file("../../../CMakeLists.txt") + } + } +} + +dependencies { + implementation("androidx.activity:activity-ktx:1.7.2") + implementation("androidx.fragment:fragment-ktx:1.6.0") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("androidx.documentfile:documentfile:1.0.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1") + implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0") + implementation("com.google.android.material:material:1.9.0") + implementation("androidx.core:core-splashscreen:1.0.1") + implementation("androidx.work:work-runtime:2.8.1") + + // For loading huge screenshots from the disk. + implementation("com.squareup.picasso:picasso:2.71828") + + // Allows FRP-style asynchronous operations in Android. + implementation("io.reactivex:rxandroid:1.2.1") + + implementation("org.ini4j:ini4j:0.5.4") + implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0") + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") + + // Please don't upgrade the billing library as the newer version is not GPL-compatible + implementation("com.android.billingclient:billing:2.0.3") +} + +fun getGitVersion(): String { + var versionName = "0.0" + + try { + versionName = ProcessBuilder("git", "describe", "--always", "--long") + .directory(project.rootDir) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start().inputStream.bufferedReader().use { it.readText() } + .trim() + .replace(Regex("(-0)?-[^-]+$"), "") + } catch (e: Exception) { + logger.error("Cannot find git, defaulting to dummy version number") + } + + if (System.getenv("GITHUB_ACTIONS") != null) { + val gitTag = System.getenv("GIT_TAG_NAME") + versionName = gitTag ?: versionName + } + + return versionName +} + +android.applicationVariants.configureEach { + val variant = this + val capitalizedName = variant.name.capitalizeUS() + + val copyTask = tasks.register("copyBundle${capitalizedName}") { + doLast { + project.copy { + from(variant.outputs.first().outputFile.parentFile) + include("*.apk") + into(layout.buildDirectory.dir("bundle")) + } + project.copy { + from(layout.buildDirectory.dir("outputs/bundle/${variant.name}")) + include("*.aab") + into(layout.buildDirectory.dir("bundle")) + } + } + } + tasks.named("bundle${capitalizedName}").configure { finalizedBy(copyTask) } +} diff --git a/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java b/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java deleted file mode 100644 index b7c32a2f1..000000000 --- a/src/android/app/src/androidTest/java/org/citra/citra_emu/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.citra.citra_emu; - -import android.content.Context; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = ApplicationProvider.getApplicationContext(); - - assertEquals("org.citra.citra_emu", appContext.getPackageName()); - } -} diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index ec83e022e..3df8d45d6 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + diff --git a/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java b/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java deleted file mode 100644 index 4e4bb317f..000000000 --- a/src/android/app/src/test/java/org/citra/citra_emu/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.citra.citra_emu; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/src/android/build.gradle b/src/android/build.gradle deleted file mode 100644 index cfece1062..000000000 --- a/src/android/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - - repositories { - google() - mavenCentral() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:8.0.2' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - google() - mavenCentral() - jcenter() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts new file mode 100644 index 000000000..d2bde7bab --- /dev/null +++ b/src/android/build.gradle.kts @@ -0,0 +1,14 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id("com.android.application") version "8.0.2" apply false + id("com.android.library") version "8.0.2" apply false + id("org.jetbrains.kotlin.android") version "1.8.21" apply false +} + +tasks.register("clean").configure { + delete(rootProject.buildDir) +} diff --git a/src/android/settings.gradle b/src/android/settings.gradle deleted file mode 100644 index e7b4def49..000000000 --- a/src/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/src/android/settings.gradle.kts b/src/android/settings.gradle.kts new file mode 100644 index 000000000..e5b8fcabe --- /dev/null +++ b/src/android/settings.gradle.kts @@ -0,0 +1,23 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} + +@Suppress("UnstableApiUsage") +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + jcenter() + } +} + +include(":app")