diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 84352e59..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-app/src/main/assets/appverifier_rs-third-party-licenses.html linguist-detectable=false
-appverifier_rs/about.hbs linguist-detectable=false
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index ae3f30ae..6d0ee1c2 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index eadda98d..e631c9c3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,19 +4,10 @@ Thanks for your interest in contributing!
If you want to suggest a feature or notify us about a bug, please use the issue tracker.
-If you want to contribute to the internal verification info database, you currently must contribute in code form.
-You can use IntelliJ IDEA Community edition, which is what the lead developer, soupslurpr uses.
-It is available at https://www.jetbrains.com/idea/download/?section=windows#:~:text=free%20to%20use-,IntelliJ%20IDEA%20Community%20Edition,-The%20IDE%20for
+Before working on a feature, please make sure to discuss the planned implementation in the issue for
+the feature and get approval from @soupslurpr to ensure it meets the project's requirements.
-Open the file at app/src/main/kotlin/dev/soupslurpr/appverifier/InternalVerificationInfoDatabase.kt for the database and start adding entries from the bottom.
-Use AppVerifier (with "Show hasMultipleSigners" on in Settings) to get the verification info.
-Other tools may not provide all the needed info or hashes so do not use them.
-You must check the app's website or repo to see which sources they say the app is officially available from (view INTERNAL_DATABASE_CRITERIA.md),
-and check the verification info of each source to see if it's the same. If the package name is
-the same but not the hashes, then you have to make a `Hashes` in the same `InternalDatabaseVerificationInfo` with the hashes for the app from that source and whether it has multiple signers.
-If the package name is different, then create another `InternalDatabaseVerificationInfo`.
-Please view the comment for `InternalDatabaseVerificationInfo` for more info and examples.
-Make one pull request for every app instead of multiple apps in one pull request.
+Contributions to the internal verification info database might not be accepted at this time.
If you need help with development or have questions it's recommended to join the AppVerifier room on Matrix at
https://matrix.to/#/#appverifier:matrix.org and ask for help there from [soupslurpr](https://github.com/soupslurpr),
diff --git a/README.md b/README.md
index 30307536..09f1eef5 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,10 @@ AppVerifier is an app signing certificate hash viewer and verifier.\
It enables you to easily verify that your apps are genuine with others!
AppVerifier takes the app's package name and signing certificates hash(es) and compares them to the ones you provided or the ones in the internal database to verify that your apps are genuine.\
-If an app isn't on the internal database yet, you can simply share the verification info to others and receive verification info from them and
+You can simply share the verification info to others and receive verification info from them and
share the received verification info to AppVerifier and you will see the verification status.\
AppVerifier does the heavy lifting for you 💪
-Check [CONTRIBUTING.md](CONTRIBUTING.md) if you'd like to contribute to the internal database.
-
## Download
AppVerifier is available on the [Accrescent](https://accrescent.app) app store and GitHub releases. [Accrescent](https://accrescent.app) is the recommended way to get AppVerifier as it is more secure than GitHub releases.\
diff --git a/app/.gitignore b/app/.gitignore
index 42afabfd..956c004d 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1 +1,2 @@
-/build
\ No newline at end of file
+/build
+/release
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 82b34efa..fcb54814 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
+ id("org.jetbrains.kotlin.plugin.compose") version "2.0.0"
}
android {
@@ -11,13 +12,17 @@ android {
applicationId = "dev.soupslurpr.appverifier"
minSdk = 28
targetSdk = 34
- versionCode = 9
- versionName = "0.7.0"
+ versionCode = 10
+ versionName = "0.8.0"
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
+
+ ndk {
+ abiFilters.clear()
+ abiFilters.addAll(listOf("arm64-v8a", "x86_64"))
+ }
}
compileOptions {
@@ -32,12 +37,7 @@ android {
buildConfig = true
}
composeOptions {
- kotlinCompilerExtensionVersion = "1.5.9"
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
+ kotlinCompilerExtensionVersion = "1.5.14"
}
androidResources {
generateLocaleConfig = true
@@ -63,15 +63,9 @@ android {
signingConfig = signingConfigs.getByName("debug")
}
}
- bundle {
- language {
- /** Disable splits for language for now since Accrescent does not support automatically
- * fetching language splits when language is changed and instead needs a reinstall of the app.
- * Remove once Accrescent gets support.
- */
- enableSplit = false
- }
- }
+ // Useless since we don't publish to the Google Play Store and they are the only ones who can
+ // view it.
+ // Reference: https://developer.android.com/reference/tools/gradle-api/8.6/com/android/build/api/dsl/DependenciesInfo
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
@@ -81,15 +75,15 @@ android {
}
dependencies {
- implementation("androidx.core:core-ktx:1.12.0")
- implementation("androidx.activity:activity-compose:1.8.2")
- implementation("androidx.navigation:navigation-compose:2.7.7")
- implementation("androidx.datastore:datastore-preferences:1.0.0")
+ implementation("androidx.core:core-ktx:1.13.1")
+ implementation("androidx.activity:activity-compose:1.9.0")
+ implementation("androidx.navigation:navigation-compose:2.8.0-beta05")
+ implementation("androidx.datastore:datastore-preferences:1.1.1")
implementation("androidx.compose.material:material-icons-extended")
- implementation("com.google.android.material:material:1.11.0")
- implementation("com.google.accompanist:accompanist-drawablepainter:0.33.2-alpha")
+ implementation("com.google.accompanist:accompanist-drawablepainter:0.35.1-alpha")
- implementation(platform("androidx.compose:compose-bom:2024.02.00"))
- implementation("androidx.compose.ui:ui-tooling-preview")
+ implementation(platform("androidx.compose:compose-bom:2024.06.00"))
implementation("androidx.compose.material3:material3")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ debugImplementation("androidx.compose.ui:ui-tooling")
}
diff --git a/app/release/signing-command.txt b/app/release/signing-command.txt
deleted file mode 100644
index 842a4521..00000000
--- a/app/release/signing-command.txt
+++ /dev/null
@@ -1 +0,0 @@
-java -jar ./bundletool-all-1.15.6.jar build-apks --bundle="./app-release.aab" --output="./AppVerifier-app-release.apks" --overwrite --ks-key-alias="key0" --ks="/Users/user/AppVerifierkeystore.jks" --ks-pass=pass:""
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 52528ca8..13bcd662 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,14 +15,13 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:memtagMode="async"
- android:theme="@style/Theme.appverifier"
- tools:targetApi="34">
+ android:theme="@style/Theme.AppVerifier"
+ tools:targetApi="33">
+ android:documentLaunchMode="intoExisting">
diff --git a/app/src/main/kotlin/dev/soupslurpr/appverifier/AppVerifier.kt b/app/src/main/kotlin/dev/soupslurpr/appverifier/AppVerifier.kt
index 4752dca1..90cc4fdf 100644
--- a/app/src/main/kotlin/dev/soupslurpr/appverifier/AppVerifier.kt
+++ b/app/src/main/kotlin/dev/soupslurpr/appverifier/AppVerifier.kt
@@ -4,6 +4,15 @@ import android.graphics.drawable.Drawable
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
+import androidx.compose.animation.AnimatedContentScope
+import androidx.compose.animation.AnimatedContentTransitionScope
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.SizeTransform
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideIn
+import androidx.compose.animation.slideOut
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.padding
@@ -20,9 +29,15 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.IntOffset
+import androidx.navigation.NamedNavArgument
+import androidx.navigation.NavBackStackEntry
+import androidx.navigation.NavDeepLink
+import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
+import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
import dev.soupslurpr.appverifier.data.Hashes
import dev.soupslurpr.appverifier.data.InternalDatabaseInfo
@@ -37,7 +52,6 @@ import dev.soupslurpr.appverifier.ui.StartupScreen
import dev.soupslurpr.appverifier.ui.VerifyAppScreen
import dev.soupslurpr.appverifier.ui.VerifyAppViewModel
import kotlinx.coroutines.launch
-import kotlin.random.Random
enum class AppVerifierScreens(@StringRes val title: Int) {
Start(title = R.string.app_name),
@@ -80,14 +94,6 @@ fun AppVerifierApp(
// backStackEntry?.destination?.route ?: AppVerifierScreens.Start.name
// )
- val randomValue = Random.nextInt(0, 10)
- val splashMessage = rememberSaveable {
- when (randomValue) {
- 0 -> "Gotta verify 'em all!"
- else -> "App verification, but easy."
- }
- }
-
val context = LocalContext.current
val openApkFileLauncher =
@@ -122,22 +128,20 @@ fun AppVerifierApp(
AppVerifierScreens.Start.name
},
modifier = modifier.padding(
- innerPadding.calculateStartPadding(LayoutDirection.Ltr),
+ innerPadding.calculateStartPadding(LocalLayoutDirection.current),
innerPadding.calculateTopPadding(),
- innerPadding.calculateEndPadding(LayoutDirection.Ltr)
+ innerPadding.calculateEndPadding(LocalLayoutDirection.current)
),
) {
- composable(route = AppVerifierScreens.Start.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.Start) {
StartupScreen(
modifier = modifier,
- splashMessage = splashMessage,
onSettingsButtonClicked = {
navController.navigate(AppVerifierScreens.Settings.name)
},
onAppListButtonClicked = {
navController.navigate(AppVerifierScreens.AppList.name)
},
- verifyAppViewModel = verifyAppViewModel,
onVerifyApkFileButtonClicked = {
openApkFileLauncher.launch(arrayOf("application/vnd.android.package-archive"))
},
@@ -149,7 +153,7 @@ fun AppVerifierApp(
}
)
}
- composable(route = AppVerifierScreens.AppList.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.AppList) {
AppListScreen(
searchQuery,
{ name: String, packageName: String, hashes: Hashes, icon: Drawable, internalDatabaseInfo:
@@ -171,7 +175,7 @@ fun AppVerifierApp(
{ verifyAppViewModel.getInternalDatabaseInfoFromVerificationInfo(it) }
)
}
- composable(route = AppVerifierScreens.VerifyApp.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.VerifyApp) {
VerifyAppScreen(
verifyAppUiState.value.icon.value,
verifyAppUiState.value.name.value,
@@ -191,7 +195,7 @@ fun AppVerifierApp(
}
)
}
- composable(route = AppVerifierScreens.Settings.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.Settings) {
SettingsScreen(
onLicenseIconButtonClicked = {
navController.navigate(AppVerifierScreens.License.name)
@@ -208,21 +212,144 @@ fun AppVerifierApp(
}
)
}
- composable(route = AppVerifierScreens.License.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.License) {
LicenseScreen()
}
- composable(route = AppVerifierScreens.PrivacyPolicy.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.PrivacyPolicy) {
PrivacyPolicyScreen()
}
- composable(route = AppVerifierScreens.Credits.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.Credits) {
CreditsScreen()
}
- composable(route = AppVerifierScreens.Donation.name) {
+ composableWithDefaultSlideTransitions(route = AppVerifierScreens.Donation) {
DonationScreen()
}
}
}
}
+fun getStateDestinationRoute(state: NavBackStackEntry): AppVerifierScreens? {
+ state.destination.route?.let { return AppVerifierScreens.valueOf(it) }
+ return null
+}
+fun getEnterTransition(
+ initialState: NavBackStackEntry,
+ targetState: NavBackStackEntry,
+): EnterTransition {
+ val initialNavBarRoute = getStateDestinationRoute(initialState)
+ val targetNavBarRoute = getStateDestinationRoute(targetState)
+
+ return if ((initialNavBarRoute != null) && (targetNavBarRoute != null)) {
+ slideIn {
+ IntOffset(
+ if (initialNavBarRoute.ordinal > targetNavBarRoute.ordinal) {
+ -it.width
+ } else {
+ it.width
+ }, 0
+ )
+ } + fadeIn()
+ } else {
+ EnterTransition.None
+ }
+}
+
+fun getExitTransition(
+ initialState: NavBackStackEntry,
+ targetState: NavBackStackEntry,
+): ExitTransition {
+ val initialNavBarRoute = getStateDestinationRoute(initialState)
+ val targetNavBarRoute = getStateDestinationRoute(targetState)
+
+ return if ((initialNavBarRoute != null) && (targetNavBarRoute != null)) {
+ slideOut {
+ IntOffset(
+ if (initialNavBarRoute.ordinal > targetNavBarRoute.ordinal) {
+ it.width
+ } else {
+ -it.width
+ }, 0
+ )
+ } + fadeOut()
+ } else {
+ ExitTransition.None
+ }
+}
+fun NavGraphBuilder.composableWithDefaultSlideTransitions(
+ route: AppVerifierScreens,
+ arguments: List = emptyList(),
+ deepLinks: List = emptyList(),
+ enterTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition?)? = null,
+ exitTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition?)? = null,
+ popEnterTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition?)? = enterTransition,
+ popExitTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition?)? = exitTransition,
+ sizeTransform: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> SizeTransform?)? = null,
+ content: @Composable (AnimatedContentScope.(NavBackStackEntry) -> Unit),
+) {
+ composable(route.name, arguments, deepLinks, if (enterTransition == null) {
+ {
+ getEnterTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (exitTransition == null) {
+ {
+ getExitTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (popEnterTransition == null) {
+ {
+ getEnterTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (popExitTransition == null) {
+ {
+ getExitTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, sizeTransform, content)
+}
+
+fun NavGraphBuilder.navigationWithDefaultSlideTransitions(
+ startDestination: String,
+ route: AppVerifierScreens,
+ arguments: List = emptyList(),
+ deepLinks: List = emptyList(),
+ enterTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition?)? = null,
+ exitTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition?)? = null,
+ popEnterTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> EnterTransition?)? = enterTransition,
+ popExitTransition: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> ExitTransition?)? = exitTransition,
+ sizeTransform: (@JvmSuppressWildcards AnimatedContentTransitionScope.() -> SizeTransform?)? = null,
+ builder: NavGraphBuilder.() -> Unit,
+) {
+ navigation(startDestination, route.name, arguments, deepLinks, if (enterTransition == null) {
+ {
+ getEnterTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (exitTransition == null) {
+ {
+ getExitTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (popEnterTransition == null) {
+ {
+ getEnterTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, if (popExitTransition == null) {
+ {
+ getExitTransition(initialState, targetState)
+ }
+ } else {
+ null
+ }, sizeTransform, builder)
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/dev/soupslurpr/appverifier/InternalVerificationInfoDatabase.kt b/app/src/main/kotlin/dev/soupslurpr/appverifier/InternalVerificationInfoDatabase.kt
index fcf53b75..a21a344e 100644
--- a/app/src/main/kotlin/dev/soupslurpr/appverifier/InternalVerificationInfoDatabase.kt
+++ b/app/src/main/kotlin/dev/soupslurpr/appverifier/InternalVerificationInfoDatabase.kt
@@ -113,7 +113,8 @@ val internalVerificationInfoDatabase = setOf(
Source.GOOGLE_PLAY_STORE
),
listOf(
- "29:F3:4E:5F:27:F2:11:B4:24:BC:5B:F9:D6:71:62:C0:EA:FB:A2:DA:35:AF:35:C1:64:16:FC:44:62:76:BA:26"
+ "29:F3:4E:5F:27:F2:11:B4:24:BC:5B:F9:D6:71:62:C0:EA:FB:A2:DA:35:AF:35:C1:64:16:FC:44:62:76:BA:26",
+ "4B:E4:F6:CD:5B:E8:44:08:3E:90:02:79:DC:82:2A:F6:5A:54:7F:EC:C2:6A:BA:7F:F1:F5:20:3A:45:51:8C:D8"
),
false
)
diff --git a/app/src/main/kotlin/dev/soupslurpr/appverifier/ui/StartupScreen.kt b/app/src/main/kotlin/dev/soupslurpr/appverifier/ui/StartupScreen.kt
index c569854e..ef7853f0 100644
--- a/app/src/main/kotlin/dev/soupslurpr/appverifier/ui/StartupScreen.kt
+++ b/app/src/main/kotlin/dev/soupslurpr/appverifier/ui/StartupScreen.kt
@@ -19,8 +19,8 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.FileOpen
-import androidx.compose.material.icons.filled.List
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
@@ -34,17 +34,14 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import dev.soupslurpr.appverifier.R
@Composable
fun StartupScreen(
modifier: Modifier,
- splashMessage: String,
onSettingsButtonClicked: () -> Unit,
onAppListButtonClicked: () -> Unit,
- verifyAppViewModel: VerifyAppViewModel,
onVerifyApkFileButtonClicked: () -> Unit,
onLaunchedEffect: () -> Unit,
) {
@@ -74,20 +71,15 @@ fun StartupScreen(
)
}
Text(
- text = stringResource(R.string.welcome),
+ text = stringResource(R.string.app_name),
style = typography.headlineLarge
)
- Text(
- text = splashMessage,
- style = typography.bodySmall,
- textAlign = TextAlign.Center
- )
FilledTonalButton(
modifier = modifier.fillMaxWidth(),
onClick = { onAppListButtonClicked() }
) {
Icon(
- imageVector = Icons.Filled.List,
+ imageVector = Icons.AutoMirrored.Filled.List,
contentDescription = null
)
Spacer(modifier = modifier.width(8.dp))
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index ac94b34f..00000000
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap/ic_launcher.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to app/src/main/res/mipmap/ic_launcher.xml
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index 25bfa8e6..5e3e0d39 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -1,16 +1,5 @@
+
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index af3f2af2..1bcbe4a4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,7 +2,6 @@
AppVerifier
Settings
Back
- Welcome to AppVerifier!
Source code
View AppVerifier\'s source code on the GitHub website in your web browser
Privacy policy
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5bfcb8d9..c260d4e5 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 53f4a672..13884ca8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,4 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id("com.android.application") version "8.2.2" apply false
- id("org.jetbrains.kotlin.android") version "1.9.22" apply false
+ id("com.android.application") version "8.5.0" apply false
+ id("org.jetbrains.kotlin.android") version "2.0.0" apply false
}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 17655d0e..0d184210 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists