android: Move update checker to common and make available to Android

This commit is contained in:
whyydk 2026-04-02 15:25:18 +02:00
parent 3066887ff4
commit 26592ee8f9
30 changed files with 313 additions and 53 deletions

View File

@ -17,7 +17,7 @@ else
fi
if [ "$GITHUB_REF_TYPE" == "tag" ]; then
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_QT_UPDATE_CHECKER=ON)
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_UPDATE_CHECKER=ON)
fi
mkdir build && cd build

View File

@ -1,7 +1,7 @@
#!/bin/bash -ex
if [ "$GITHUB_REF_TYPE" == "tag" ]; then
export EXTRA_CMAKE_FLAGS=(-DENABLE_QT_UPDATE_CHECKER=ON)
export EXTRA_CMAKE_FLAGS=(-DENABLE_UPDATE_CHECKER=ON)
fi
mkdir -p build/$BUILD_ARCH && cd build/$BUILD_ARCH

View File

@ -3,7 +3,7 @@
mkdir build && cd build
if [ "$GITHUB_REF_TYPE" == "tag" ]; then
export EXTRA_CMAKE_FLAGS=(-DENABLE_QT_UPDATE_CHECKER=ON)
export EXTRA_CMAKE_FLAGS=(-DENABLE_UPDATE_CHECKER=ON)
fi
cmake .. -G Ninja \

View File

@ -110,7 +110,7 @@ option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OF
# Set bundled qt as dependent options.
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_QT_UPDATE_CHECKER "Enable built-in update checker for the Qt frontend" OFF)
option(ENABLE_UPDATE_CHECKER "Enable built-in update checker for the Qt / Android frontend" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT IOS" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF)

View File

@ -143,6 +143,8 @@ foreach(KEY IN ITEMS
"web_api_url"
"citra_username"
"citra_token"
"check_for_update_on_start"
"update_check_channel"
)
set(SETTING_KEY_LIST "${SETTING_KEY_LIST}\n\"${KEY}\",")
set(SETTING_KEY_DEFINITIONS "${SETTING_KEY_DEFINITIONS}\nDEFINE_KEY(${KEY})")

View File

@ -169,6 +169,11 @@ android {
isDefault = true
dimension = "version"
versionNameSuffix = "-vanilla"
externalNativeBuild {
cmake {
arguments += "-DENABLE_UPDATE_CHECKER=ON"
}
}
}
register("googlePlay") {
dimension = "version"

View File

@ -16,6 +16,11 @@ import org.citra.citra_emu.utils.GpuDriverHelper
import org.citra.citra_emu.utils.PermissionsHandler
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.MemoryUtil
import java.io.File
import java.io.FileOutputStream
import java.security.KeyStore
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
class CitraApplication : Application() {
private fun createNotificationChannel() {
@ -59,6 +64,46 @@ class CitraApplication : Application() {
logDeviceInfo()
createNotificationChannel()
NativeLibrary.playTimeManagerInit()
if (NativeLibrary.isUpdateCheckerEnabled()) {
initializeCACertificates()
}
}
// needed for update checking
private fun initializeCACertificates() {
try {
val factory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
)
factory.init(null as KeyStore?)
val trustManager = factory.trustManagers[0] as X509TrustManager
val certFile = File(filesDir, "cacert.pem")
if (!certFile.exists()) {
FileOutputStream(certFile).use { out ->
trustManager.acceptedIssuers.forEach { cert ->
out.write("-----BEGIN CERTIFICATE-----\n".toByteArray())
val encoded = android.util.Base64.encodeToString(
cert.encoded,
android.util.Base64.NO_WRAP // 👈 important
)
out.write(encoded.toByteArray())
out.write("\n-----END CERTIFICATE-----\n".toByteArray())
}
}
}
NativeLibrary.setCACertificatePath(certFile.absolutePath)
Log.info("[SSL] CA certs ready: ${certFile.absolutePath}")
} catch (e: Exception) {
Log.error("[SSL] Failed to init CA certs: ${e.message}")
}
}
fun logDeviceInfo() {

View File

@ -527,6 +527,13 @@ object NativeLibrary {
sEmulationActivity.clear()
}
// Update checker
external fun getUpdateTag(): String
external fun isUpdateCheckerEnabled(): Boolean
external fun getUpdateUrl(): String
// Sets the path to CA certificates for SSL/TLS verification.
external fun setCACertificatePath(path: String)
private val cameraPermissionLock = Object()
private var cameraPermissionGranted = false
const val REQUEST_CODE_NATIVE_CAMERA = 800

View File

@ -138,4 +138,7 @@ object SettingKeys {
external fun android_hide_images(): String
external fun screen_orientation(): String
external fun performance_overlay_position(): String
external fun check_for_update_on_start(): String
external fun update_check_channel(): String
}

View File

@ -56,7 +56,8 @@ enum class BooleanSetting(
COMPRESS_INSTALLED_CIA_CONTENT(SettingKeys.compress_cia_installs(), Settings.SECTION_STORAGE, false),
ANDROID_HIDE_IMAGES(SettingKeys.android_hide_images(), Settings.SECTION_MISC, false),
APPLY_REGION_FREE_PATCH(SettingKeys.apply_region_free_patch(), Settings.SECTION_SYSTEM, true),
USE_INTEGER_SCALING(SettingKeys.use_integer_scaling(), Settings.SECTION_RENDERER, false);
USE_INTEGER_SCALING(SettingKeys.use_integer_scaling(), Settings.SECTION_RENDERER, true),
CHECK_FOR_UPDATES(SettingKeys.check_for_update_on_start(), Settings.SECTION_THEME, true);
override var boolean: Boolean = defaultValue

View File

@ -56,6 +56,7 @@ enum class IntSetting(
TURBO_LIMIT(SettingKeys.turbo_limit(), Settings.SECTION_CORE, 200),
PERFORMANCE_OVERLAY_POSITION(SettingKeys.performance_overlay_position(), Settings.SECTION_LAYOUT, 0),
RENDER_3D_WHICH_DISPLAY(SettingKeys.render_3d_which_display(),Settings.SECTION_RENDERER,0),
UPDATE_CHECK_CHANNEL(SettingKeys.update_check_channel(), Settings.SECTION_THEME, 0),
ASPECT_RATIO(SettingKeys.aspect_ratio(), Settings.SECTION_LAYOUT, 0);
override var int: Int = defaultValue

View File

@ -246,7 +246,8 @@ class Settings {
SECTION_STORAGE,
SECTION_UTILITY,
SECTION_AUDIO,
SECTION_DEBUG
SECTION_DEBUG,
SECTION_THEME
)
}
}

View File

@ -16,6 +16,7 @@ import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.serialization.builtins.IntArraySerializer
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.display.ScreenLayout
import org.citra.citra_emu.display.StereoMode
@ -1849,7 +1850,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
}
private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_theme))
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.app_settings))
sl.apply {
val theme: AbstractBooleanSetting = object : AbstractBooleanSetting {
override var boolean: Boolean
@ -1868,6 +1869,37 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
override val defaultValue = false
}
if (NativeLibrary.isUpdateCheckerEnabled()) {
add(
HeaderSetting(
R.string.app_settings,
)
)
add(
SwitchSetting(
BooleanSetting.CHECK_FOR_UPDATES,
R.string.check_for_updates_on_start,
R.string.check_for_updates_on_start_description,
)
)
add(
SingleChoiceSetting(
IntSetting.UPDATE_CHECK_CHANNEL,
R.string.update_check_channel,
0,
R.array.updateCheckChannelNames,
R.array.updateCheckChannelValues,
IntSetting.UPDATE_CHECK_CHANNEL.key,
IntSetting.UPDATE_CHECK_CHANNEL.defaultValue
)
)
}
add(
HeaderSetting(
R.string.set_up_theme_settings,
)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(
SwitchSetting(

View File

@ -170,8 +170,8 @@ class HomeSettingsFragment : Fragment() {
details = homeViewModel.gamesDir
),
HomeSetting(
R.string.preferences_theme,
R.string.theme_and_color_description,
R.string.app_settings,
R.string.app_settings_description,
R.drawable.ic_palette,
{ SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }
),

View File

@ -21,6 +21,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
@ -38,6 +39,7 @@ import androidx.work.OneTimeWorkRequest
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkManager
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationBarView
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.TimeSource
@ -47,6 +49,7 @@ import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.contracts.OpenFileResultContract
import org.citra.citra_emu.databinding.ActivityMainBinding
import org.citra.citra_emu.features.settings.model.BooleanSetting
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.features.settings.model.SettingsViewModel
import org.citra.citra_emu.features.settings.ui.SettingsActivity
@ -189,6 +192,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
if (!firstTimeSetup && NativeLibrary.isUpdateCheckerEnabled() && BooleanSetting.CHECK_FOR_UPDATES.boolean) {
checkForUpdates()
}
setInsets()
}
@ -270,6 +280,37 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
private fun checkForUpdates() {
Thread {
val latestVersion = NativeLibrary.getUpdateTag()
if (!latestVersion.isEmpty()) {
runOnUiThread {
showUpdateDialog(latestVersion)
}
}
}.start()
}
private fun showUpdateDialog(version: String) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.update_available)
.setMessage(getString(R.string.update_available_description, version))
.setPositiveButton(android.R.string.ok) { _, _ ->
val url = NativeLibrary.getUpdateUrl()
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
startActivity(intent)
}
.setNeutralButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
}
.setNegativeButton(R.string.dont_show_again) { dialog, _ ->
BooleanSetting.CHECK_FOR_UPDATES.boolean = false
settingsViewModel.settings.saveSetting(BooleanSetting.CHECK_FOR_UPDATES, SettingsFile.FILE_NAME_CONFIG)
dialog.dismiss()
}
.show()
}
fun finishSetup(navController: NavController) {
navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment)
(binding.navigationView as NavigationBarView).setupWithNavController(navController)

View File

@ -300,6 +300,10 @@ void Config::ReadValues() {
ReadSetting("Miscellaneous", Settings::values.log_filter);
ReadSetting("Miscellaneous", Settings::values.log_regex_filter);
// App settings / Theme Settings
ReadSetting("Theme", Settings::values.update_check_channel);
ReadSetting("Theme", Settings::values.check_for_update_on_start);
// Apply the log_filter setting as the logger has already been initialized
// and doesn't pick up the filter on its own.
Common::Log::Filter filter;

View File

@ -519,6 +519,14 @@ static const char* android_config_default_file_content = (BOOST_HANA_STRING(R"(
# 0 (default): No, 1: Yes
)") DECLARE_KEY(android_hide_images) BOOST_HANA_STRING(R"(
[Theme]
# Update check channel for Android. 0: Stable (Default), 1: Pre-release
)") DECLARE_KEY(update_check_channel) BOOST_HANA_STRING(R"(
# Whether to check for updates on startup. 0: No, 1 (default): Yes
)") DECLARE_KEY(check_for_update_on_start) BOOST_HANA_STRING(R"(
[Debugging]
# Record frame time data, can be found in the log directory. Boolean value
)") DECLARE_KEY(record_frame_times) BOOST_HANA_STRING(R"(

View File

@ -52,6 +52,10 @@
#include "jni/camera/still_image_camera.h"
#include "jni/config.h"
#ifdef ENABLE_UPDATE_CHECKER
#include "common/update_checker.h"
#endif
#ifdef ENABLE_OPENGL
#include "jni/emu_window/emu_window_gl.h"
#endif
@ -646,6 +650,79 @@ jstring Java_org_citra_citra_1emu_NativeLibrary_getRecommendedExtension(
return env->NewStringUTF(j_should_compress ? compressed_ext.c_str() : uncompressed_ext.c_str());
}
JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_isUpdateCheckerEnabled(
JNIEnv* env,
jobject obj) {
#ifdef ENABLE_UPDATE_CHECKER
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}
#ifdef ENABLE_UPDATE_CHECKER
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_setCACertificatePath(
JNIEnv* env,
jobject obj,
jstring path) {
const char* path_str = env->GetStringUTFChars(path, nullptr);
UpdateChecker::SetCACertPath(path_str);
}
bool IsPrereleaseBuild() {
return ((strstr(Common::g_build_fullname, "alpha") != nullptr) ||
(strstr(Common::g_build_fullname, "beta") != nullptr) ||
(strstr(Common::g_build_fullname, "rc") != nullptr));
}
static bool ShouldCheckForPrereleaseUpdates() {
const bool update_channel = Settings::values.update_check_channel.GetValue();
const bool using_prerelease_channel =
(update_channel == Settings::UpdateCheckChannels::PRERELEASE);
return (IsPrereleaseBuild() || using_prerelease_channel);
}
static int GetMajorVersion(const std::string& version) {
size_t dot = version.find('.');
try {
return std::stoi(version.substr(0, dot));
} catch (...) {
return 0;
}
}
JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_getUpdateTag(
JNIEnv* env,
jobject obj) {
const std::optional<std::string> latest_release_tag =
UpdateChecker::GetLatestRelease(ShouldCheckForPrereleaseUpdates());
if (latest_release_tag && latest_release_tag.value() != Common::g_build_fullname) {
const int latest_major_version = GetMajorVersion(latest_release_tag.value());
const int current_major_version = GetMajorVersion(Common::g_build_fullname);
if (current_major_version <= latest_major_version) {
return env->NewStringUTF(latest_release_tag->c_str());
}
}
return env->NewStringUTF("");
}
JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_getUpdateUrl(
JNIEnv* env,
jobject obj) {
std::string update_page_url;
if (ShouldCheckForPrereleaseUpdates()) {
update_page_url = "https://github.com/azahar-emu/azahar/releases";
} else {
update_page_url = "https://azahar-emu.org/pages/download/";
}
return env->NewStringUTF(update_page_url.c_str());
}
#endif
void Java_org_citra_citra_1emu_NativeLibrary_setUserDirectory(JNIEnv* env,
[[maybe_unused]] jobject obj,
jstring j_directory) {

View File

@ -55,6 +55,15 @@
<item>3</item>
</integer-array>
<string-array name="updateCheckChannelNames">
<item>@string/update_check_channel_stable</item>
<item>@string/update_check_channel_pre_release</item>
</string-array>
<integer-array name="updateCheckChannelValues">
<item>0</item>
<item>1</item>
</integer-array>
<string-array name="smallScreenPositions">
<item>@string/small_screen_position_top_right</item>
<item>@string/small_screen_position_middle_right</item>
@ -646,4 +655,6 @@
<item>9</item>
</integer-array>
<string name="update_check_channel_stable">Stable</string>
<string name="update_check_channel_pre_release">Pre-Release</string>
</resources>

View File

@ -34,7 +34,7 @@
<string name="about_description">Build version, credits, and more</string>
<string name="games_dir_selected">Application directory selected</string>
<string name="select_citra_user_folder_home_description">Changes the files that Azahar uses to load applications</string>
<string name="theme_and_color_description">Modify the look of the app</string>
<string name="app_settings_description">Modify the look and behavior of the app</string>
<string name="install_cia_title">Install CIA</string>
<!-- GPU driver installation -->
@ -431,6 +431,7 @@
<string name="preferences_audio">Audio</string>
<string name="preferences_debug">Debug</string>
<string name="preferences_theme">Theme and Color</string>
<string name="preferences_app_settings">App Settings</string>
<string name="preferences_layout">Layout</string>
<!-- ROM loading errors -->
@ -948,4 +949,13 @@
<string name="decompress_failed">Decompression failed.</string>
<string name="compress_decompress_installed_app">Already installed applications cannot be compressed or decompressed.</string>
<!-- Updater -->
<string name="app_settings">App Settings</string>
<string name="check_for_updates_on_start">Check For Updates</string>
<string name="check_for_updates_on_start_description">Checks for updates once on app start.</string>
<string name="update_check_channel">Update Channel</string>
<string name="update_available_description">A new version is available: %1$s\n\nWould you like to download it?</string>
<string name="update_available">Update found!</string>
<string name="dont_show_again">Don\'t Show Again</string>
</resources>

View File

@ -209,12 +209,6 @@ file(GLOB COMPAT_LIST
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
if (ENABLE_QT_UPDATE_CHECKER)
target_link_libraries(citra_qt PRIVATE httplib json-headers)
target_sources(citra_qt PRIVATE update_checker.cpp)
target_compile_definitions(citra_qt PUBLIC ENABLE_QT_UPDATE_CHECKER)
endif()
if (ENABLE_QT_TRANSLATION)
set(CITRA_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)

View File

@ -21,6 +21,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <fmt/format.h>
#include <fmt/ostream.h>
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
@ -74,8 +75,8 @@
#include "citra_qt/qt_swizzle.h"
#include "citra_qt/uisettings.h"
#include "common/play_time_manager.h"
#ifdef ENABLE_QT_UPDATE_CHECKER
#include "citra_qt/update_checker.h"
#ifdef ENABLE_UPDATE_CHECKER
#include "common/update_checker.h"
#endif
#include "citra_qt/util/clickable_label.h"
#include "citra_qt/util/graphics_device_info.h"
@ -180,11 +181,11 @@ bool IsPrereleaseBuild() {
(strstr(Common::g_build_fullname, "rc") != NULL));
}
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
static bool ShouldCheckForPrereleaseUpdates() {
const bool update_channel = UISettings::values.update_check_channel.GetValue();
const bool update_channel = Settings::values.update_check_channel.GetValue();
const bool using_prerelease_channel =
(update_channel == UISettings::UpdateCheckChannels::PRERELEASE);
(update_channel == Settings::UpdateCheckChannels::PRERELEASE);
return (IsPrereleaseBuild() || using_prerelease_channel);
}
@ -438,8 +439,8 @@ GMainWindow::GMainWindow(Core::System& system_)
}
#endif
#ifdef ENABLE_QT_UPDATE_CHECKER
if (UISettings::values.check_for_update_on_start) {
#ifdef ENABLE_UPDATE_CHECKER
if (Settings::values.check_for_update_on_start) {
update_future = QtConcurrent::run([]() -> QString {
const std::optional<std::string> latest_release_tag =
UpdateChecker::GetLatestRelease(ShouldCheckForPrereleaseUpdates());
@ -4080,7 +4081,7 @@ void GMainWindow::OnMoviePlaybackCompleted() {
QMessageBox::information(this, tr("Playback Completed"), tr("Movie playback completed."));
}
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
void GMainWindow::OnEmulatorUpdateAvailable() {
QString version_string = update_future.result();
if (version_string.isEmpty())

View File

@ -10,7 +10,7 @@
#ifdef __unix__
#include <QDBusObjectPath>
#endif
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
#include <QFuture>
#include <QFutureWatcher>
#endif
@ -307,7 +307,7 @@ private slots:
void OnDecreaseVolume();
void OnIncreaseVolume();
void OnMute();
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
void OnEmulatorUpdateAvailable();
#endif
void OnSwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value,
@ -444,7 +444,7 @@ private:
std::shared_ptr<Camera::QtMultimediaCameraHandlerFactory> qt_cameras;
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
// Prompt shown when update check succeeds
QFuture<QString> update_future;
QFutureWatcher<QString> update_watcher;

View File

@ -577,9 +577,9 @@ void QtConfig::ReadMiscellaneousValues() {
#ifdef __unix__
ReadBasicSetting(Settings::values.enable_gamemode);
#endif
#ifdef ENABLE_QT_UPDATE_CHECKER
ReadBasicSetting(UISettings::values.check_for_update_on_start);
ReadBasicSetting(UISettings::values.update_check_channel);
#ifdef ENABLE_UPDATE_CHECKER
ReadBasicSetting(Settings::values.check_for_update_on_start);
ReadBasicSetting(Settings::values.update_check_channel);
#endif
qt_config->endGroup();
@ -1160,9 +1160,9 @@ void QtConfig::SaveMiscellaneousValues() {
#ifdef __unix__
WriteBasicSetting(Settings::values.enable_gamemode);
#endif
#ifdef ENABLE_QT_UPDATE_CHECKER
WriteBasicSetting(UISettings::values.check_for_update_on_start);
WriteBasicSetting(UISettings::values.update_check_channel);
#ifdef ENABLE_UPDATE_CHECKER
WriteBasicSetting(Settings::values.check_for_update_on_start);
WriteBasicSetting(Settings::values.update_check_channel);
#endif
qt_config->endGroup();
}

View File

@ -43,7 +43,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
#ifndef __unix__
ui->toggle_gamemode->setVisible(false);
#endif
#ifndef ENABLE_QT_UPDATE_CHECKER
#ifndef ENABLE_UPDATE_CHECKER
ui->updates_group->setVisible(false);
#endif
@ -90,11 +90,11 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_background_mute->setChecked(
UISettings::values.mute_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
#ifdef ENABLE_QT_UPDATE_CHECKER
#ifdef ENABLE_UPDATE_CHECKER
ui->toggle_update_checker->setChecked(
UISettings::values.check_for_update_on_start.GetValue());
Settings::values.check_for_update_on_start.GetValue());
ui->update_channel_combobox->setCurrentIndex(
UISettings::values.update_check_channel.GetValue());
Settings::values.update_check_channel.GetValue());
#endif
#ifdef __unix__
ui->toggle_gamemode->setChecked(Settings::values.enable_gamemode.GetValue());
@ -182,9 +182,9 @@ void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
#ifdef ENABLE_QT_UPDATE_CHECKER
UISettings::values.check_for_update_on_start = ui->toggle_update_checker->isChecked();
UISettings::values.update_check_channel = ui->update_channel_combobox->currentIndex();
#ifdef ENABLE_UPDATE_CHECKER
Settings::values.check_for_update_on_start = ui->toggle_update_checker->isChecked();
Settings::values.update_check_channel = ui->update_channel_combobox->currentIndex();
#endif
#ifdef __unix__
Settings::values.enable_gamemode = ui->toggle_gamemode->isChecked();

View File

@ -59,12 +59,6 @@ enum class GameListText : s32 {
ListEnd, ///< Keep this at the end of the enum.
};
class UpdateCheckChannels {
public:
static constexpr int STABLE = 0;
static constexpr int PRERELEASE = 1;
};
struct Values {
QByteArray geometry;
QByteArray state;
@ -89,11 +83,6 @@ struct Values {
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::Setting<bool> hide_mouse{false, "hideInactiveMouse"};
#ifdef ENABLE_QT_UPDATE_CHECKER
Settings::Setting<bool> check_for_update_on_start{true, "check_for_update_on_start"};
Settings::Setting<int> update_check_channel{UpdateCheckChannels::STABLE,
"update_check_channel"};
#endif
Settings::Setting<std::string> inserted_cartridge{"", "inserted_cartridge"};

View File

@ -176,4 +176,10 @@ if (SSE42_COMPILE_OPTION)
target_compile_options(citra_common PRIVATE ${SSE42_COMPILE_OPTION})
endif()
target_link_libraries(citra_common PUBLIC xxHash::xxhash)
target_link_libraries(citra_common PUBLIC xxHash::xxhash)
if (ENABLE_UPDATE_CHECKER)
target_link_libraries(citra_common PRIVATE httplib json-headers)
target_sources(citra_common PRIVATE update_checker.cpp)
target_compile_definitions(citra_common PUBLIC ENABLE_UPDATE_CHECKER)
endif()

View File

@ -19,6 +19,13 @@
namespace Settings {
class UpdateCheckChannels {
public:
static constexpr int STABLE = 0;
static constexpr int PRERELEASE = 1;
};
enum class GraphicsAPI {
Software = 0,
OpenGL = 1,
@ -642,6 +649,11 @@ struct Values {
// Miscellaneous
Setting<std::string> log_filter{"*:Info", Keys::log_filter};
Setting<std::string> log_regex_filter{"", Keys::log_regex_filter};
#ifdef ENABLE_UPDATE_CHECKER
Settings::Setting<bool> check_for_update_on_start{true, Keys::check_for_update_on_start};
Settings::Setting<int> update_check_channel{UpdateCheckChannels::STABLE,
Keys::update_check_channel};
#endif
// Video Dumping
std::string output_format;

View File

@ -7,9 +7,14 @@
#include <fmt/format.h>
#include <httplib.h>
#include <json.hpp>
#include "common/logging/log.h"
#include "logging/log.h"
#include "update_checker.h"
std::string g_ca_cert_path;
void UpdateChecker::SetCACertPath(std::string path) {
g_ca_cert_path = std::move(path);
}
std::optional<std::string> GetResponse(std::string url, std::string path) {
constexpr std::size_t timeout_seconds = 15;
@ -18,6 +23,8 @@ std::optional<std::string> GetResponse(std::string url, std::string path) {
client->set_read_timeout(timeout_seconds);
client->set_write_timeout(timeout_seconds);
client->set_ca_cert_path(g_ca_cert_path.c_str());
if (client == nullptr) {
LOG_ERROR(Frontend, "Invalid URL {}{}", url, path);
return {};
@ -50,7 +57,9 @@ std::optional<std::string> GetResponse(std::string url, std::string path) {
}
std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prereleases) {
constexpr auto update_check_url = "http://api.github.com";
std::string update_check_path = "/repos/azahar-emu/azahar";
try {
if (include_prereleases) { // This can return either a prerelease or a stable release,

View File

@ -9,4 +9,5 @@
namespace UpdateChecker {
std::optional<std::string> GetLatestRelease(bool);
void SetCACertPath(std::string path);
}