kernel:Add Dynamic Signature Configuration

This commit is contained in:
ShirkNeko
2025-07-05 16:21:29 +08:00
parent 6a60b72e21
commit dd6d695020
13 changed files with 690 additions and 12 deletions

View File

@@ -95,6 +95,27 @@ object Natives {
*/
external fun getSusfsFeatureStatus(): SusfsFeatureStatus?
/**
* Set dynamic signature configuration
* @param size APK signature size
* @param hash APK signature hash (64 character hex string)
* @return true if successful, false otherwise
*/
external fun setDynamicSign(size: Int, hash: String): Boolean
/**
* Get current dynamic signature configuration
* @return DynamicSignConfig object containing current configuration, or null if not set
*/
external fun getDynamicSign(): DynamicSignConfig?
/**
* Clear dynamic signature configuration
* @return true if successful, false otherwise
*/
external fun clearDynamicSign(): Boolean
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val NOBODY_UID = 9999
@@ -147,6 +168,21 @@ object Natives {
val statusSusSu: Boolean = false
) : Parcelable
@Immutable
@Parcelize
@Keep
data class DynamicSignConfig(
val size: Int = 0,
val hash: String = ""
) : Parcelable {
constructor() : this(0, "")
fun isValid(): Boolean {
return size > 0 && hash.length == 64 && hash.all {
it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F'
}
}
}
@Immutable
@Parcelize

View File

@@ -145,6 +145,13 @@ fun MoreSettingsScreen(
var showDpiConfirmDialog by remember { mutableStateOf(false) }
var showImageEditor by remember { mutableStateOf(false) }
// 动态签名配置状态
var dynamicSignConfig by remember { mutableStateOf<Natives.DynamicSignConfig?>(null) }
var isDynamicSignEnabled by remember { mutableStateOf(false) }
var dynamicSignSize by remember { mutableStateOf("") }
var dynamicSignHash by remember { mutableStateOf("") }
var showDynamicSignDialog by remember { mutableStateOf(false) }
// 主题模式选项
val themeOptions = listOf(
stringResource(R.string.theme_follow_system),
@@ -652,6 +659,147 @@ fun MoreSettingsScreen(
)
}
LaunchedEffect(Unit) {
// 初始化动态签名配置
dynamicSignConfig = Natives.getDynamicSign()
dynamicSignConfig?.let { config ->
if (config.isValid()) {
isDynamicSignEnabled = true
dynamicSignSize = config.size.toString()
dynamicSignHash = config.hash
}
}
}
// 动态签名配置对话框
if (showDynamicSignDialog) {
AlertDialog(
onDismissRequest = { showDynamicSignDialog = false },
title = { Text(stringResource(R.string.dynamic_sign_title)) },
text = {
Column(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
// 启用开关
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { isDynamicSignEnabled = !isDynamicSignEnabled }
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Switch(
checked = isDynamicSignEnabled,
onCheckedChange = { isDynamicSignEnabled = it }
)
Spacer(modifier = Modifier.width(12.dp))
Text(stringResource(R.string.enable_dynamic_sign))
}
Spacer(modifier = Modifier.height(16.dp))
// 签名大小输入
androidx.compose.material3.OutlinedTextField(
value = dynamicSignSize,
onValueChange = { dynamicSignSize = it },
label = { Text(stringResource(R.string.signature_size)) },
enabled = isDynamicSignEnabled,
modifier = Modifier.fillMaxWidth(),
singleLine = true,
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(
keyboardType = androidx.compose.ui.text.input.KeyboardType.Number
)
)
Spacer(modifier = Modifier.height(12.dp))
// 签名哈希输入
androidx.compose.material3.OutlinedTextField(
value = dynamicSignHash,
onValueChange = { hash ->
// 只允许十六进制字符
if (hash.all { it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F' }) {
dynamicSignHash = hash
}
},
label = { Text(stringResource(R.string.signature_hash)) },
enabled = isDynamicSignEnabled,
modifier = Modifier.fillMaxWidth(),
singleLine = true,
supportingText = {
Text(stringResource(R.string.hash_must_be_64_chars))
},
isError = isDynamicSignEnabled && dynamicSignHash.isNotEmpty() && dynamicSignHash.length != 64
)
}
},
confirmButton = {
Button(
onClick = {
if (isDynamicSignEnabled) {
val size = dynamicSignSize.toIntOrNull()
if (size != null && size > 0 && dynamicSignHash.length == 64) {
val success = Natives.setDynamicSign(size, dynamicSignHash)
if (success) {
dynamicSignConfig = Natives.DynamicSignConfig(size, dynamicSignHash)
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_set_success),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_set_failed),
Toast.LENGTH_SHORT
).show()
}
} else {
Toast.makeText(
context,
context.getString(R.string.invalid_sign_config),
Toast.LENGTH_SHORT
).show()
return@Button
}
} else {
val success = Natives.clearDynamicSign()
if (success) {
dynamicSignConfig = null
dynamicSignSize = ""
dynamicSignHash = ""
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_disabled_success),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_clear_failed),
Toast.LENGTH_SHORT
).show()
return@Button
}
}
showDynamicSignDialog = false
},
enabled = if (isDynamicSignEnabled) {
dynamicSignSize.toIntOrNull()?.let { it > 0 } == true &&
dynamicSignHash.length == 64
} else true
) {
Text(stringResource(R.string.confirm))
}
},
dismissButton = {
TextButton(onClick = { showDynamicSignDialog = false }) {
Text(stringResource(R.string.cancel))
}
}
)
}
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
@@ -1226,6 +1374,17 @@ fun MoreSettingsScreen(
}
)
}
// 动态签名设置
SettingItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.dynamic_sign_title),
subtitle = if (isDynamicSignEnabled) {
stringResource(R.string.dynamic_sign_enabled_summary, dynamicSignSize)
} else {
stringResource(R.string.dynamic_sign_disabled)
},
onClick = { showDynamicSignDialog = true }
)
}
}
}