From abd000fe2515b21c6b7f59bfcbed67c40039b4bd Mon Sep 17 00:00:00 2001 From: pillownara <112834231+pillownara@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:02:18 +0700 Subject: [PATCH 1/2] chore: update compileSdk and targetSdk to Android 17 (API 37) --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1739f1e..0e04a0c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,11 +20,11 @@ val latestTag = repo?.latestTag?.removePrefix("v") ?: "1.0" android { namespace = "com.parallelc.micts" - compileSdk = 36 + compileSdk = 37 defaultConfig { minSdk = 28 - targetSdk = 36 + targetSdk = 37 versionCode = commitCount versionName = latestTag From bef37de3fcf5a270745fb70099304a062134cc0d Mon Sep 17 00:00:00 2001 From: pillownara <112834231+pillownara@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:23:23 +0700 Subject: [PATCH 2/2] fix(android17): wrap reflection to R$string fields with try-catch for Android 17+ compatibility Android 17 blocks reflection to static final fields. VIMSHooker and CSMSHooker access config strings via reflection, which will throw IllegalAccessException on Android 17+. Wrap with runCatching and fallback to -1 if field access fails. Fixes: Android 17 (API 37) compatibility issue --- .../java/com/parallelc/micts/hooker/CSMSHooker.kt | 9 ++++++++- .../java/com/parallelc/micts/hooker/VIMSHooker.kt | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/parallelc/micts/hooker/CSMSHooker.kt b/app/src/main/java/com/parallelc/micts/hooker/CSMSHooker.kt index 9473064..baad5ae 100644 --- a/app/src/main/java/com/parallelc/micts/hooker/CSMSHooker.kt +++ b/app/src/main/java/com/parallelc/micts/hooker/CSMSHooker.kt @@ -20,7 +20,14 @@ class CSMSHooker { @SuppressLint("PrivateApi") fun hook(param: SystemServerStartingParam) { val rString = param.classLoader.loadClass("com.android.internal.R\$string") - contextualSearchPackageName = rString.getField("config_defaultContextualSearchPackageName").getInt(null) + + // Android 17+: Handle reflection to static final fields with try-catch + contextualSearchPackageName = runCatching { + rString.getField("config_defaultContextualSearchPackageName").getInt(null) + }.onFailure { e -> + module!!.log(Log.WARN, "MiCTS", "Failed to get config_defaultContextualSearchPackageName on Android 17+", e) + }.getOrElse { -1 } + val systemServer = param.classLoader.loadClass("com.android.server.SystemServer") module!!.hook(systemServer.getDeclaredMethod("deviceHasConfigString", Context::class.java, Int::class.java)) .intercept(DeviceHasConfigStringHooker()) diff --git a/app/src/main/java/com/parallelc/micts/hooker/VIMSHooker.kt b/app/src/main/java/com/parallelc/micts/hooker/VIMSHooker.kt index 6b50e14..bf8519b 100644 --- a/app/src/main/java/com/parallelc/micts/hooker/VIMSHooker.kt +++ b/app/src/main/java/com/parallelc/micts/hooker/VIMSHooker.kt @@ -25,8 +25,18 @@ class VIMSHooker { fun hook(param: SystemServerStartingParam) { val vimsStub = param.classLoader.loadClass("com.android.server.voiceinteraction.VoiceInteractionManagerService\$VoiceInteractionManagerServiceStub") val rString = param.classLoader.loadClass("com.android.internal.R\$string") - contextualSearchKey = rString.getField("config_defaultContextualSearchKey").getInt(null) - contextualSearchPackageName = rString.getField("config_defaultContextualSearchPackageName").getInt(null) + // Android 17+: Handle reflection to static final fields with try-catch + contextualSearchKey = runCatching { + rString.getField("config_defaultContextualSearchKey").getInt(null) + }.onFailure { e -> + module!!.log(Log.WARN, "MiCTS", "Failed to get config_defaultContextualSearchKey on Android 17+", e) + }.getOrElse { -1 } + + contextualSearchPackageName = runCatching { + rString.getField("config_defaultContextualSearchPackageName").getInt(null) + }.onFailure { e -> + module!!.log(Log.WARN, "MiCTS", "Failed to get config_defaultContextualSearchPackageName on Android 17+", e) + }.getOrElse { -1 } module!!.hook(vimsStub.getDeclaredMethod("showSessionFromSession", IBinder::class.java, Bundle::class.java, Int::class.java, String::class.java)).intercept(ShowSessionHooker()) }