diff --git a/.ci/android/build.sh b/.ci/android/build.sh index 836faa38d5..07cda2829f 100755 --- a/.ci/android/build.sh +++ b/.ci/android/build.sh @@ -1,21 +1,121 @@ -#!/bin/bash -e +#!/bin/sh -e # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -export NDK_CCACHE=$(which ccache) +NUM_JOBS=$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2) +export CMAKE_BUILD_PARALLEL_LEVEL="${NUM_JOBS}" +ARTIFACTS_DIR="$PWD/artifacts" -if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then +: "${CCACHE:=false}" +RETURN=0 + +usage() { + cat < Build flavor (variable: TARGET) + Valid values are: legacy, optimized, standard, chromeos + Default: standard + -b, --build-type Build type (variable: TYPE) + Valid values are: Release, RelWithDebInfo, Debug + Default: Debug + +Extra arguments are passed to CMake (e.g. -DCMAKE_OPTION_NAME=VALUE) +Set the CCACHE variable to "true" to enable build caching. +The APK and AAB will be output into "artifacts". + +EOF + + exit "$RETURN" +} + +die() { + echo "-- ! $*" >&2 + RETURN=1 usage +} + +target() { + [ -z "$1" ] && die "You must specify a valid target." + + TARGET="$1" +} + +type() { + [ -z "$1" ] && die "You must specify a valid type." + + TYPE="$1" +} + +while true; do + case "$1" in + -r|--release) DEVEL=false ;; + -t|--target) target "$2"; shift ;; + -b|--build-type) type "$2"; shift ;; + -h|--help) usage ;; + *) break ;; + esac + + shift +done + +: "${TARGET:=standard}" +: "${TYPE:=Release}" +: "${DEVEL:=true}" + +TARGET_LOWER=$(echo "$TARGET" | tr '[:upper:]' '[:lower:]') + +case "$TARGET_LOWER" in + legacy) FLAVOR=Legacy ;; + optimized) FLAVOR=GenshinSpoof ;; + standard) FLAVOR=Mainline ;; + chromeos) FLAVOR=ChromeOS ;; + *) die "Invalid build flavor $TARGET." +esac + +case "$TYPE" in + RelWithDebInfo|Release|Debug) ;; + *) die "Invalid build type $TYPE." +esac + +LOWER_FLAVOR=$(echo "$FLAVOR" | sed 's/./\L&/') +LOWER_TYPE=$(echo "$TYPE" | sed 's/./\L&/') + +if [ -n "${ANDROID_KEYSTORE_B64}" ]; then export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks" - base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}" + echo "${ANDROID_KEYSTORE_B64}" | base64 --decode > "${ANDROID_KEYSTORE_FILE}" + SHA1SUM=$(keytool -list -v -storepass "${ANDROID_KEYSTORE_PASS}" -keystore "${ANDROID_KEYSTORE_FILE}" | grep SHA1 | cut -d " " -f3) + echo "-- Keystore SHA1 is ${SHA1SUM}" fi cd src/android chmod +x ./gradlew -./gradlew assembleMainlineRelease -./gradlew bundleMainlineRelease +set -- "$@" -DUSE_CCACHE="${CCACHE}" +[ "$DEVEL" != "true" ] && set -- "$@" -DENABLE_UPDATE_CHECKER=ON -if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then +echo "-- building..." + +./gradlew "copy${FLAVOR}${TYPE}Outputs" \ + -Dorg.gradle.caching="${CCACHE}" \ + -Dorg.gradle.parallel="${CCACHE}" \ + -Dorg.gradle.workers.max="${NUM_JOBS}" \ + -PYUZU_ANDROID_ARGS="$*" \ + --info + +if [ -n "${ANDROID_KEYSTORE_B64}" ]; then rm "${ANDROID_KEYSTORE_FILE}" fi + +echo "-- Done! APK and AAB artifacts are in ${ARTIFACTS_DIR}" + +ls -l "${ARTIFACTS_DIR}/" diff --git a/.ci/android/package.sh b/.ci/android/package.sh deleted file mode 100755 index 50b7bbc332..0000000000 --- a/.ci/android/package.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')" -GITREV="$(git show -s --format='%h')" -ARTIFACTS_DIR="$PWD/artifacts" -mkdir -p "${ARTIFACTS_DIR}/" - -REV_NAME="eden-android-${GITDATE}-${GITREV}" -BUILD_FLAVOR="mainline" -BUILD_TYPE_LOWER="release" -BUILD_TYPE_UPPER="Release" - -cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/${BUILD_TYPE_LOWER}/app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.apk" \ - "${ARTIFACTS_DIR}/${REV_NAME}.apk" || echo "APK not found" - -cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}${BUILD_TYPE_UPPER}"/"app-${BUILD_FLAVOR}-${BUILD_TYPE_LOWER}.aab" \ - "${ARTIFACTS_DIR}/${REV_NAME}.aab" || echo "AAB not found" - -ls -la "${ARTIFACTS_DIR}/" diff --git a/CMakeLists.txt b/CMakeLists.txt index 4afbc13683..4a108e47af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -436,10 +436,10 @@ if (ENABLE_OPENSSL) option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL}) endif() +# TODO(crueter): CPM this if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL) - # TODO(crueter): CPM this - set(vvl_version "1.4.321.0") - set(vvl_zip_file "${CMAKE_BINARY_DIR}/externals/vvl-android.zip") + set(vvl_version "1.4.328.0") + set(vvl_zip_file "${CMAKE_BINARY_DIR}/externals/vvl-android-${vvl_version}.zip") if (NOT EXISTS "${vvl_zip_file}") # Download and extract validation layer release to externals directory set(vvl_base_url "https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download") @@ -450,8 +450,14 @@ if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL) endif() # Copy the arm64 binary to src/android/app/main/jniLibs - set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/arm64-v8a/") - file(COPY "${CMAKE_BINARY_DIR}/externals/android-binaries-${vvl_version}/arm64-v8a/libVkLayer_khronos_validation.so" + if (ARCHITECTURE_arm64) + set(vvl_abi arm64-v8a) + elseif(ARCHITECTURE_x86_64) + set(vvl_abi x86_64) + endif() + + set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/${vvl_abi}/") + file(COPY "${CMAKE_BINARY_DIR}/externals/android-binaries-${vvl_version}/${vvl_abi}/libVkLayer_khronos_validation.so" DESTINATION "${vvl_lib_path}") endif() diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 78bab05030..53b9e24079 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -603,8 +603,12 @@ function(AddCIPackage) add_ci_package(mingw-arm64) endif() - if (ANDROID AND NOT "android" IN_LIST DISABLED_PLATFORMS) - add_ci_package(android) + if((ANDROID AND ARCHITECTURE_x86_64) AND NOT "android-x86_64" IN_LIST DISABLED_PLATFORMS) + add_ci_package(android-x86_64) + endif() + + if((ANDROID AND ARCHITECTURE_arm64) AND NOT "android-aarch64" IN_LIST DISABLED_PLATFORMS) + add_ci_package(android-aarch64) endif() if(PLATFORM_SUN AND NOT "solaris-amd64" IN_LIST DISABLED_PLATFORMS) diff --git a/cpmfile.json b/cpmfile.json index 6cf7ed1a41..c00f955087 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -4,7 +4,7 @@ "package": "OpenSSL", "name": "openssl", "repo": "crueter-ci/OpenSSL", - "version": "3.6.0-e3608d80df", + "version": "3.6.0-965d6279e8", "min_version": "1.1.1" }, "boost": { diff --git a/docs/build/Android.md b/docs/build/Android.md index 5805ed2797..638d429328 100644 --- a/docs/build/Android.md +++ b/docs/build/Android.md @@ -1,30 +1,37 @@ -# Note: These build instructions are a work-in-progress. +# Android ## Dependencies + * [Android Studio](https://developer.android.com/studio) * [NDK 27+ and CMake 3.22.1](https://developer.android.com/studio/projects/install-ndk#default-version) * [Git](https://git-scm.com/download) -### WINDOWS ONLY - Additional Dependencies - * **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select "Desktop development with C++" support in the installer. Make sure to update to the latest version if already installed.** - * **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** - - A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. +## WINDOWS ONLY - Additional Dependencies + +* **[Visual Studio 2022 Community](https://visualstudio.microsoft.com/downloads/)** - **Make sure to select "Desktop development with C++" support in the installer. Make sure to update to the latest version if already installed.** +* **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** - **Make sure to select Latest SDK.** + * A convenience script to install the latest SDK is provided in `.ci\windows\install-vulkan-sdk.ps1`. ## Cloning Eden with Git -``` + +```sh git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git ``` -Eden by default will be cloned into - + +Eden by default will be cloned into: + * `C:\Users\\eden` on Windows * `~/eden` on Linux and macOS ## Building + 1. Start Android Studio, on the startup dialog select `Open`. 2. Navigate to the `eden/src/android` directory and click on `OK`. 3. In `Build > Select Build Variant`, select `release` or `relWithDebInfo` as the "Active build variant". 4. Build the project with `Build > Make Project` or run it on an Android device with `Run > Run 'app'`. ## Building with Terminal + 1. Download the SDK and NDK from Android Studio. 2. Navigate to SDK and NDK paths. 3. Then set ANDROID_SDK_ROOT and ANDROID_NDK_ROOT in terminal via @@ -38,7 +45,44 @@ Eden by default will be cloned into - Remember to have a Java SDK installed if not already, on Debian and similar this is done with `sudo apt install openjdk-17-jdk`. ### Script -A convenience script for building is provided in `.ci/android/build.sh`. The built APK can be put into an `artifacts` directory via `.ci/android/package.sh`. On Windows, these must be done in the Git Bash or MinGW terminal. + +A convenience script for building is provided in `.ci/android/build.sh`. On Windows, this must be run in Git Bash or MSYS2. This script provides the following options: + +```txt +Usage: build.sh [-c|--chromeos] [-t|--target FLAVOR] [-b|--build-type BUILD_TYPE] + [-h|--help] [-r|--release] [extra options] + +Build script for Android. +Associated variables can be set outside the script, +and will apply both to this script and the packaging script. +bool values are "true" or "false" + +Options: + -c, --chromeos Build for ChromeOS (x86_64) (variable: CHROMEOS, bool) + Default: false + -r, --release Enable update checker. If set, sets the DEVEL bool variable to false. + By default, DEVEL is true. + -t, --target Build flavor (variable: TARGET) + Valid values are: legacy, optimized, standard + Default: standard + -b, --build-type Build type (variable: TYPE) + Valid values are: Release, RelWithDebInfo, Debug + Default: Debug + +Extra arguments are passed to CMake (e.g. -DCMAKE_OPTION_NAME=VALUE) +Set the CCACHE variable to "true" to enable build caching. +The APK and AAB will be output into "artifacts". +``` + +Examples: + +* Build legacy release with update checker for ChromeOS: + * `.ci/android/build.sh -c -r -t legacy` +* Build standard release with debug info without update checker for phones: + * `.ci/android/build.sh -b RelWithDebInfo` +* Build optimized release with update checker: + * `.ci/android/build.sh -r -t optimized` ### Additional Resources -https://developer.android.com/studio/intro + + diff --git a/externals/cpmfile.json b/externals/cpmfile.json index ee5ccb451e..7f5af5dfce 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -9,7 +9,7 @@ }, "sirit": { "repo": "eden-emulator/sirit", - "git_version": "1.0.2", + "git_version": "1.0.3", "tag": "v%VERSION%", "artifact": "sirit-source-%VERSION%.tar.zst", "hash_suffix": "sha512sum", @@ -23,11 +23,7 @@ "package": "sirit", "name": "sirit", "repo": "eden-emulator/sirit", - "version": "1.0.2", - "disabled_platforms": [ - "mingw-amd64", - "mingw-arm64" - ] + "version": "1.0.3" }, "httplib": { "repo": "yhirose/cpp-httplib", @@ -167,7 +163,7 @@ "package": "SDL2", "name": "SDL2", "repo": "crueter-ci/SDL2", - "version": "2.32.10-38e0094637", + "version": "2.32.10-a65111bd2d", "min_version": "2.26.4" }, "catch2": { diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 58461d8934..d71613db8c 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -114,16 +114,6 @@ if (UNIX AND NOT ANDROID) endif() if (YUZU_USE_BUNDLED_FFMPEG) - # MSVC conflicts with ksuser otherwise - # MinGW has the funny quirk of requiring avutil after avcodec - # Android needs some deps to be compiled with PIC (TODO) - # TODO(crueter) fix - if (ANDROID) - set(BUILD_SHARED_LIBS ON) - else() - set(BUILD_SHARED_LIBS OFF) - endif() - AddJsonPackage(ffmpeg-ci) set(FFmpeg_INCLUDE_DIR diff --git a/externals/ffmpeg/cpmfile.json b/externals/ffmpeg/cpmfile.json index 0baeeb4713..0d0a612eda 100644 --- a/externals/ffmpeg/cpmfile.json +++ b/externals/ffmpeg/cpmfile.json @@ -1,8 +1,8 @@ { "ffmpeg": { "repo": "FFmpeg/FFmpeg", - "sha": "c2184b65d2", - "hash": "007b1ccdd4d3ea3324835258d9a255103253bd66edb442b12d9c60dca85149cad52136a3b3120e5094115b6a3d9e80eeacbf9c07e5ffafc9ac459614d5fa3b22", + "sha": "ddf443f1e9", + "hash": "ded1c313843f23805102565bd3ca92602fb9c2951e059ca5e1a486ab3ef7d589acccf3cde05c5ff0cfc5199c3a261dccb4d2a93254e585824850696fb41a292e", "bundled": true }, "ffmpeg-ci": { @@ -10,7 +10,7 @@ "package": "FFmpeg", "name": "ffmpeg", "repo": "crueter-ci/FFmpeg", - "version": "8.0-be99d2c0b2", + "version": "8.0-ddf443f1e9", "min_version": "4.1" } } diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 01a413261e..87d815c92c 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -4,10 +4,11 @@ // SPDX-FileCopyrightText: Copyright yuzu/Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -import android.annotation.SuppressLint +// import android.annotation.SuppressLint import kotlin.collections.setOf import org.jlleitschuh.gradle.ktlint.reporter.ReporterType import com.github.triplet.gradle.androidpublisher.ReleaseStatus +import org.gradle.api.tasks.Copy plugins { id("com.android.application") @@ -63,11 +64,6 @@ android { versionName = getGitVersion() versionCode = autoVersion - ndk { - @SuppressLint("ChromeOsAbiSupport") - abiFilters += listOf("arm64-v8a") - } - externalNativeBuild { cmake { val extraCMakeArgs = @@ -127,7 +123,7 @@ android { isMinifyEnabled = true isDebuggable = false proguardFiles( - getDefaultProguardFile("proguard-android.txt"), + getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } @@ -139,7 +135,7 @@ android { signingConfig = signingConfigs.getByName("default") isDebuggable = true proguardFiles( - getDefaultProguardFile("proguard-android.txt"), + getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) versionNameSuffix = "-relWithDebInfo" @@ -163,12 +159,20 @@ android { create("mainline") { dimension = "version" resValue("string", "app_name_suffixed", "Eden") + + ndk { + abiFilters += listOf("arm64-v8a") + } } create("genshinSpoof") { dimension = "version" resValue("string", "app_name_suffixed", "Eden Optimized") applicationId = "com.miHoYo.Yuanshen" + + ndk { + abiFilters += listOf("arm64-v8a") + } } create("legacy") { @@ -187,6 +191,25 @@ android { res.srcDirs("src/main/legacy") } } + + ndk { + abiFilters += listOf("arm64-v8a") + } + } + + create("chromeOS") { + dimension = "version" + resValue("string", "app_name_suffixed", "Eden") + + ndk { + abiFilters += listOf("x86_64") + } + + externalNativeBuild { + cmake { + abiFilters("x86_64") + } + } } } @@ -321,3 +344,35 @@ fun getGitVersion(): String { } return versionName.ifEmpty { "0.0" } } + +afterEvaluate { + val artifactsDir = layout.projectDirectory.dir("../../../artifacts") + val outputsDir = layout.buildDirectory.dir("outputs").get() + + android.applicationVariants.forEach { variant -> + val variantName = variant.name + val variantTask = variantName.replaceFirstChar { it.uppercaseChar() } + + val flavor = variant.flavorName + val type = variant.buildType.name + + val baseName = "app-$flavor-$type" + + val apkFile = outputsDir.file("apk/$flavor/$type/$baseName.apk") + val aabFile = outputsDir.file("bundle/$variantName/$baseName.aab") + + val taskName = "copy${variantTask}Outputs" + + tasks.register(taskName) { + group = "publishing" + description = "Copy APK and AAB for $variantName to $artifactsDir" + + from(apkFile) + from(aabFile) + into(artifactsDir) + + dependsOn("assemble${variantTask}") + dependsOn("bundle${variantTask}") + } + } +} diff --git a/tools/cpm/download.sh b/tools/cpm/download.sh index 9793db0c04..bc436ba0f1 100755 --- a/tools/cpm/download.sh +++ b/tools/cpm/download.sh @@ -65,7 +65,12 @@ ci_package() { echo "-- CI package $PACKAGE_NAME" - for platform in windows-amd64 windows-arm64 mingw-amd64 mingw-arm64 android solaris-amd64 freebsd-amd64 openbsd-amd64 linux-amd64 linux-aarch64 macos-universal; do + for platform in windows-amd64 windows-arm64 \ + mingw-amd64 mingw-arm64 \ + android-aarch64 android-x86_64 \ + solaris-amd64 freebsd-amd64 openbsd-amd64 \ + linux-amd64 linux-aarch64 \ + macos-universal; do echo "-- * platform $platform" case $DISABLED in