diff --git a/manager/src/main/java/nkbe/util/ShizukuApi.kt b/manager/src/main/java/nkbe/util/ShizukuApi.kt index 0fe7c3d..472b7b7 100644 --- a/manager/src/main/java/nkbe/util/ShizukuApi.kt +++ b/manager/src/main/java/nkbe/util/ShizukuApi.kt @@ -42,6 +42,15 @@ object ShizukuApi { var isBinderAvailable = false var isPermissionGranted by mutableStateOf(false) + fun getBackendUidOrNull(): Int? { + if (!isBinderAvailable || !isPermissionGranted) return null + return runCatching { Shizuku.getUid() } + .getOrNull() + ?.takeIf { it >= 0 } + } + + fun isRootBackend(): Boolean = getBackendUidOrNull() == 0 + fun init() { Shizuku.addBinderReceivedListenerSticky { isBinderAvailable = true diff --git a/manager/src/main/java/org/lsposed/npatch/ui/page/manage/AppManagePage.kt b/manager/src/main/java/org/lsposed/npatch/ui/page/manage/AppManagePage.kt index f9e5e79..b98a2b4 100644 --- a/manager/src/main/java/org/lsposed/npatch/ui/page/manage/AppManagePage.kt +++ b/manager/src/main/java/org/lsposed/npatch/ui/page/manage/AppManagePage.kt @@ -114,11 +114,16 @@ fun AppManageBody( is ProcessingState.Idle -> Unit is ProcessingState.Processing -> LoadingDialog() is ProcessingState.Done -> { - val it = viewModel.optimizeState as ProcessingState.Done + val it = viewModel.optimizeState as ProcessingState.Done val optimizeSucceed = stringResource(R.string.manage_optimize_successfully) val optimizeFailed = stringResource(R.string.manage_optimize_failed) LaunchedEffect(Unit) { - snackbarHost.showSnackbar(if (it.result) optimizeSucceed else optimizeFailed) + val message = if (it.result.success) { + optimizeSucceed + } else { + it.result.messageRes?.let { resId -> lspApp.getString(resId) } ?: optimizeFailed + } + snackbarHost.showSnackbar(message) viewModel.dispatch(AppManageViewModel.ViewAction.ClearOptimizeResult) } } diff --git a/manager/src/main/java/org/lsposed/npatch/ui/viewmodel/manage/AppManageViewModel.kt b/manager/src/main/java/org/lsposed/npatch/ui/viewmodel/manage/AppManageViewModel.kt index 30adcf0..d6d3117 100644 --- a/manager/src/main/java/org/lsposed/npatch/ui/viewmodel/manage/AppManageViewModel.kt +++ b/manager/src/main/java/org/lsposed/npatch/ui/viewmodel/manage/AppManageViewModel.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.lsposed.npatch.Patcher +import org.lsposed.npatch.R import org.lsposed.npatch.lspApp import org.lsposed.npatch.share.Constants import org.lsposed.npatch.share.PatchConfig @@ -45,6 +46,11 @@ class AppManageViewModel : ViewModel() { object Refresh : ViewAction() } + data class OptimizeResult( + val success: Boolean, + val messageRes: Int? = null + ) + // 手動管理狀態,避免實時響應系統廣播導致列表跳動 var appList: List> by mutableStateOf(emptyList()) private set @@ -55,7 +61,7 @@ class AppManageViewModel : ViewModel() { var updateLoaderState: ProcessingState> by mutableStateOf(ProcessingState.Idle) private set - var optimizeState: ProcessingState by mutableStateOf(ProcessingState.Idle) + var optimizeState: ProcessingState by mutableStateOf(ProcessingState.Idle) private set private val logger = object : Logger() { @@ -195,8 +201,13 @@ class AppManageViewModel : ViewModel() { Log.i(TAG, "Perform optimize for ${appInfo.app.packageName}") optimizeState = ProcessingState.Processing val result = withContext(Dispatchers.IO) { - ShizukuApi.performDexOptMode(appInfo.app.packageName) + if (!ShizukuApi.isRootBackend()) { + Log.w(TAG, "Optimize refused: Shizuku backend is not root, uid=${ShizukuApi.getBackendUidOrNull()}") + OptimizeResult(success = false, messageRes = R.string.manage_optimize_permission_denied) + } else { + OptimizeResult(success = ShizukuApi.performDexOptMode(appInfo.app.packageName)) + } } optimizeState = ProcessingState.Done(result) } -} \ No newline at end of file +} diff --git a/manager/src/main/res/values-zh-rCN/strings.xml b/manager/src/main/res/values-zh-rCN/strings.xml index e1a3f81..968a25d 100644 --- a/manager/src/main/res/values-zh-rCN/strings.xml +++ b/manager/src/main/res/values-zh-rCN/strings.xml @@ -41,6 +41,7 @@ 优化 优化成功 优化失败 + 权限不足:优化功能要求 Shizuku 运行在 Root 特权下 卸载成功 尚无模块 模块设置 diff --git a/manager/src/main/res/values/strings.xml b/manager/src/main/res/values/strings.xml index 6b7f7ee..bf54a99 100644 --- a/manager/src/main/res/values/strings.xml +++ b/manager/src/main/res/values/strings.xml @@ -42,6 +42,7 @@ Optimize Optimize successfully Optimize failed + Insufficient privilege: optimize requires Shizuku running as root Uninstall successfully No modules yet Module settings