出與密鑰更新避坑指南)
簡(jiǎn)介pepk簽名工具源碼包面向需要更新Google Play應(yīng)用簽名的Android開(kāi)發(fā)者用于處理上架與密鑰升級(jí)中的簽名生成、校驗(yàn)及遷移問(wèn)題。壓縮包共含2000個(gè)文件其中1999個(gè)為Java源文件1個(gè)為txt說(shuō)明文件整體壓縮后僅5.02MBJava代碼覆蓋TLS協(xié)議工具、PKIX證書路徑驗(yàn)證、AES與GOST等加密算法實(shí)現(xiàn)txt說(shuō)明文件則梳理源碼結(jié)構(gòu)與使用要點(diǎn)。目前已有372人學(xué)習(xí)下載既適合剛接觸簽名機(jī)制的初學(xué)者也適合需要二次定制簽名流程的中高級(jí)開(kāi)發(fā)人員。研讀源碼可理解pepk在證書鏈校驗(yàn)、加密摘要計(jì)算以及最終輸出格式生成上如何對(duì)接Google Play簽名體系從而獨(dú)立排查簽名失敗或構(gòu)建自定義工具。資源體量緊湊、模塊劃分清晰可直接導(dǎo)入工程查看關(guān)鍵算法對(duì)移動(dòng)應(yīng)用交付與市場(chǎng)發(fā)布環(huán)節(jié)的簽名管理有實(shí)際參考價(jià)值。1. 把“pepk源碼”拆開(kāi)看這是Play簽名托管的鑰匙轉(zhuǎn)換器不是簽名工具“pepk”這個(gè)名字在簽名鏈路里經(jīng)常被誤解。它不是一個(gè)給APK做簽名的工具而是把開(kāi)發(fā)者手里那把“簽名主鑰匙”從本地安全導(dǎo)出的轉(zhuǎn)換器你用它的可執(zhí)行jar配上一串參數(shù)把JKS密鑰庫(kù)里的私鑰加密成一份.pepk文件交到Google Play控制臺(tái)之后Play App Signing才真正接管簽名動(dòng)作。反直覺(jué)的點(diǎn)在于本地證書導(dǎo)出得越干凈你越不需要把release keystore直接發(fā)給Google也就越少一次密鑰泄漏的風(fēng)險(xiǎn)。需要做這件事的通常是三類人存量應(yīng)用要遷移到Play App Signing、應(yīng)用密鑰需要輪換更新、或者剛接手一個(gè)沒(méi)有文檔的舊項(xiàng)目要重建發(fā)布鏈路。這篇按“原理 → 落地命令 → 更新簽名 → 避坑 → 驗(yàn)證”的順序一次講完。2. 為什么Play堅(jiān)持要.pepk兩把鑰匙的分工以及pepk的職責(zé)邊界2.1 兩把鑰匙的分工Upload Key負(fù)責(zé)上傳App Signing Key負(fù)責(zé)真正簽名在Play Console的“應(yīng)用完整性”頁(yè)面開(kāi)啟Play App Signing之后簽名體系會(huì)被拆成兩層。第一層叫上傳密鑰Upload Key它只證明“這次上傳包是你這個(gè)開(kāi)發(fā)者發(fā)出來(lái)的”作用范圍到控制臺(tái)接收文件為止第二層叫應(yīng)用簽名密鑰App Signing Key由Google托管最終每一個(gè)分發(fā)給用戶的APK或者從AAB生成的安裝包都用它簽名。這兩層拆開(kāi)之后最直接的收益是上傳密鑰可以隨時(shí)換只要不動(dòng)應(yīng)用簽名密鑰老用戶升級(jí)安裝包時(shí)就永遠(yuǎn)不會(huì)撞上“更新包簽名不一致”這個(gè)Android安裝器最頭疼的錯(cuò)誤。反過(guò)來(lái)說(shuō)如果你沒(méi)開(kāi)Play App Signingkeystore一旦丟失或者泄露整個(gè)應(yīng)用的身份就得換幾萬(wàn)老用戶會(huì)因?yàn)楹灻麑?duì)不上而無(wú)法覆蓋安裝只能卸載重裝數(shù)據(jù)全部清空。這個(gè)代價(jià)在Android 11之后的機(jī)型上尤其明顯因?yàn)榘惭b器對(duì)簽名不一致的攔截幾乎是零容忍的。所以一旦決定走Play App Signing這條路本地那把release keystore就不再是“直接簽出最終包”的鑰匙而是變成用來(lái)生成上傳密鑰和托管材料的根憑據(jù)。它仍然重要但重要程度從“每臺(tái)機(jī)器都要用”降到“只在遷移和導(dǎo)出時(shí)用一次”。很多人沒(méi)轉(zhuǎn)過(guò)這個(gè)彎才會(huì)出現(xiàn)后面章節(jié)里那些拿錯(cuò)鑰匙、導(dǎo)出錯(cuò)文件的翻車現(xiàn)場(chǎng)。2.2 pepk的職責(zé)邊界只做“導(dǎo)出與加密”不碰簽名動(dòng)作pepk全稱Play Encryption Public Key核心動(dòng)作只有一個(gè)把本地JKS/PKCS12里的私鑰條目用Google下發(fā)的RSA公鑰加密輸出成.pepk文件。這個(gè)文件里不是你的keystore本體也不是APK簽名而是“被加密過(guò)的私鑰證書”的封裝。上傳到控制臺(tái)后Google用自己的私鑰解開(kāi)得到你的應(yīng)用簽名密鑰之后所有面向用戶的分發(fā)包都由它簽名。理解這個(gè)邊界很重要因?yàn)槲以趯?shí)際排查里見(jiàn)過(guò)兩種誤用。第一種是把pepk當(dāng)成簽名工具拿著它去簽AAB輸出文件根本沒(méi)有任何簽名塊第二種是跑完pepk之后以為本地keystore就沒(méi)用了隨手刪掉結(jié)果Play側(cè)還沒(méi)有完成遷移兩邊都拿不到密鑰只能走密鑰輪換流程重新生成一把新鑰匙。pepk自始至終不簽名、不校驗(yàn)、不輪換它的輸入是jks、輸出是pepk僅此而已。2.3 什么時(shí)候需要跑pepk新應(yīng)用上線、存量遷移、密鑰重置跑pepk的時(shí)機(jī)有三種參數(shù)基本一致差別在控制臺(tái)入口。第一種是新應(yīng)用上線在Play Console創(chuàng)建應(yīng)用后選擇“由Google管理我的簽名密鑰”構(gòu)建AAB、下載加密公鑰、導(dǎo)出pepk上傳流程最順。第二種是存量應(yīng)用遷移老應(yīng)用已經(jīng)在Play上架原來(lái)是自簽名上傳APK現(xiàn)在要切到Play App Signing控制臺(tái)會(huì)引導(dǎo)你導(dǎo)出一份pepk把本地簽名密鑰“交給”Google托管。第三種是密鑰重置后重建導(dǎo)出包當(dāng)你主動(dòng)重置上傳密鑰或者輪換App Signing Key之后需要重新生成新的pepk或者上傳新的證書否則舊記錄和新本地密鑰就對(duì)不上。判斷自己屬于哪一種最簡(jiǎn)單的辦法是看一眼控制臺(tái)“應(yīng)用完整性”頁(yè)面的狀態(tài)如果寫的是“應(yīng)用簽名密鑰可由Google管理”但本地有舊keystore那就是遷移場(chǎng)景如果頁(yè)面顯示已經(jīng)托管但你換了一臺(tái)電腦要重建發(fā)布環(huán)境那通常不需要重新跑pepk只需要把上傳密鑰證書重新上傳即可。這個(gè)區(qū)分直接決定了你接下來(lái)是走第3章的導(dǎo)出流程還是走第4章的重置流程。3. 從源碼到命令用pepk生成可用導(dǎo)出包的完整落地步驟3.1 先讀“源碼”用jar tf和javap核對(duì)入口避免版本黑匣子pepk官方以jar包形式下發(fā)源碼沒(méi)有完整公開(kāi)社區(qū)里能搜到一些對(duì)它的逆向解讀和第三方重寫版本但我不建議在生產(chǎn)環(huán)境用第三方實(shí)現(xiàn)。更可靠的做法是拿到j(luò)ar之后先用JDK自帶的工具把它的結(jié)構(gòu)和入口類讀一遍確認(rèn)參數(shù)名和Main-Class而不是直接對(duì)著網(wǎng)上的命令盲跑。版本不同參數(shù)可能是--encryption-key也可能是--rsa-aes-encryption-keys這一步能省掉后面大量“玄學(xué)報(bào)錯(cuò)”。# 第一步列出jar里的類篩出與入口、加解密相關(guān)的類 jar tf pepk.jar | grep -iE main|Pepk|Encrypt|Signing # 第二步反編譯入口類的方法簽名確認(rèn)支持哪些命令行參數(shù) javap -p -c com.google.play.signing.pepk.PepkSigningTool 2/dev/null | head -80邏輯說(shuō)明jar tf打印jar包內(nèi)所有條目能看到包名結(jié)構(gòu)javap -p -c反匯編指定類的方法和字節(jié)碼。如果提示類找不到說(shuō)明入口類名不對(duì)回到上一條輸出里去找?guī)ain-Class字樣的類。這一步的目的是把黑匣子打開(kāi)一條縫至少確認(rèn)你手上這個(gè)jar認(rèn)哪種參數(shù)寫法再?zèng)Q定用舊版還是新版命令。參數(shù)說(shuō)明-p顯示私有成員-c輸出字節(jié)碼head -80控制輸出長(zhǎng)度避免刷屏。3.2 最小可用命令從JKS導(dǎo)出.pepk的六個(gè)參數(shù)逐個(gè)拆確認(rèn)jar沒(méi)問(wèn)題之后最常見(jiàn)的導(dǎo)出命令長(zhǎng)這樣。執(zhí)行前先確認(rèn)三件事keystore文件存在、alias拼寫正確、從Play控制臺(tái)下載的加密公鑰文件是.pem格式。java -jar pepk.jar \ --keystore/secure/release.jks \ --keystore-passfile:/secure/keystore-pass.txt \ --key-aliasrelease \ --rsa-aes-encryption-keys/secure/play_encryption_key.pem \ --output/secure/upload-keys/signing-key.pepk邏輯說(shuō)明把release.jks里的release別名條目取出來(lái)用play_encryption_key.pem里的公鑰加密寫到signing-key.pepk。這里--keystore-passfile:...是密碼文件用法比直接明文寫在命令行安全因?yàn)槊钚袇?shù)會(huì)出現(xiàn)在shell歷史里密碼文件可以單獨(dú)設(shè)置權(quán)限。如果下載到的公鑰是最舊版格式控制臺(tái)頁(yè)面給的是一串base64字符串這時(shí)才需要用--encryption-key代替--rsa-aes-encryption-keys。判斷標(biāo)準(zhǔn)很簡(jiǎn)單拿到的是一整個(gè)-----BEGIN PUBLIC KEY-----塊就用新參數(shù)拿到一長(zhǎng)行字符串就用舊參數(shù)。參數(shù)說(shuō)明--keystore指本地jks或pkcs12文件--key-alias必須和keytool -list里顯示的一致大小寫敏感--output的父目錄必須已經(jīng)存在jar不會(huì)幫你建目錄--rsa-aes-encryption-keys指向的pem文件在Play Console的“應(yīng)用完整性 → Play App Signing → 加密密鑰”里下載不是上傳密鑰證書這倆在同一個(gè)頁(yè)面上很多新手會(huì)下錯(cuò)。3.3 把參數(shù)收進(jìn)配置文件的封裝腳本密碼不落命令行臨時(shí)跑一次可以手敲命令但如果這個(gè)導(dǎo)出動(dòng)作要復(fù)現(xiàn)比如CI流程或者換人交接建議直接把整個(gè)導(dǎo)出過(guò)程封裝成一個(gè)腳本參數(shù)從外部變量讀入密碼只走file:或env:前綴。#!/usr/bin/env bash set -euo pipefail PEPK_JAR${PEPK_JAR:?未指定 pepk.jar 路徑} KS${KS_FILE:?未指定 keystore 路徑} KS_ALIAS${KS_ALIAS:?未指定 alias} KS_PASS_FILE${KS_PASS_FILE:?未指定密碼文件} PEM_FILE${PEM_FILE:?未指定加密公鑰 pem} OUTPUT_PEPK${OUTPUT_PEPK:?未指定輸出文件路徑} if [ ! -f $KS_PASS_FILE ]; then echo 密碼文件不存在: $KS_PASS_FILE exit 1 fi umask 077 java -jar $PEPK_JAR \ --keystore$KS \ --keystore-passfile:$KS_PASS_FILE \ --key-alias$KS_ALIAS \ --rsa-aes-encryption-keys$PEM_FILE \ --output$OUTPUT_PEPK echo 導(dǎo)出完成: $OUTPUT_PEPK sha256sum $OUTPUT_PEPK邏輯說(shuō)明set -euo pipefail保證任何一步失敗腳本馬上退出不會(huì)帶著半成品繼續(xù)跑${VAR:?}的寫法在變量缺失時(shí)直接報(bào)錯(cuò)退出避免空參數(shù)導(dǎo)致pepk讀錯(cuò)文件umask 077讓新生成的pepk文件只有當(dāng)前用戶可讀寫防止導(dǎo)出物落到共享目錄里被其他人順手拷走最后的sha256sum輸出哈希值方便和上傳后控制臺(tái)顯示的值做初步比對(duì)。這個(gè)腳本看起來(lái)比直接跑一條命令啰嗦但它解決的是發(fā)布鏈路里最常見(jiàn)的隱患密碼泄露和接口不可復(fù)現(xiàn)。把KS_PASS_FILE放到只有發(fā)布負(fù)責(zé)人能讀的目錄腳本本身可以進(jìn)代碼庫(kù)別人接手時(shí)不需要知道密碼也能完成導(dǎo)出生效流程。血淚經(jīng)驗(yàn)是直接把密碼寫進(jìn)命令行的團(tuán)隊(duì)三個(gè)月后一定有人把整段shell history貼到聊天工具里。3.4 拿到.pepk之后上傳到Play Console的下一步導(dǎo)出成功后登錄Play Console進(jìn)入目標(biāo)應(yīng)用的“應(yīng)用完整性 → 設(shè)置 → 遷移應(yīng)用簽名密鑰”或“導(dǎo)出并上傳密鑰”流程把pepk文件拖進(jìn)去。提交后控制臺(tái)會(huì)解析出兩個(gè)證書指紋一個(gè)是App Signing Key的一個(gè)是Upload Key的。這時(shí)候建議立刻截圖或者復(fù)制頁(yè)面上的SHA256指紋存進(jìn)團(tuán)隊(duì)的密鑰管理記錄里因?yàn)楹罄m(xù)換電腦、重建環(huán)境、校驗(yàn)簽名用的都是這串指紋而不是文件本身。如果上傳時(shí)報(bào)“無(wú)法解析本地簽名密鑰”之類的錯(cuò)誤90%是alias大小寫不對(duì)或者pem文件下載的不是當(dāng)前版本?;氐?.2的命令用keytool -list -v -keystore release.jks確認(rèn)alias再?gòu)目刂婆_(tái)重新下載一次加密公鑰重新導(dǎo)出。注意控制臺(tái)里的“加密公鑰”和“上傳密鑰證書”是兩項(xiàng)導(dǎo)出pepk只需要前者很多人在這一步拿錯(cuò)文件導(dǎo)出產(chǎn)物上傳后照樣報(bào)格式錯(cuò)誤。4. 更新Google Play簽名密鑰輪換與上傳密鑰重置的實(shí)操路徑4.1 先分清“更新簽名”的兩種訴求搞錯(cuò)等于翻車“更新google play簽名”這句話背后的訴求可能完全不同動(dòng)手前必須分清楚。第一訴求是輪換App Signing Key應(yīng)用簽名密鑰本身泄露或者合規(guī)要求強(qiáng)制更換這時(shí)用戶端安裝包簽名會(huì)變化已安裝的老用戶無(wú)法覆蓋安裝新包只能引導(dǎo)卸載重裝影響面巨大屬于最后手段。第二訴求是重置上傳密鑰團(tuán)隊(duì)人員變動(dòng)、舊keystore密碼失守、CI環(huán)境要遷移但應(yīng)用簽名密鑰不動(dòng)用戶端簽名不變只是以后上傳包的校驗(yàn)鑰匙換一把這是日常最常遇到的“更新簽名”。我用一張表把兩者的區(qū)別列出來(lái)方便對(duì)照決策操作對(duì)象用戶端安裝包簽名老用戶覆蓋安裝典型觸發(fā)場(chǎng)景控制臺(tái)入口重置上傳密鑰不變正常人員離職、CI遷移、upload keystore疑似泄露應(yīng)用完整性 → 重置上傳密鑰輪換App Signing Key變更不兼容需卸載重裝托管密鑰泄露、平臺(tái)合規(guī)要求應(yīng)用完整性 → 輪換密鑰分清這兩種之后后面所有操作步驟才有意義。如果只是想換一把“團(tuán)隊(duì)自己手里的鑰匙”卻誤走了輪換流程等于給全量用戶制造了一次強(qiáng)制卸載重裝這個(gè)翻車代價(jià)幾乎不可逆。4.2 密鑰輪換的標(biāo)準(zhǔn)流程下載新證書本地重簽重新上傳只有確定要?jiǎng)覣pp Signing Key時(shí)才走這一步。在Play Console的“應(yīng)用完整性 → 輪換密鑰”里發(fā)起輪換后Google會(huì)生成一把新的應(yīng)用簽名密鑰并提供新證書下載入口。隨后要做的是用新證書在本地重新生成keystore、對(duì)新包重新簽名、再上傳到Play。# 生成新的上傳密鑰庫(kù)注意這里是“上傳密鑰”用戶端簽名仍由新App Signing Key決定 keytool -genkeypair -v \ -keystore upload_keystore_new.jks \ -alias upload \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # 導(dǎo)出新證書后續(xù)要上傳到控制臺(tái) keytool -export -rfc \ -alias upload \ -keystore upload_keystore_new.jks \ -storepass CHANGE_ME \ -file upload_cert_new.pem # 用新keystore重新簽名AAB/APKAGP構(gòu)建產(chǎn)物必須以新證書簽名后才能上傳 apksigner sign \ --ks upload_keystore_new.jks \ --ks-key-alias upload \ --ks-pass pass:CHANGE_ME \ --out app-release-resigned.aab \ app-release-unsigned.aab邏輯說(shuō)明輪換之后Play側(cè)的新App Signing Key已經(jīng)生效本地所有上傳包都必須用新上傳密鑰簽名。keytool -genkeypair生成新密鑰對(duì)-validity 10000大約是27年覆蓋應(yīng)用生命周期keytool -export導(dǎo)出證書給控制臺(tái)做匹配apksigner sign把未簽名的構(gòu)建產(chǎn)物簽成可上傳的包。參數(shù)說(shuō)明-keyalg RSA -keysize 2048是Play支持的常見(jiàn)組合不要為了“更安全”選4096或ECC控制臺(tái)只認(rèn)RSA 2048容易在后續(xù)校驗(yàn)時(shí)被拒apksigner是Android SDK build-tools里的工具不要在jarsigner上浪費(fèi)時(shí)間它對(duì)AAB的處理經(jīng)常出現(xiàn)簽名塊格式兼容問(wèn)題。輪換后有一個(gè)硬性時(shí)間點(diǎn)輪換流程一旦在控制臺(tái)確認(rèn)舊App Signing Key簽出的包就不再被Play接受用于新上傳但已經(jīng)分發(fā)給用戶的舊包仍然裝在用戶設(shè)備上。所以輪換要選在發(fā)版窗口關(guān)閉后立刻執(zhí)行然后馬上用新證書出一個(gè)全量包上傳讓Play用它應(yīng)對(duì)后續(xù)用戶下載。這個(gè)窗口期里如果繼續(xù)發(fā)新版本會(huì)出現(xiàn)一部分用戶拿到新簽名包后無(wú)法覆蓋安裝的情況必須在發(fā)布說(shuō)明里明確提示。4.3 上傳密鑰重置給團(tuán)隊(duì)換鑰匙的后悔藥與三天信任期日常場(chǎng)景更常見(jiàn)的是重置上傳密鑰。過(guò)程分四步在控制臺(tái)申請(qǐng)重置、生成本地新keystore、上傳新證書、填寫賬號(hào)安全碼確認(rèn)。提交后Play不會(huì)立刻吊銷舊上傳密鑰而是保留一段信任期常見(jiàn)做法是保留3天這段期間新舊上傳密鑰都有效。這樣設(shè)計(jì)是為了給CI系統(tǒng)一個(gè)過(guò)渡窗口但你也會(huì)因此踩到“更新包簽名不一致”的坑如果你在第1天先手動(dòng)用新key傳了一個(gè)包第2天CI還在用舊key自動(dòng)上傳兩個(gè)包簽名來(lái)源不同用戶收到更新時(shí)就可能報(bào)錯(cuò)。# 生成新的上傳密鑰庫(kù) keytool -genkeypair -v \ -keystore upload_keystore_v2.jks \ -alias upload_v2 \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # 導(dǎo)出證書用于控制臺(tái)上傳 keytool -export -rfc \ -alias upload_v2 \ -keystore upload_keystore_v2.jks \ -storepass CHANGE_ME \ -file upload_cert_v2.pem邏輯說(shuō)明這兩條命令生成的是“上傳密鑰”和4.2里生成upload keystore的目的一致但不會(huì)觸動(dòng)App Signing Key。生成后把upload_cert_v2.pem上傳到控制臺(tái)填入安全碼提交即可。參數(shù)說(shuō)明-storepass這里為了演示直接寫在命令行生產(chǎn)環(huán)境請(qǐng)改成-storepass:env或受保護(hù)的密碼文件-validity 10000對(duì)上傳密鑰同樣適用它只簽上傳動(dòng)作不簽用戶包過(guò)期風(fēng)險(xiǎn)極低。重置完成后最重要的動(dòng)作是同步CI變量。跑到你CI系統(tǒng)的簽名配置里把舊的keystore路徑、alias、密碼全部換成新值然后發(fā)一個(gè)測(cè)試包到內(nèi)部測(cè)試軌道驗(yàn)證。注意不要急著刪掉舊keystore文件信任期內(nèi)兩邊都能上傳但一旦發(fā)現(xiàn)CI新配置有問(wèn)題舊key還能做緊急回退。這個(gè)“后悔藥”只在信任期內(nèi)有效過(guò)了窗口再想用舊key控制臺(tái)會(huì)直接拒絕上傳。5. 簽名更新避坑清單五個(gè)讓老手也翻車的真實(shí)現(xiàn)場(chǎng)5.1 “更新包簽名不一致”來(lái)自CI里那把舊的upload keystore現(xiàn)象某個(gè)版本發(fā)布后用戶反饋覆蓋安裝失敗報(bào)錯(cuò)提示“更新包簽名不一致”但本地手工打包上傳又是成功的。原因是CI系統(tǒng)里還配著舊的上傳密鑰重置上傳密鑰后你在本地用了新key打包CI自動(dòng)構(gòu)建還在用舊key簽名兩個(gè)包到了Play側(cè)后用戶端出現(xiàn)簽名來(lái)源漂移。解決方法是重置后第一時(shí)間全量替換CI里的簽名變量并且在信任期內(nèi)用舊key發(fā)一個(gè)明確標(biāo)記為“過(guò)渡驗(yàn)證”的包到內(nèi)部軌道確認(rèn)兩條鏈路都不再產(chǎn)出混淆簽名。別指望靠記憶同步把keystore指紋寫進(jìn)CI構(gòu)建腳本的checklist里每次構(gòu)建失敗時(shí)先比對(duì)指紋再查代碼。5.2 pepk報(bào)“加密公鑰格式無(wú)效”大概率是pem新舊混用現(xiàn)象跑導(dǎo)出命令時(shí)拋CryptoException或者提示無(wú)法解析加密公鑰命令看著沒(méi)問(wèn)題keystore和alias也沒(méi)錯(cuò)。原因是下載的pem文件和pepk.jar版本不匹配新版jar只認(rèn)--rsa-aes-encryption-keys參數(shù)并接收完整PEM塊舊版jar需要--encryption-key參數(shù)接收base64字符串或者你下載的pem是上次輪換前的舊公鑰。解決方法是回到控制臺(tái)“應(yīng)用完整性”頁(yè)面重新下載當(dāng)前加密密鑰檢查文件頭是不是-----BEGIN PUBLIC KEY-----再對(duì)照3.1里的javap輸出確認(rèn)jar支持的參數(shù)名。下載后建議用grep -c BEGIN PUBLIC KEY做一次前置校驗(yàn)文件不對(duì)就當(dāng)場(chǎng)停下別繼續(xù)往下跑。5.3 輪換后測(cè)試機(jī)裝不上包本地測(cè)試簽名與分發(fā)簽名脫節(jié)現(xiàn)象App Signing Key輪換后開(kāi)發(fā)機(jī)和測(cè)試機(jī)上adb install新包報(bào)簽名不一致卸載重裝又舍不得測(cè)試數(shù)據(jù)。原因是本地開(kāi)發(fā)/測(cè)試環(huán)境還在用舊應(yīng)用簽名密鑰簽出的調(diào)試包或者沒(méi)把調(diào)試配置切到新上傳證書。解決方法是把測(cè)試軌道的分發(fā)包統(tǒng)一用新上傳證書重簽調(diào)試期別開(kāi)Play App Signing的用戶端簽名如果測(cè)試機(jī)必須保留舊數(shù)據(jù)就保留一條穩(wěn)定通道繼續(xù)發(fā)布舊簽名包等下一個(gè)版本再統(tǒng)一切換。輪換這類操作最好安排在版本號(hào)跳大版的窗口把“簽名切換”和“強(qiáng)制升級(jí)”綁在一起止損面最小。5.4 密碼里的特殊字符與中文路徑pepk最脆弱的輸入現(xiàn)象導(dǎo)出命令在macOS上跑得好好的換到Windows PowerShell就報(bào)錯(cuò)或者導(dǎo)出成功但上傳時(shí)提示文件損壞。原因是keystore密碼里含有$、、!等字符在shell里被解釋成變量或歷史展開(kāi)中文路徑在Windows控制臺(tái)編碼下傳到pepk內(nèi)部變成亂碼文件名。解決方法是所有密碼一律走file:前綴路徑目錄只用ASCII字符Windows下推薦用Git Bash而不是cmd執(zhí)行導(dǎo)出腳本可以少踩一半編碼坑。這里沒(méi)有玄學(xué)凡是沒(méi)進(jìn)配置文件而直接手敲的參數(shù)早晚會(huì)在某個(gè)環(huán)境的奇怪字符上出問(wèn)題。5.5 一個(gè)keystore多個(gè)alias導(dǎo)出成功卻不匹配現(xiàn)象pepk導(dǎo)出命令正常執(zhí)行、控制臺(tái)也顯示上傳成功但后續(xù)構(gòu)建出的包在Play側(cè)校驗(yàn)時(shí)提示密鑰與歷史記錄不匹配。原因是同一個(gè)keystore文件里存了多個(gè)alias比如有調(diào)試用的、有舊項(xiàng)目遺留的導(dǎo)出時(shí)用了一個(gè)能解密但對(duì)不上的條目。解決方法是導(dǎo)出前先執(zhí)行keytool -list -v -keystore release.jks核對(duì)目標(biāo)alias的SHA256指紋把這個(gè)指紋和Play控制臺(tái)的記錄比對(duì)通過(guò)后再跑pepk。記錄指紋這一步別省項(xiàng)目交接時(shí)新接手的人就是靠這串指紋確認(rèn)自己有沒(méi)有拿錯(cuò)鑰匙。6. 收尾驗(yàn)證把a(bǔ)pksigner和Play控制臺(tái)的指紋對(duì)齊簽名更新操作正確與否最后都要落到證書指紋上。三個(gè)地方必須對(duì)照一致本地keystore里的證書、最終產(chǎn)出的AAB/APK攜帶的證書、Play Console“應(yīng)用完整性”頁(yè)面上顯示的證書。用一個(gè)清單一口氣核完檢查對(duì)象命令看什么本地keystorekeytool -list -v -keystore release.jks -alias release輸出里的SHA256指紋AAB內(nèi)嵌證書keytool -printcert -jarfile app-release.aab簽名塊里的SHA256指紋APK證書apksigner verify --print-certs app-release.apk用--print-certs打印指紋同時(shí)驗(yàn)證簽名完整Play控制臺(tái)應(yīng)用完整性 → Play App Signing 頁(yè)面頁(yè)面展示的App Signing Key與Upload Key指紋我習(xí)慣在每次上傳前把四個(gè)指紋貼到發(fā)布檢查單里尤其是輪換和重置之后這三處只要有任何一處不一致就得停下來(lái)查而不是賭一把傳上去再說(shuō)。實(shí)際執(zhí)行時(shí)最順手的是把a(bǔ)pksigner verify --print-certs接在CI發(fā)布job的最后一步簽名校驗(yàn)失敗直接fail整個(gè)流水線省得人工比對(duì)。這套流程跑下來(lái)你會(huì)發(fā)現(xiàn)pepk的導(dǎo)出只是整個(gè)簽名鏈路里最機(jī)械的一環(huán)真正決定它安全性的反而是周邊的規(guī)矩密碼進(jìn)文件、指紋進(jìn)檢查單、舊密鑰留過(guò)渡期。早期做項(xiàng)目時(shí)我直接把release keystore發(fā)給同事讓他傳控制臺(tái)后來(lái)那只鑰匙在五臺(tái)電腦間復(fù)制了一圈才被想起來(lái)要吊銷那次之后就再?zèng)]讓keystore離開(kāi)過(guò)保險(xiǎn)柜?,F(xiàn)在每次輪換或重置后我會(huì)先改CI、再發(fā)測(cè)試包、最后對(duì)照指紋順序不亂也就再?zèng)]遇到簽名翻車。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取