aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrueter <crueter@eden-emu.dev>2026-01-31 01:18:36 +0100
committercrueter <crueter@eden-emu.dev>2026-01-31 01:18:36 +0100
commit638663b28e10b1247fc2fb2e387b6e0aec070098 (patch)
tree3fc894fcd3f682c99a8fa7b037a421dc3d359a30 /src
parentdf838a57fd5d1a118e310933b37e9aeb2d88327b (diff)
[cmake, frontend] Add nightly build modifier (#3431)
The `NIGHTLY_BUILD` option changes the app name to "Eden Nightly" and changes the auto-update URL to use our new Nightly repository. This needs added to Android, but I can't right now as I have to leave. Signed-off-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3431
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/android/app/build.gradle.kts30
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt11
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt24
-rw-r--r--src/android/app/src/main/jni/native.cpp50
-rw-r--r--src/frontend_common/update_checker.cpp13
-rw-r--r--src/frontend_common/update_checker.h10
-rw-r--r--src/yuzu/main_window.cpp18
-rw-r--r--src/yuzu/main_window.h5
9 files changed, 125 insertions, 40 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 014134c14e..f8afaeb328 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -20,6 +20,10 @@ if (YUZU_STATIC_BUILD)
add_compile_definitions(QT_STATICPLUGIN)
endif()
+if (NIGHTLY_BUILD)
+ add_compile_definitions(NIGHTLY_BUILD)
+endif()
+
# Set compilation flags
if (MSVC AND NOT CXX_CLANG)
set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index 185704c8fe..06c35669ce 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// import android.annotation.SuppressLint
+import com.android.build.gradle.api.ApplicationVariant
import kotlin.collections.setOf
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
@@ -37,6 +38,9 @@ android {
compileSdkVersion = "android-36"
ndkVersion = "28.2.13676358"
+ val isNightly =
+ providers.gradleProperty("nightly").orNull?.toBooleanStrictOrNull() ?: false
+
buildFeatures {
viewBinding = true
}
@@ -71,6 +75,7 @@ android {
val extraCMakeArgs =
(project.findProperty("YUZU_ANDROID_ARGS") as String?)?.split("\\s+".toRegex())
?: emptyList()
+
arguments.addAll(
listOf(
"-DENABLE_QT=0", // Don't use QT
@@ -89,6 +94,13 @@ android {
)
)
+ if (isNightly) {
+ arguments.addAll(listOf(
+ "-DENABLE_UPDATE_CHECKER=ON",
+ "-DNIGHTLY_BUILD=ON",
+ ))
+ }
+
abiFilters("arm64-v8a")
}
}
@@ -125,7 +137,12 @@ android {
signingConfigs.getByName("default")
}
- manifestPlaceholders += mapOf("appNameSuffix" to "")
+ if (isNightly) {
+ applicationIdSuffix = ".nightly"
+ manifestPlaceholders += mapOf("appNameSuffix" to " Nightly")
+ } else {
+ manifestPlaceholders += mapOf("appNameSuffix" to "")
+ }
isMinifyEnabled = true
isDebuggable = false
@@ -239,6 +256,15 @@ android {
path = file("${edenDir}/CMakeLists.txt")
}
}
+
+ productFlavors.all {
+ val currentName = manifestPlaceholders["appNameBase"] as? String ?: "Eden"
+ val suffix = if (isNightly) " Nightly" else ""
+
+ // apply nightly suffix I/A
+ resValue("string", "app_name_suffixed", "$currentName$suffix")
+ resValue("string", "app_name", "Eden$suffix")
+ }
}
idea {
@@ -258,7 +284,7 @@ tasks.register<Delete>("ktlintReset", fun Delete.() {
val showFormatHelp = {
logger.lifecycle(
"If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
- "codestyle fixes"
+ "codestyle fixes"
)
}
tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 8919f25fd6..4082454e7b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -218,7 +218,7 @@ object NativeLibrary {
/**
* Checks for available updates.
*/
- external fun checkForUpdate(): String?
+ external fun checkForUpdate(): Array<String>?
/**
* Return the URL to the release page
@@ -228,7 +228,7 @@ object NativeLibrary {
/**
* Return the URL to download the APK for the given version
*/
- external fun getUpdateApkUrl(version: String, packageId: String): String
+ external fun getUpdateApkUrl(tag: String, artifact: String, packageId: String): String
/**
* Returns whether the update checker is enabled through CMAKE options.
@@ -236,6 +236,11 @@ object NativeLibrary {
external fun isUpdateCheckerEnabled(): Boolean
/**
+ * Returns whether or not this is a nightly build.
+ */
+ external fun isNightlyBuild(): Boolean
+
+ /**
* Returns the build version generated by CMake (BUILD_VERSION).
*/
external fun getBuildVersion(): String
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 23716ac5a5..8186a6b18f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.ui.main
@@ -183,18 +183,26 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val latestVersion = NativeLibrary.checkForUpdate()
if (latestVersion != null) {
runOnUiThread {
- showUpdateDialog(latestVersion)
+ val tag: String = latestVersion[0]
+ val name: String = latestVersion[1]
+ showUpdateDialog(tag, name)
}
}
}.start()
}
- private fun showUpdateDialog(version: String) {
+ private fun showUpdateDialog(tag: String, name: String) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.update_available)
- .setMessage(getString(R.string.update_available_description, version))
+ .setMessage(getString(R.string.update_available_description, name))
.setPositiveButton(android.R.string.ok) { _, _ ->
- downloadAndInstallUpdate(version)
+ var artifact = tag
+ // Nightly builds have a slightly different format
+ if (NativeLibrary.isNightlyBuild()) {
+ val splitTag = tag.split('.')
+ artifact = splitTag.subList(1, splitTag.size - 1).joinToString(".")
+ }
+ downloadAndInstallUpdate(tag, artifact)
}
.setNeutralButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
@@ -207,11 +215,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
.show()
}
- private fun downloadAndInstallUpdate(version: String) {
+ private fun downloadAndInstallUpdate(version: String, artifact: String) {
CoroutineScope(Dispatchers.IO).launch {
val packageId = applicationContext.packageName
- val apkUrl = NativeLibrary.getUpdateApkUrl(version, packageId)
- val apkFile = File(cacheDir, "update-$version.apk")
+ val apkUrl = NativeLibrary.getUpdateApkUrl(version, artifact, packageId)
+ val apkFile = File(cacheDir, "update-$artifact.apk")
withContext(Dispatchers.Main) {
showDownloadProgressDialog()
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 5746659b68..550befa85c 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -1595,7 +1595,6 @@ JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_updatePowerState(
g_has_battery.store(hasBattery, std::memory_order_relaxed);
}
-// return #ifdef ENABLE_UPDATE_CHECKER
JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isUpdateCheckerEnabled(
JNIEnv* env,
jobject obj) {
@@ -1606,22 +1605,47 @@ JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isUpdateChecker
#endif
}
+JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isNightlyBuild(
+ JNIEnv* env,
+ jobject obj) {
+#ifdef NIGHTLY_BUILD
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+
#ifdef ENABLE_UPDATE_CHECKER
-JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_checkForUpdate(
+JNIEXPORT jobjectArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_checkForUpdate(
JNIEnv* env,
jobject obj) {
const bool is_prerelease = ((strstr(Common::g_build_version, "pre-alpha") != nullptr) ||
(strstr(Common::g_build_version, "alpha") != nullptr) ||
(strstr(Common::g_build_version, "beta") != nullptr) ||
(strstr(Common::g_build_version, "rc") != nullptr));
- const std::optional<std::string> latest_release_tag =
+ const std::optional<UpdateChecker::Update> release =
UpdateChecker::GetLatestRelease(is_prerelease);
- if (latest_release_tag && latest_release_tag.value() != Common::g_build_version) {
- return env->NewStringUTF(latest_release_tag.value().c_str());
+ if (!release || release->tag == Common::g_build_version) {
+ return nullptr;
}
- return nullptr;
+
+ const std::string tag = release->tag;
+ const std::string name = release->name;
+
+ jobjectArray result = env->NewObjectArray(2, env->FindClass("java/lang/String"), nullptr);
+
+ const jstring jtag = env->NewStringUTF(tag.c_str());
+ const jstring jname = env->NewStringUTF(name.c_str());
+
+ env->SetObjectArrayElement(result, 0, jtag);
+ env->SetObjectArrayElement(result, 1, jname);
+ env->DeleteLocalRef(jtag);
+ env->DeleteLocalRef(jname);
+
+ return result;
}
JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateUrl(
@@ -1640,9 +1664,11 @@ JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateUrl(
JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateApkUrl(
JNIEnv* env,
jobject obj,
- jstring version,
+ jstring tag,
+ jstring artifact,
jstring packageId) {
- const char* version_str = env->GetStringUTFChars(version, nullptr);
+ const char* version_str = env->GetStringUTFChars(tag, nullptr);
+ const char* artifact_str = env->GetStringUTFChars(artifact, nullptr);
const char* package_id_str = env->GetStringUTFChars(packageId, nullptr);
std::string variant;
@@ -1653,7 +1679,11 @@ JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateApkUrl(
} else if (package_id.find("com.miHoYo.Yuanshen") != std::string::npos) {
variant = "optimized";
} else {
+#ifdef ARCHITECTURE_arm64
variant = "standard";
+#else
+ variant = "chromeos";
+#endif
}
const std::string apk_filename = fmt::format("Eden-Android-{}-{}.apk", version_str, variant);
@@ -1663,7 +1693,7 @@ JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_getUpdateApkUrl(
version_str,
apk_filename);
- env->ReleaseStringUTFChars(version, version_str);
+ env->ReleaseStringUTFChars(tag, version_str);
env->ReleaseStringUTFChars(packageId, package_id_str);
return env->NewStringUTF(url.c_str());
}
diff --git a/src/frontend_common/update_checker.cpp b/src/frontend_common/update_checker.cpp
index 9a8143c788..21bb6c4c7d 100644
--- a/src/frontend_common/update_checker.cpp
+++ b/src/frontend_common/update_checker.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright Citra Emulator Project / Azahar Emulator Project
@@ -78,7 +78,7 @@ std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::stri
}
}
-std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prereleases) {
+std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool include_prereleases) {
const auto update_check_url = std::string{Common::g_build_auto_update_api};
std::string update_check_path = fmt::format("/repos/{}",
std::string{Common::g_build_auto_update_repo});
@@ -96,6 +96,9 @@ std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prerelea
const std::string latest_tag
= nlohmann::json::parse(tags_response.value()).at(0).at("name");
+ const std::string latest_name =
+ nlohmann::json::parse(releases_response.value()).at(0).at("name");
+
const bool latest_tag_has_release = releases_response.value().find(
fmt::format("\"{}\"", latest_tag))
!= std::string::npos;
@@ -105,7 +108,7 @@ std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prerelea
if (!latest_tag_has_release)
return {};
- return latest_tag;
+ return Update{latest_tag, latest_name};
} else { // This is a stable release, only check for other stable releases.
update_check_path += "/releases/latest";
const auto response = UpdateChecker::GetResponse(update_check_url, update_check_path);
@@ -114,7 +117,9 @@ std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prerelea
return {};
const std::string latest_tag = nlohmann::json::parse(response.value()).at("tag_name");
- return latest_tag;
+ const std::string latest_name = nlohmann::json::parse(response.value()).at("name");
+
+ return Update{latest_tag, latest_name};
}
} catch (nlohmann::detail::out_of_range &) {
diff --git a/src/frontend_common/update_checker.h b/src/frontend_common/update_checker.h
index 957843bee0..9dbb321eef 100644
--- a/src/frontend_common/update_checker.h
+++ b/src/frontend_common/update_checker.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright Citra Emulator Project / Azahar Emulator Project
@@ -11,6 +11,12 @@
#include <string>
namespace UpdateChecker {
+
+typedef struct {
+ std::string tag;
+ std::string name;
+} Update;
+
std::optional<std::string> GetResponse(std::string url, std::string path);
-std::optional<std::string> GetLatestRelease(bool include_prereleases);
+std::optional<Update> GetLatestRelease(bool include_prereleases);
} // namespace UpdateChecker
diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp
index cffd9f4444..3ca6eaf99c 100644
--- a/src/yuzu/main_window.cpp
+++ b/src/yuzu/main_window.cpp
@@ -516,17 +516,17 @@ MainWindow::MainWindow(bool has_broken_vulkan)
#ifdef ENABLE_UPDATE_CHECKER
if (UISettings::values.check_for_updates) {
- update_future = QtConcurrent::run([]() -> QString {
+ update_future = QtConcurrent::run([]() -> UpdateChecker::Update {
const bool is_prerelease = ((strstr(Common::g_build_version, "pre-alpha") != NULL) ||
(strstr(Common::g_build_version, "alpha") != NULL) ||
(strstr(Common::g_build_version, "beta") != NULL) ||
(strstr(Common::g_build_version, "rc") != NULL));
- const std::optional<std::string> latest_release_tag =
+ const std::optional<UpdateChecker::Update> latest_release_tag =
UpdateChecker::GetLatestRelease(is_prerelease);
- if (latest_release_tag && latest_release_tag.value() != Common::g_build_version) {
- return QString::fromStdString(latest_release_tag.value());
+ if (latest_release_tag && latest_release_tag->tag != Common::g_build_version) {
+ return latest_release_tag.value();
}
- return QString{};
+ return UpdateChecker::Update{};
});
update_watcher.connect(&update_watcher, &QFutureWatcher<QString>::finished, this,
&MainWindow::OnEmulatorUpdateAvailable);
@@ -4020,8 +4020,8 @@ void MainWindow::OnCaptureScreenshot() {
#ifdef ENABLE_UPDATE_CHECKER
void MainWindow::OnEmulatorUpdateAvailable() {
- QString version_string = update_future.result();
- if (version_string.isEmpty())
+ UpdateChecker::Update version = update_future.result();
+ if (version.tag.empty())
return;
QMessageBox update_prompt(this);
@@ -4030,14 +4030,14 @@ void MainWindow::OnEmulatorUpdateAvailable() {
update_prompt.addButton(QMessageBox::Yes);
update_prompt.addButton(QMessageBox::Ignore);
update_prompt.setText(
- tr("Download the %1 update?").arg(version_string));
+ tr("Download %1?").arg(version.name));
update_prompt.exec();
if (update_prompt.button(QMessageBox::Yes) == update_prompt.clickedButton()) {
auto const full_url = fmt::format("{}/{}/releases/tag/",
std::string{Common::g_build_auto_update_website},
std::string{Common::g_build_auto_update_repo}
);
- QDesktopServices::openUrl(QUrl(QString::fromStdString(full_url) + version_string));
+ QDesktopServices::openUrl(QUrl(QString::fromStdString(full_url + version.tag)));
}
}
#endif
diff --git a/src/yuzu/main_window.h b/src/yuzu/main_window.h
index fe91ea18f1..351a581729 100644
--- a/src/yuzu/main_window.h
+++ b/src/yuzu/main_window.h
@@ -18,6 +18,7 @@
#include "common/common_types.h"
#include "frontend_common/content_manager.h"
+#include "frontend_common/update_checker.h"
#include "input_common/drivers/tas_input.h"
#include "qt_common/config/qt_config.h"
#include "qt_common/util/game.h"
@@ -471,8 +472,8 @@ private:
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
#ifdef ENABLE_UPDATE_CHECKER
- QFuture<QString> update_future;
- QFutureWatcher<QString> update_watcher;
+ QFuture<UpdateChecker::Update> update_future;
+ QFutureWatcher<UpdateChecker::Update> update_watcher;
#endif
MultiplayerState* multiplayer_state = nullptr;