第一章:Go桌面程序的基本架构与跨平台构建原理
Go语言构建桌面程序的核心在于其静态链接特性和原生GUI库的协同设计。与传统C++或Java桌面应用依赖运行时环境不同,Go编译器将标准库、运行时及第三方依赖(如fyne或walk)全部打包进单一二进制文件,从而实现“零依赖分发”。这一特性直接支撑了跨平台能力——只需在目标操作系统上执行对应GOOS/GOARCH组合的构建命令,即可生成本地原生可执行文件。
Go构建系统的跨平台机制
Go通过环境变量控制目标平台:
GOOS指定操作系统(如windows、darwin、linux)GOARCH指定架构(如amd64、arm64)
例如,在Linux主机上交叉编译macOS应用:# 设置目标平台为macOS ARM64 GOOS=darwin GOARCH=arm64 go build -o myapp-macos ./main.go该命令不依赖macOS SDK或Xcode,完全由Go工具链内置支持,底层调用LLVM后端生成目标平台ABI兼容的机器码。
桌面程序典型分层结构
一个健壮的Go桌面应用通常包含以下逻辑层:
| 层级 | 职责 | 典型实现方式 |
|---|---|---|
| UI层 | 渲染窗口、控件与事件绑定 | fyne.io/fyne/v2 或 github.com/therecipe/qt/widgets |
| 业务逻辑层 | 处理数据流、状态管理、算法 | 纯Go函数与结构体,无平台依赖 |
| 平台适配层 | 访问系统API(通知、托盘、文件对话框) | 使用条件编译(//go:build windows)或抽象接口 |
条件编译实践示例
为实现Windows托盘图标与macOS菜单栏图标的差异化支持,可使用文件标签分离实现:
// tray_windows.go
//go:build windows
package main
func initTray() { /* Windows-specific tray logic */ }
// tray_darwin.go
//go:build darwin
package main
func initTray() { /* macOS-specific status bar logic */ }
Go构建时自动选择匹配GOOS的文件,确保各平台行为精准收敛。这种架构使开发者能以同一套业务逻辑代码,输出真正原生体验的跨平台桌面程序。
第二章:Apple Notarization认证全流程解析与实战
2.1 macOS代码签名机制与Go二进制签名实践
macOS强制执行 Hardened Runtime 和 Gatekeeper 验证,未签名或签名失效的Go程序将被系统拦截。
签名前必备条件
- Apple Developer ID 证书(本地钥匙串中显示为
3rd Party Mac Developer Application) - 启用
com.apple.security.cs.allow-jit等必要 entitlements(尤其对CGO或反射密集型Go程序)
签名流程示意
# 构建带调试信息的可执行文件
go build -o myapp .
# 嵌入自定义entitlements(如允许动态代码生成)
codesign --entitlements entitlements.plist \
--sign "3rd Party Mac Developer Application: Your Name (ABC123)" \
--deep --force \
--options=runtime \
myapp
--options=runtime启用 hardened runtime;--deep递归签名所有嵌套资源(如 embedded dylib 或 cgo 依赖);--force覆盖已有签名。
常见签名状态验证
| 状态 | 命令 | 输出含义 |
|---|---|---|
| 有效签名 | codesign -v myapp |
无输出即成功 |
| 权限详情 | codesign -d --entitlements :- myapp |
显示 JSON 格式 entitlements |
| 全链校验 | spctl --assess --verbose=4 myapp |
Gatekeeper 级别评估结果 |
graph TD
A[Go源码] --> B[go build]
B --> C[未签名二进制]
C --> D[codesign + entitlements]
D --> E[Gatekeeper可运行]
2.2 Apple Developer账号配置与证书/Provisioning Profile自动化管理
手动维护 iOS 签名资源极易引发构建失败。现代 CI/CD 流程依赖自动化工具链实现可信、可复现的签名管理。
核心流程概览
graph TD
A[登录 Apple Developer Portal] --> B[生成 CSR]
B --> C[创建/更新证书]
C --> D[注册设备/配置 Bundle ID]
D --> E[生成 Provisioning Profile]
E --> F[下载并导入密钥链/证书仓库]
证书生命周期管理
使用 fastlane sigh 实现一键同步:
fastlane sigh \
--username "dev@company.com" \
--app_identifier "com.company.app" \
--development \ # 或 --adhoc / --appstore
--force \
--skip_install
--username:Apple ID,需提前配置两步验证应用专用密码;--app_identifier:必须与 Xcode 工程 Bundle ID 严格一致;--force:强制刷新过期或不匹配的 profile,避免缓存干扰。
推荐实践对照表
| 维度 | 手动操作 | 自动化方案(fastlane + match) |
|---|---|---|
| 安全性 | 证书私钥本地明文存储 | 加密 Git 仓库统一托管 |
| 团队协作 | 邮件分发 .p12 文件 | match nuke 一键清理旧证书 |
| CI 构建稳定性 | 依赖本地 Keychain 状态 | 每次构建前 match development 动态拉取 |
2.3 使用notarytool提交Go打包应用(.app/.pkg)的标准化流程
准备签名环境
确保已安装 Xcode 命令行工具与 Apple Developer 账户配置完成,notarytool 依赖有效的 AC_PASSWORD 和 TEAM_ID 环境变量。
构建并归档应用
# 构建 macOS 原生 Go 应用(启用 CGO 以支持签名依赖)
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o MyApp.app/Contents/MacOS/myapp .
# 将 .app 打包为可提交格式(zip 或 pkg)
ditto -c -k --keepParent MyApp.app MyApp.app.zip
此步骤生成符合 Apple Notarization 要求的扁平化归档;
ditto比zip更可靠地保留资源分支与扩展属性。
提交至苹果公证服务
notarytool submit \
--keychain-profile "AC_PASSWORD" \
--team-id "ABC123XYZ" \
MyApp.app.zip
--keychain-profile引用钥匙串中存储的 App Store Connect API 密钥;--team-id必须与开发者账号完全匹配,否则返回invalid team ID错误。
验证状态流转
| 状态 | 含义 |
|---|---|
Accepted |
已入队,等待扫描 |
Invalid |
签名损坏或 Bundle ID 冲突 |
Success |
公证通过,可分发 |
graph TD
A[提交 .zip/.pkg] --> B{Apple 服务接收}
B --> C[静态分析 + Hardened Runtime 检查]
C --> D[病毒扫描 & 权限声明验证]
D --> E[成功:返回 staple-ready ticket]
2.4 处理Notarization失败的常见错误码与二进制加固方案(Hardened Runtime、entitlements、CFBundleIdentifier一致性校验)
常见Notarization拒绝错误码
| 错误码 | 含义 | 关联配置项 |
|---|---|---|
ERROR_ITMS-90296 |
App使用了不支持的API(如私有框架) | Hardened Runtime + entitlements |
ERROR_ITMS-90338 |
Bundle ID与开发者证书/Provisioning Profile不匹配 | CFBundleIdentifier一致性校验 |
ERROR_ITMS-90297 |
缺少必需的硬编码权限(如com.apple.security.app-sandbox) |
Entitlements.plist |
Hardened Runtime启用示例
<!-- entitlements.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.hardened-runtime</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<false/>
</dict>
</plist>
该配置强制启用Hardened Runtime,并禁用JIT——Apple要求沙盒App必须同时启用这两项,否则notarytool submit将因签名不合规被静默拒收。allow-jit需显式设为false(即使未使用JIT),否则触发ERROR_ITMS-90297。
CFBundleIdentifier一致性校验流程
graph TD
A[Info.plist中CFBundleIdentifier] --> B{是否与Developer Portal中App ID一致?}
B -->|否| C[Notarization失败 ERROR_ITMS-90338]
B -->|是| D[检查Provisioning Profile是否包含该ID]
D -->|否| C
D -->|是| E[通过校验]
2.5 CI/CD中集成Notarization验证闭环(stapling、spctl评估与Gatekeeper兼容性测试)
在 macOS 应用发布流水线中,Notarization 不仅是苹果强制要求的签名增强环节,更需形成自动化验证闭环。
Stapling:嵌入公证票据到二进制
xcrun stapler staple --verbose MyApp.app
# --verbose 输出 stapling 状态及票据有效期;stapler 会自动从 Apple 服务器拉取并嵌入 .ticket 文件到 app 包的 _CodeSignature/ 目录
spctl 本地策略评估
spctl --assess --verbose=4 --type execute MyApp.app
# --type execute 模拟 Gatekeeper 启动校验流程;--verbose=4 显示完整信任链(公证票据、Apple Root、Developer ID)
Gatekeeper 兼容性测试矩阵
| 测试项 | macOS 12+ | macOS 13+ | 备注 |
|---|---|---|---|
| 未 stapled + 有效公证 | ❌ 阻断 | ⚠️ 提示用户 | 需联网实时校验 |
| stapled + 有效票据 | ✅ 通行 | ✅ 通行 | 离线可用,推荐标准实践 |
graph TD
A[CI 构建完成] --> B[上传至 Apple Notary Service]
B --> C{公证成功?}
C -->|Yes| D[staple 到 App]
C -->|No| E[失败告警并中断]
D --> F[spctl 本地评估]
F --> G[Gatekeeper 行为模拟]
第三章:Microsoft SmartScreen认证关键路径与可信链构建
3.1 Windows应用信誉体系解析:SmartScreen决策逻辑与EV Code Signing必要性
Windows SmartScreen 并非简单黑名单机制,而是基于应用信誉(Reputation)的动态决策引擎。其核心依赖微软云服务实时聚合的安装量、历史行为、证书链可信度等维度数据。
SmartScreen 决策关键因子
- 应用首次出现时间(越新,风险权重越高)
- 签名证书类型(OV/EV)、有效期及颁发机构可信等级
- 文件哈希是否存在于 Microsoft Defender Application Guard(MDAG)信誉库
- 用户群体安装速率突增检测(防“水坑式”分发)
EV Code Signing 的不可替代性
普通代码签名仅验证开发者身份;而 EV证书强制要求硬件令牌+线下审核,触发 SmartScreen 的“快速信誉积累”路径——新应用签署EV证书后,通常在48小时内跨越“未知发布者”警告阶段。
# 查询本地应用SmartScreen状态(需以管理员运行)
Get-AppLockerFileInformation -Path "C:\App\launcher.exe" |
Select-Object -ExpandProperty Publisher |
Format-List *
此命令提取文件签名元数据中的
Publisher字段,包含证书指纹、颁发者(Issuer)及扩展验证标志(ExtendedValidation: True/False)。SmartScreen 服务端据此匹配TrustedRootCA信任链并查询EV Certificate Flag布尔值,决定是否启用加速信誉建模。
| 证书类型 | 首次安装警告 | 信誉建立周期 | 是否支持自动信誉加速 |
|---|---|---|---|
| 无签名 | 强制阻止 | 不适用 | 否 |
| OV签名 | 高风险提示 | 数周至数月 | 否 |
| EV签名 | 低风险提示(可选) | 是 |
graph TD
A[用户双击EXE] --> B{SmartScreen本地缓存查命中?}
B -->|是| C[放行/静默]
B -->|否| D[上传文件哈希+证书信息至Microsoft云]
D --> E[匹配EV标识 + 安装基数>500?]
E -->|是| F[返回'已验证发布者']
E -->|否| G[返回'未知发布者-阻止']
3.2 Go程序Windows签名实践:signtool + timestamp server + Authenticode全链配置
Windows 平台分发 Go 程序时,未签名的 .exe 会触发 SmartScreen 警告。Authenticode 签名是绕过该拦截的必要环节。
准备签名证书与工具
- 获取受信任 CA(如 DigiCert、Sectigo)颁发的代码签名证书(
.pfx格式) - 安装 Windows SDK,确保
signtool.exe可用(通常位于C:\Program Files (x86)\Windows Kits\10\bin\<ver>\x64\)
签名命令与时间戳加固
signtool sign ^
/f "mycode.pfx" ^
/p "password123" ^
/t "http://timestamp.digicert.com" ^
/fd SHA256 ^
myapp.exe
/f指定 PFX 证书路径;/p为私钥密码/t连接权威时间戳服务器,确保签名在证书过期后仍有效(关键!)/fd SHA256强制使用 SHA-256 哈希算法,兼容 Win10+ 与 UEFI 安全启动
验证签名完整性
| 步骤 | 命令 | 用途 |
|---|---|---|
| 查看签名信息 | signtool verify /pa myapp.exe |
检查证书链与时间戳有效性 |
| 强制校验时间戳 | signtool verify /pa /v /td SHA256 myapp.exe |
输出详细验证日志 |
graph TD
A[Go build生成myapp.exe] --> B[signtool sign + .pfx]
B --> C[向timestamp.digicert.com请求RFC3161时间戳]
C --> D[嵌入时间戳+证书链]
D --> E[Windows内核验证:证书信任链 + 时间戳有效性 + 文件哈希一致性]
3.3 绕过“未知发布者”警告的实测策略:声誉积累期优化与Installer引导设计
Windows SmartScreen 对新证书签名应用的“未知发布者”拦截,本质是基于应用安装包哈希+发行者证书指纹+下载来源可信度的三元声誉评估。在证书冷启动阶段,需主动干预信任链构建。
声誉加速关键路径
- 提前7–14天在 Microsoft Partner Center 注册并提交
.exe(无功能,仅含合法签名)以触发初始信誉爬取 - 使用
signtool.exe签名时强制嵌入时间戳服务(推荐http://timestamp.digicert.com) - Installer 必须通过 HTTPS 分发,且域名需与 EV 证书 Subject 匹配
推荐签名命令(带解释)
signtool sign /fd SHA256 /td SHA256 ^
/tr "http://timestamp.digicert.com" ^
/sha1 "A1B2...F0" ^
/d "MyApp Installer" ^
MyAppSetup.exe
/fd SHA256指定文件摘要算法;/td SHA256指定时间戳哈希算法(双哈希兼容性更强);/tr为 RFC 3161 时间戳服务器地址,确保离线验证有效性;/sha1是本地证书存储中目标证书指纹,避免多证书混淆。
Installer 引导设计要点
| 组件 | 要求 |
|---|---|
| 主进程名称 | 避免 setup.exe,改用 MyApp_Installer_v2.1.0.exe |
| 数字签名 | 必须含完整证书链(含根证书) |
| 下载页 HTTP 头 | X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin |
graph TD
A[用户点击下载] --> B{HTTPS + 域名匹配EV证书?}
B -->|是| C[SmartScreen 查询云端声誉]
B -->|否| D[立即标记“未知发布者”]
C --> E{哈希已收录?<br/>证书指纹≥30天?}
E -->|是| F[显示“已验证发布者”]
E -->|否| G[降级为“运行 Anyway”提示]
第四章:双认证协同工程化落地与安全增强实践
4.1 Go构建脚本统一编排:基于goreleaser的macOS/Windows双平台签名流水线
为实现跨平台可分发二进制的可信交付,需在CI中统一注入代码签名能力。goreleaser通过signs配置段原生支持双平台签名:
# .goreleaser.yml 片段
signs:
- id: macos-notarize
cmd: cosign
args: ["sign-blob", "--key", "${MAC_CERT_KEY}", "--output-signature", "${artifact}.sig", "${artifact}"]
artifacts: checksum
env:
- "COSIGN_PASSWORD=${MAC_CERT_PASS}"
该配置将校验和文件交由cosign签名,配合Apple Developer ID证书完成macOS Gatekeeper兼容性准备;Windows侧则调用signtool.exe通过Azure Key Vault托管的EV证书远程签名。
关键签名策略对比:
| 平台 | 工具 | 证书来源 | 自动化依赖 |
|---|---|---|---|
| macOS | cosign |
Apple Notary API | notarytool CLI |
| Windows | signtool |
Azure Key Vault | az login + PKCS#12 |
graph TD
A[Go源码] --> B[goreleaser build]
B --> C{平台分支}
C --> D[macOS: notarize + staple]
C --> E[Windows: signtool /tr]
D & E --> F[统一checksums.txt签名]
4.2 二进制完整性保障:Go build flags加固(-ldflags -H=windowsgui, -buildmode=pie)、UPX兼容性规避与符号剥离
Go 编译时的链接器标志与构建模式直接影响二进制的可分析性与抗篡改能力。
隐藏控制台窗口(Windows GUI 模式)
go build -ldflags "-H=windowsgui" -o app.exe main.go
-H=windowsgui 告知链接器生成 Windows GUI 子系统二进制,不弹出控制台窗口,同时隐式禁用 main.main 符号导出,降低入口点暴露风险。
启用地址空间布局随机化(ASLR)支持
go build -buildmode=pie -o app-pie main.go
-buildmode=pie 生成位置无关可执行文件(PIE),使加载基址随机化,是现代操作系统 ASLR 的前提条件;注意:Go 1.16+ 默认启用,但显式声明可确保跨版本一致性。
符号剥离与 UPX 冲突规避策略
| 策略 | 命令示例 | 效果 | 兼容性 |
|---|---|---|---|
| 剥离调试符号 | -ldflags="-s -w" |
移除 DWARF 与 Go 符号表 | ✅ 完全兼容 |
| 强制禁用 UPX | upx --force --no-unpack app |
阻止自动 unpack 行为 | ⚠️ 需配合 -buildmode=pie(UPX 不支持 PIE) |
graph TD
A[源码] --> B[go build -buildmode=pie -ldflags=\"-s -w -H=windowsgui\"]
B --> C[无符号、PIE、GUI 子系统二进制]
C --> D[静态抗逆向 + ASLR + 隐蔽入口]
4.3 应用元信息合规性检查:Info.plist与RC文件字段标准化(CFBundleVersion、LSApplicationCategoryType、CompanyName等)
iOS/macOS 应用分发前需确保元信息严格符合 App Store 与 MDM 策略要求。关键字段缺失或格式错误将导致审核拒绝或企业部署失败。
核心校验字段语义约束
CFBundleVersion:必须为纯数字点分格式(如1.2.3),禁止字母/前导零(1.02.0❌)LSApplicationCategoryType:仅接受 Apple 官方枚举值(如public.app-category.productivity)CompanyName:须与开发者证书组织名完全一致,区分大小写且不可为空
Info.plist 合规性验证脚本(Shell)
# 检查 CFBundleVersion 格式是否合法
plutil -p Info.plist | grep "CFBundleVersion" | \
sed -n 's/.*CFBundleVersion[[:space:]]*=>[[:space:]]*"\([^"]*\)".*/\1/p' | \
grep -qE '^[0-9]+(\.[0-9]+)*$' && echo "✅ Version format valid" || echo "❌ Invalid version"
逻辑分析:
plutil -p解析 plist 为可读文本;sed提取引号内值;grep -qE断言纯数字点分结构。该正则^[0-9]+(\.[0-9]+)*$排除1.0a、01.2等非法变体。
常见字段映射对照表
| 字段名 | Info.plist 键 | RC 文件宏 | 示例值 |
|---|---|---|---|
| 构建版本 | CFBundleVersion |
INFOPLIST_VERSION |
2.1.0 |
| 应用类别 | LSApplicationCategoryType |
— | public.app-category.developer-tools |
| 公司名称 | CompanyName |
PRODUCT_NAME(需同步) |
Acme Corp |
graph TD
A[读取 Info.plist] --> B{CFBundleVersion 格式校验}
B -->|通过| C[LSApplicationCategoryType 枚举匹配]
B -->|失败| D[报错并终止]
C -->|匹配| E[CompanyName 与证书组织比对]
C -->|不匹配| D
4.4 可信分发基础设施搭建:自建更新服务器TLS证书绑定、增量更新签名验证与安装包哈希锚定
TLS证书绑定:Nginx强制双向信任
在更新服务器(如Nginx)中启用客户端证书校验,确保仅授权构建节点可推送更新:
ssl_client_certificate /etc/ssl/certs/ca-bundle.pem;
ssl_verify_client on;
ssl_verify_depth 2;
ssl_client_certificate 指定根CA公钥用于验证上传方证书链;ssl_verify_client on 强制双向TLS,阻断未签名请求。
增量更新签名验证流程
使用Ed25519私钥对delta包签名,客户端用预置公钥校验:
# 构建侧签名
openssl dgst -ed25519 -sign update-key.pem -out patch-v1.2.3.delta.sig patch-v1.2.3.delta
安装包哈希锚定机制
所有发布包SHA-256哈希写入不可篡改的Merkle Tree根,并内嵌至固件启动区:
| 包名 | SHA-256哈希(截取前16字节) | 锚定位置 |
|---|---|---|
| firmware-v2.1.0.bin | a7f3...d9c2 |
OTP Bank 3 |
| patch-v2.1.1.delta | e4b8...6a1f |
eFuse Row 42 |
graph TD
A[构建系统] -->|生成签名+哈希| B[更新服务器]
B --> C[客户端下载]
C --> D{验证:TLS证书 ✅<br>签名有效 ✅<br>哈希匹配 ✅}
D -->|全部通过| E[安全安装]
第五章:未来演进与企业级分发治理建议
多模态分发管道的实时协同架构
现代企业正从单一CI/CD流水线转向“分发即服务(DaaS)”范式。某头部金融云平台在2023年重构其容器镜像治理体系,将Helm Chart、OCI Artifact、Wasm模块、策略Bundle四类制品统一接入OpenSSF Sigstore签名网关,并通过Kubernetes Admission Controller实现部署前自动验签。该架构使生产环境镜像篡改事件归零,同时将合规审计准备周期从7人日压缩至1.5小时。关键设计在于引入轻量级Policy-as-Code引擎——Kyverno v1.11嵌入式策略编排器,支持基于GitOps Pull模式动态加载策略版本。
跨云环境下的制品生命周期图谱
企业级分发已突破单集群边界,需建立跨云制品溯源能力。下表展示了某制造集团在AWS EKS、Azure AKS与本地OpenShift三环境中同步管理Firmware固件包的元数据一致性要求:
| 维度 | AWS EKS | Azure AKS | OpenShift |
|---|---|---|---|
| 签名机制 | Notary v2 + AWS KMS | Azure Key Vault + Cosign | Red Hat SignTool + HashiCorp Vault |
| 保留策略 | 按SHA256哈希去重,保留最近3个主版本 | 基于设备型号标签自动归档,冷备至Blob Storage | 与Ansible Tower Job ID绑定,保留全生命周期日志 |
| 审计粒度 | 每次Pull操作记录IP+IAM Role+Pod UID | 记录AAD Group + Service Principal | 记录OpenShift Project + SCC约束详情 |
零信任分发网络的渐进式落地路径
某政务云项目采用分阶段实施策略:第一阶段在Ingress层强制TLS 1.3+双向认证,第二阶段在Service Mesh中注入SPIFFE身份证书,第三阶段将所有制品仓库升级为OCI Registry v1.1规范兼容节点,并启用Distribution Spec中的subject字段链式签名。实测数据显示,当Registry节点遭遇中间人攻击时,客户端校验失败率从传统SHA256比对的83%提升至99.997%(基于2024年Q2红队渗透测试报告)。
flowchart LR
A[开发者提交PR] --> B{CI流水线}
B --> C[构建OCI镜像]
C --> D[自动触发Sigstore签名]
D --> E[写入多区域Registry]
E --> F[Policy Engine实时扫描]
F --> G{是否符合SLA?}
G -->|是| H[推送至Prod Namespace]
G -->|否| I[阻断并触发告警工单]
H --> J[Service Mesh注入mTLS证书]
开源组件供应链的动态风险熔断机制
某电商中台系统集成超过1,200个NPM包与480个PyPI库,通过构建SBOM+VEX联合分析管道实现主动防御。当Log4j 2.17.1漏洞披露后,系统在37分钟内完成全栈影响评估:自动识别出17个内部服务依赖log4j-core-2.15.0,其中9个服务因使用Spring Boot 2.6.3内置版本而实际不受影响——该结论由静态AST解析与运行时字节码特征比对双重验证得出。熔断策略配置在GitOps仓库中以YAML声明,变更经Policy Bot自动审批后秒级生效。
混合云分发带宽智能调度模型
面对边缘节点频繁断连场景,某智能交通平台设计自适应分发算法:当边缘K3s节点连续3次心跳超时,系统自动切换至预置的离线分发通道——将增量补丁打包为SquashFS只读镜像,通过LoRaWAN网关分片传输,接收端利用Zstandard流式解压技术实现内存占用低于16MB。2024年汛期压力测试中,该方案在平均带宽仅128Kbps的洪涝灾区维持了98.2%的固件更新成功率。
