Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/release-notes/versions/1.8.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### PVM2 零转换失败诊断修复

- 修复“已匹配到业务类,但没有可转换的方法”时,实际跳过原因和覆盖率报告随临时目录丢失的问题。现在会显示匹配类数、方法数及分类原因,并在输出目录保留独立的失败报告。
- APK、AAB 与命令行共用报告保留逻辑;桌面端复制诊断摘要只包含固定原因分类和数量,不包含路径、证书、密码、包名或业务方法名。
- 修正构造器、静态初始化器及无代码方法被类级排除原因覆盖的问题;报告无法读取或保存时明确提示,避免继续指向不存在的报告。
- 增加 Native 方法、界面类排除和寄存器超限等零转换场景的真实打包器回归,并验证 APK/AAB 失败报告保留与摘要脱敏。

### 使用说明

- 本版修复失败原因丢失和诊断不准确,不改变 PVM2 方法转换的支持范围。仍无可转换方法时会阻断交付,不会静默关闭保护。
- 遇到同类报错,请升级后重新执行,并优先提供复制的诊断摘要。输出目录中的完整失败报告可能包含业务类和方法信息,分享前请手动脱敏。
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/shield-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shield-cli"
version = "1.8.0"
version = "1.8.1"
edition = "2021"
authors = ["MocikaDev"]
license = "MIT OR Apache-2.0"
Expand Down
6 changes: 5 additions & 1 deletion apps/shield-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,11 @@ pub fn run_protect_aab_with_control(
progress(&step, &event.message);
},
Arc::clone(&cancel),
)?;
)
.map_err(|mut error| {
shield_core::protection_report::Pvm2Failure::preserve(&mut error, &args.output);
error
})?;
}
ProtectionEngineArg::Xop => {
let packer = args
Expand Down
4 changes: 2 additions & 2 deletions apps/shield-gui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/shield-gui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mocika-shield-gui",
"version": "1.8.0",
"version": "1.8.1",
"license": "MIT OR Apache-2.0",
"private": true,
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion apps/shield-gui/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mocika-shield"
version = "1.8.0"
version = "1.8.1"
edition = "2021"
license = "MIT OR Apache-2.0"
publish = false
Expand Down
2 changes: 1 addition & 1 deletion apps/shield-gui/src-tauri/src/aab_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ pub(crate) async fn execute_protect_aab(
if cancel.load(Ordering::Relaxed) {
ExecutionFailure::cancelled()
} else {
ExecutionFailure::from(format!("{error:#}"))
ExecutionFailure::from_source(format!("{error:#}"), error.as_ref())
}
})?;
task_manager
Expand Down
40 changes: 39 additions & 1 deletion apps/shield-gui/src-tauri/src/failure_diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! 将任务失败映射为受控诊断;不负责发送或持久化原始错误。
use serde::{Deserialize, Serialize};
use shield_core::diagnostic::{Diagnostic, FailureCode, ToolName, CLASSIFIER_VERSION};
use shield_core::protection_report::{Pvm2Failure, Pvm2FailureSummary};

#[derive(Clone, Debug)]
pub(crate) struct ExecutionFailure {
Expand All @@ -9,6 +10,7 @@ pub(crate) struct ExecutionFailure {
pub(crate) cancelled: bool,
/// 空字段等前置输入校验不属于已执行操作失败。
pub(crate) executed: bool,
pub(crate) pvm2_failure: Option<Pvm2FailureSummary>,
}

impl ExecutionFailure {
Expand All @@ -18,6 +20,7 @@ impl ExecutionFailure {
diagnostic: Diagnostic::new(FailureCode::Unknown),
cancelled: true,
executed: false,
pvm2_failure: None,
}
}
pub(crate) fn diagnosed(message: String, diagnostic: Diagnostic) -> Self {
Expand All @@ -26,6 +29,7 @@ impl ExecutionFailure {
diagnostic,
cancelled: false,
executed: true,
pvm2_failure: None,
}
}
pub(crate) fn preflight(message: String, diagnostic: Diagnostic) -> Self {
Expand All @@ -34,25 +38,58 @@ impl ExecutionFailure {
diagnostic,
cancelled: false,
executed: false,
pvm2_failure: None,
}
}
pub(crate) fn from_shield(error: shield_core::ShieldError) -> Self {
let pvm2_failure = match &error {
shield_core::ShieldError::Other(source) => source
.downcast_ref::<Pvm2Failure>()
.map(|f| f.summary.clone()),
_ => None,
};
let preflight = match &error {
shield_core::ShieldError::Other(source) => {
shield_core::diagnostic::is_preflight_error(source)
}
_ => false,
};
match Diagnostic::from_shield(&error) {
let mut failure = match Diagnostic::from_shield(&error) {
Some(diagnostic) if preflight => Self::preflight(error.to_string(), diagnostic),
Some(diagnostic) => Self::diagnosed(error.to_string(), diagnostic),
None => Self {
message: "已取消".into(),
diagnostic: Diagnostic::new(FailureCode::Unknown),
cancelled: true,
executed: false,
pvm2_failure: None,
},
};
failure.pvm2_failure = pvm2_failure;
failure
}

pub(crate) fn from_source(message: String, error: &(dyn std::error::Error + 'static)) -> Self {
let mut failure = Self::from(message);
let mut cause = Some(error);
while let Some(value) = cause {
if let Some(pvm2) = value.downcast_ref::<Pvm2Failure>() {
failure.pvm2_failure = Some(pvm2.summary.clone());
break;
}
if let Some(shield_core::ShieldError::Other(source)) =
value.downcast_ref::<shield_core::ShieldError>()
{
failure.pvm2_failure = source
.downcast_ref::<Pvm2Failure>()
.map(|f| f.summary.clone());
if failure.pvm2_failure.is_some() {
break;
}
}
cause = value.source();
}
failure
}
}
impl From<String> for ExecutionFailure {
Expand All @@ -62,6 +99,7 @@ impl From<String> for ExecutionFailure {
diagnostic: Diagnostic::new(FailureCode::Unknown),
cancelled: false,
executed: true,
pvm2_failure: None,
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions apps/shield-gui/src-tauri/src/ios_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ pub(crate) async fn protect_ios_project(
Err(message) if message.contains("已取消") => TaskStatus::Cancelled,
Err(_) => TaskStatus::Failed,
};
let _ = task_manager.finish(&window, &options.1, status, result.as_ref().err().cloned());
let _ = task_manager.finish(
&window,
&options.1,
status,
result.as_ref().err().cloned(),
None,
);
result
}

Expand Down Expand Up @@ -146,7 +152,13 @@ pub(crate) async fn prepare_ios_sdk(
Err(message) if message.contains("已取消") => TaskStatus::Cancelled,
Err(_) => TaskStatus::Failed,
};
let _ = task_manager.finish(&window, &task_id, status, result.as_ref().err().cloned());
let _ = task_manager.finish(
&window,
&task_id,
status,
result.as_ref().err().cloned(),
None,
);
result
}

Expand Down
4 changes: 4 additions & 0 deletions apps/shield-gui/src-tauri/src/task_completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ pub(crate) fn finish_task(
task_id,
status,
result.as_ref().err().map(|error| error.message.clone()),
result
.as_ref()
.err()
.and_then(|error| error.pvm2_failure.clone()),
)? {
window
.state::<crate::application_sharing::SharingState>()
Expand Down
4 changes: 4 additions & 0 deletions apps/shield-gui/src-tauri/src/task_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub(crate) struct TaskSnapshot {
pub(crate) finished_at_ms: Option<u64>,
pub(crate) logs: Vec<TaskLog>,
pub(crate) error: Option<String>,
pub(crate) pvm2_failure: Option<shield_core::protection_report::Pvm2FailureSummary>,
#[serde(skip)]
pub(crate) protect_succeeded: bool,
#[serde(skip)]
Expand Down Expand Up @@ -103,6 +104,7 @@ impl TaskManager {
message: "任务已开始".to_string(),
}],
error: None,
pvm2_failure: None,
protect_succeeded: false,
signing_started: false,
};
Expand Down Expand Up @@ -158,6 +160,7 @@ impl TaskManager {
task_id: &str,
status: TaskStatus,
error: Option<String>,
pvm2_failure: Option<shield_core::protection_report::Pvm2FailureSummary>,
) -> Result<bool, String> {
let mut tasks = self.0.lock().map_err(|_| "任务状态锁已损坏".to_string())?;
let task = tasks
Expand All @@ -169,6 +172,7 @@ impl TaskManager {
}
task.finished_at_ms = Some(now);
task.error = error.clone();
task.pvm2_failure = pvm2_failure;
task.logs.push(TaskLog {
timestamp_ms: now,
step: task.current_step.clone(),
Expand Down
8 changes: 7 additions & 1 deletion apps/shield-gui/src-tauri/src/updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,13 @@ pub(crate) async fn install_update(
Ok(())
}
Err(error) => {
let _ = tasks.finish(&window, &task_id, TaskStatus::Failed, Some(error.clone()));
let _ = tasks.finish(
&window,
&task_id,
TaskStatus::Failed,
Some(error.clone()),
None,
);
Err(error)
}
}
Expand Down
2 changes: 1 addition & 1 deletion apps/shield-gui/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Shellsmith",
"version": "1.8.0",
"version": "1.8.1",
"identifier": "dev.mocika.shield-gui",
"build": {
"beforeDevCommand": "npm run dev -- --host 127.0.0.1",
Expand Down
2 changes: 1 addition & 1 deletion apps/shield-gui/src/components/app/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export function StatusMessage({
)}
/>
)}
<div className="min-w-0 break-words">{children}</div>
<div className="min-w-0 whitespace-pre-line break-words">{children}</div>
</div>
{action}
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/shield-gui/src/hooks/use-about-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type AppInfo = {
};

const defaultAppInfo: AppInfo = {
version: "1.8.0",
version: "1.8.1",
git_hash: "dev",
build_date: "unknown",
};
Expand Down
6 changes: 6 additions & 0 deletions apps/shield-gui/src/hooks/use-protect-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function useProtectWorkflow({
const [dragActive, setDragActive] = useState(false);
const [warning, setWarning] = useState("");
const [error, setError] = useState("");
const [pvm2Failure, setPvm2Failure] = useState<TaskSnapshot["pvm2_failure"]>(null);
const [precheck, setPrecheck] = useState("");
const [preflight, setPreflight] = useState<ApkCheckResult | null>(null);
const [runtimeUi, setRuntimeUi] = useState(defaults.runtime_ui ?? defaultRuntimeUi);
Expand Down Expand Up @@ -119,6 +120,7 @@ export function useProtectWorkflow({
setFilenameEdited(false);
setState("idle");
setError("");
setPvm2Failure(null);
setPrecheck("");
setPreflight(null);
setWarning("");
Expand Down Expand Up @@ -157,6 +159,7 @@ export function useProtectWorkflow({
}
setWarning("");
setError("");
setPvm2Failure(null);
setPrecheck("");
setPreflight(null);
setCurrentStep("");
Expand Down Expand Up @@ -219,6 +222,7 @@ export function useProtectWorkflow({
onTauriEvent<TaskSnapshot>("task-state", (payload) => {
if (payload.kind !== "protect" || payload.task_id !== taskId.current) return;
setCurrentStep(payload.current_step);
setPvm2Failure(payload.pvm2_failure ?? null);
setCurrentDetail(payload.logs.at(-1)?.message ?? "");
setStartedAt(payload.started_at_ms);
setFinishedAt(payload.finished_at_ms ?? null);
Expand Down Expand Up @@ -292,6 +296,7 @@ export function useProtectWorkflow({
started = true;
setExcludedAbis(exclusions);
setError("");
setPvm2Failure(null);
setCurrentStep("CheckTools");
setCurrentDetail("");
setStartedAt(Date.now());
Expand Down Expand Up @@ -365,6 +370,7 @@ export function useProtectWorkflow({
dragActive,
warning,
error,
pvm2Failure,
precheck,
preflight,
runtimeMode,
Expand Down
Loading
Loading