1. 问题现象:打包时突然蹦出来的签名报错
先说结论:这个报错Unable to sign the application; please provide passwords!,我这边最早是在用Unity打包Android版本的时候遇到的,后来帮同事排查,发现iOS、乃至部分场景下的桌面平台构建,也会出现类似提示。不过绝大多数情况下,它都出现在Android项目的打包环节,而且在很多新手项目里几乎属于“必经之路”。
现象很直观:你点下Build或者Build And Run,Unity吭哧吭哧编译了大半天,进度条一路狂奔到快要结束,然后突然弹出一个报错窗口或者Console面板刷出一行红字——Unable to sign the application; please provide passwords!。第一次遇到的人往往一脸懵:我压根没设置过什么密码啊,什么签名不签名的,我就是想打个能装到手机上的APK而已。
问题就出在这:你确实没手动设置过密码,但Unity在Android打包链路中需要给应用做签名,缺了密码它就签不了。这是一个典型的“Unity默认设置不符合你预期”的坑,不是环境坏了,不是SDK没配好,更不是代码写错了,纯粹是构建配置里缺了一项关键信息。
这个报错还有一个特点:它经常不是稳定复现的。有人换个电脑就好了,有人清了缓存就好了,有人升级了Unity版本又冒出来了。这也导致它的排查路线特别容易跑偏,网上查一圈,有人说是Java环境问题,有人说是SDK权限问题,实际上真正的罪魁祸首往往就那一个。我写这篇东西,就是想把这条线彻底捋清楚,包括为什么会报这个错、正确的解决姿势是什么、以及那些奇奇怪怪的触发方式背后都是怎么回事。
2. 报错背后的签名机制
2.1 为什么Android应用必须要签名
要理解这个报错,先把Android的签名机制讲明白。Android系统对安装包有一个硬性要求:应用必须经过数字签名才能被安装,无论你是从应用商店下载,还是用数据线传到手机上点安装包,系统在安装前都会校验签名信息。签名的用途主要有三个方向:一是确认安装包的来源,告诉系统这个APK是谁发布的;二是保证完整性,防止应用在传输或存储过程中被人篡改;三是建立应用身份标识,同一个签名的应用之间才能做升级覆盖安装、共享数据这类操作。
这个规则从Android诞生第一天起就有,不是某个厂商加的限制。所以在Android项目里,“给APK做签名”不是一个可选项,而是打包流程里绕不开的一步。既然绕不开,Unity就得代表开发者做这件事,可它没拿到你的密码,自然就执行不下去。
2.2 Unity背后的签名工具链和密码从哪来
Unity在Android构建时,真正执行签名操作的是一个叫apksigner的命令行工具,这个工具来自Android SDK的build-tools目录。签名用的密钥库文件是Java标准的keystore格式,文件名通常叫xxx.keystore或者xxx.jks。整个链路大概是:Unity把编译好的代码和资源打包成未签名的APK,然后把APK交给apksigner,apksigner读取keystore里的密钥进行签名。
这个keystore在使用时有两道密码:storepass——整个密钥库文件的访问密码;keypass——密钥库中某个具体密钥条目的密码。绝大多数情况下,Unity要求这两个密码是一致的,设置的时候也建议直接用同一个值,少给自己添麻烦。
如果你从来没手动创建过keystore,Unity也不是什么准备都不做就把活儿接过来了。它在首次为项目配置Android签名时,会默认使用一个由开发环境自动生成的调试密钥库,路径一般在C:\Users\你的用户名\.android\debug.keystore(Windows)或者~/.android/debug.keystore(macOS/Linux)。这个调试密码库有公开的默认密码,明文写出来就是android。意思是说,就算你什么都不管,Unity本来也有一把“万能钥匙”可以用来签名。
那问题来了——明明有默认调试密钥库和默认密码,为什么还会报please provide passwords!?这个就很难评了,我实际踩坑的经验是对应几种情况:Unity在打包时读取不到调试keystore文件、SDK工具链路径异常导致apksigner拿不到默认密码、以及你自己在Project Settings里指定了自定义keystore,但没有把密码填进去。最后一个情况尤其多,后面我专门用一节细讲。
2.3 为什么报错文案看起来像没给密码
报错文案直译过来是“无法签名应用程序,请提供密码”。这个提示的迷惑性很强,它会让人下意识去找“哪里输入密码”,或者以为构建窗口会弹出一个密码输入框。实际上Unity的构建流程默认是非交互式的,它不会在命令行界面弹窗要密码。密码要么提前写在配置里,要么它自己去读默认值,两条路都堵死了,就直接抛出这个异常终止构建。
所以遇到这个报错,你的思路不应该是我怎么把密码“喂”给正在运行的这个构建任务,而是去检查构建配置里到底有没有把签名信息填对、填全。顺着这个思路排查,大概率几分钟内就能定位到问题。
3. 最正统的解决流程:Player Settings里补全签名信息
3.1 打开签名配置面板
在Unity里点击菜单栏的Edit,选择Project Settings,在左侧列表中找到Player标签页。这个页面很长,左侧是不同类型平台的图标,打包Android就在左侧选中那个绿色的安卓机器人图标,然后展开右侧的设置项。你需要在设置区域里往下翻,找到Publishing Settings分组,在这个分组里能看到Keystore Manager和Project Keystore之类的签名相关配置项。
具体的字段名不同Unity版本之间会有差异,老一点的版本是Project Keystore下拉框加上Project Key下拉框,新版本改成了Custom Keystore复选框加文件选择按钮。不管长什么样,核心逻辑就一个:你可以选择用Unity默认生成的调试密钥库,也可以指定自己创建的正式密钥库。报错信息里的“please provide passwords”,就是因为这里有一个配置没有正确完成。
下面分两种方式说明,你自己对号入座。
3.2 方式一:直接用Unity默认调试密钥库
如果你只是自己开发测试,需要打个APK装到手机上跑一跑,根本没打算上架应用商店,那最简单的办法就是用Unity自带的默认密钥库。这里有一个极易踩坑的重点:你需要手动让Unity重新生成或者加载一次默认keystore,并且不要勾选自定义签名。
在Publishing Settings下方,找到Project Keystore对应的下拉框。如果你发现这里显示的是空,或者名为Unknown,那就是Unity没找到可用的密钥库。此时先点击旁边的Keystore Manager按钮,在弹出的窗口里选择Create New,创建一个新的密钥库文件,也可以选择Use Existing,定位到之前生成过的keystore文件。如果你没有特殊需求,直接指定为~/.android/debug.keystore(Windows下就是用户目录下的.android文件夹里那个文件)。选择好之后,下方会展开一栏密码输入区域。
在这个密码区域里,把Keystore Password和Confirm Password都填上android,Key Alias选择androiddebugkey,Key Password同样填android。保存设置,再回到打包界面重新构建。用了默认密钥,密码就是上面这些已知的默认值。
注意:
debug.keystore有可能之前被创建过但密码不是默认值,或者文件已经损坏。遇到这种情况,最简单的方式是把.android目录下的debug.keystore文件删掉,让Unity或者Android工具链生成一个新的,再用默认密码去匹配。删除之前请确认其他项目没有还在用它,否则需要用新密钥签名的项目都要重新覆盖安装才能升级。
3.3 方式二:使用自定义正式签名
如果你的应用准备上架应用商店,或者测试环境对签名包名一致性有要求,那就需要创建一套自己的正式签名信息。这类签名常见的用途是:模拟线上环境、对接微信等要求固定签名的第三方SDK、以及预发布给外部测试团队使用的包。
在Publishing Settings下,勾选Custom Keystore,点击旁边的Browse按钮选择你的keystore文件。选完之后,Unity下方会出现输入框,需要填写:
Keystore Password:密钥库文件的访问密码Key Alias:你要使用哪个别名下的密钥(一个keystore文件可以存放多个密钥条目,每个alias对应一个密钥)Key Password:该密钥的密码,一般和Keystore Password保持一致
如果你现在手头没有keystore文件,可以点击Keystore Manager,选择Create New,弹出窗口里填好别名、组织信息、密码等字段,点击创建,就能生成一个新的.keystore文件。创建过程中Unity会问你保存到哪里,选个保险点的目录,这个文件只此一份,丢了就找不回来了,后面上架更新都得靠它做身份验证,这个逻辑跟物理世界里的公章钥匙扣没有任何区别。
填好这些字段后,Unity不会再报please provide passwords,因为构建流程在打包前已经把所有需要的密码都拿到了。
3.4 配置完成后验证是否生效
配置保存好之后,别急着直接点大按钮构建。我建议先执行一次干净的构建操作:在File > Build Settings里选择Android平台,确保场景列表没有问题,然后点击Build。Unity会先执行一次完整的编译流程,如果签名配置正确,这次不会再弹签名相关的报错,最终你会拿到一个正常的APK文件。
如果想进一步验证签名是否真的可用,可以用命令行的方式。把apksigner工具找到,它在Android SDK目录/build-tools/版本号/下面,执行:
apksigner verify --print-certs 你的应用.apk正常输出里会显示证书的SHA-256指纹等信息,说明签名是有效且可验证的。顺手用这个工具还能看到证书有效期、签名算法版本这些细节,对排查一些安装时的INSTALL_PARSE_FAILED_NO_CERTIFICATES报错也很有帮助。
4. 深入排查:那些“看起来一样”但解法不同的情况
4.1 报错可能在构建快结束时才出现
这个报错的触发时机很值得聊一聊。它不是在一开始编译时就报,而是等到所有编译、资源打包、合并清单等步骤都完成后,在最终签名这个环节才蹦出来。这意味着你每次触发报错,都已经白白等了很长时间——大型项目编译一次动辄需要几分钟,确实挺浪费时间。
为什么签名放这么后面?可以理解成Unity整个构建是一个流水线:编译C#代码、把代码和资源打成未签名APK、优化资源、最后才是签名。签名是收尾动作,所以前面的步骤全通过,轮到签名才发现没有密码。这也是为什么前文提到的检查签字配置应该放在所有环境排查的最优先位置,其他组件有没有装对,靠报错前面的日志就能看出来,而签字问题就被埋在最底下,容易被人忽略。
4.2 同一个报错,可能是环境路径的问题
我遇到的第二次Unable to sign the application就不是签名配置的问题了,而是Unity压根调不到apksigner工具。具体表现是同一个项目,在另一台电脑上打包一切正常,换回这台就报错。排查了一圈,最后定位在Android SDK的路径配置上。
Unity打包Android必须要找到Android SDK的位置,这个SDK还可以内嵌Unity自带的版本,也可以是用户自己安装的版本。日常情况下,路径会记在Edit > Preferences > External Tools > Android SDK里。如果你这个路径指向的SDK目录里build-tools版本缺失,或者目录权限不对,Unity就无法调用apksigner完成签名,于是也会抛出这个报错。
这种情况的解决方式是:打开SDK Manager,确认build-tools下至少有一个较新的版本;如果目录存在问题,可以修复安装,或者安装一个明确的新版本build-tools。前提是版本要和Unity的兼容范围匹配,太新或者太旧都可能被Unity拒绝。没把握的话,直接在Unity Preferences里选择Install with Unity,让它自动下载一个匹配的SDK组件,省心也安全。
4.3 密码没错,但“signature”依然无法通过
这个就诡异了,但我真的见过几次。表现是:配置里的所有密码都填得明明白白,文件也能正常读取,项目构建也不报错,但安装到手机上时系统提示签名不匹配,或者升级安装时报出INSTALL_FAILED_UPDATE_INCOMPATIBLE。这类情况的根因多数不是这次构建的配置问题,而是之前的安装包签名不同。
典型场景:早期测试时用的是默认调试密钥库签名的包,后来切换到了自定义正式签名的包,两个签名不一样,系统认为这是两个不同的应用,自然禁止覆盖安装。这种情况处理后带来的教训是:从项目一开始就要确定好签名策略,测试阶段就用最终要上架的那个签名,不然推广团队或者测试同事每换一次签名包,都要卸载旧应用重新安装。
4.4 多模块项目、安卓库的次级签名问题
还有一种衍生场景:你主项目是一个工程,但同时依赖了好几款接入的安卓原生Module或aar包。Unity在打包时,如果这些第三方库打包时就带着自己的签名信息,而签名文件和主工程里的密钥不一致,那在签名环节同样可能报错或者生成包安装时报错。遇到这种情况,先检查一下Plugins/Android目录下有没有.keystore或.jks文件,如果有,评估它们是否真的需要在构建时参与签名;不需要的话,就从构建流程里移出去,确保最终签名统一用主工程的那一套。
5. 拿到报错后,一套更硬核的排查流程
5.1 第一步:拉开Console日志看全貌
Unity的Console面板只会显示一行简短报错,但往往关键线索都在日志更靠前的部分。展开Console面板,打开右上角的三条横线菜单,确认Collapse没有被勾选,Log Type里Error那一列是勾选状态。如果日志被折叠了,很多跟进信息会被藏起来,展开看才能看到完整堆栈。
如果日志量实在太大了,可以直接把日志导入电脑的文件夹里看。在Console面板的右上角菜单里,选择Open Editor Log,它会用文本编辑器打开完整的编辑器日志文件。在这个文件里搜索关键字Keystore、apksigner、sign,配合报错时间点,应该能找到真正引发签名失败的那一行底层原因。
5.2 第二步:检查keystore文件本身是否可用
在命令行中用keytool工具直接检查keystore文件,可以确认文件没有损坏、密码是否正确、alias名称是否对得上。
如果你知道keystore的密码(假设是android,文件路径是~/.android/debug.keystore),可以在终端执行:
keytool -list -v -keystore ~/.android/debug.keystore -storepass android如果你用的是自己的正式keystore,就把路径和密码换成自己的。命令成功的话,会列出这个密钥库里的所有条目,包括别名、证书指纹、有效期。如果命令报错提示Keystore was tampered with或者password was incorrect,那就是文件本身的问题了。前者只能重建文件,后者检查一下密码是否记混了。执行这个命令本身不会修改keystore文件,放心跑就行。
5.3 第三步:用命令行手动完成一次签名
如果你想彻底绕开Unity的封装,直接验证SDK工具链的签名能力是否正常,可以手动跑一遍签名流程。先用Unity构建导出一个未签名的APK,构建时在Build Settings里勾选Export Project,然后取消Build App Bundle,让它导出Gradle工程。之后进入导出的工程目录,使用Gradle完成一次构建,如果Gradle能正常完成签名,说明SDK和apksigner没问题,问题就锁定在Unity配置上。
这个办法适合那些Unity界面操作已经试遍但依旧无解的项目,至少能把问题边界画清楚。稍微麻烦的是需要了解一点Gradle的命令,但不算复杂,一般的项目目录下直接执行:
./gradlew assembleDebug(Windows下是gradlew.bat assembleDebug),然后看构建输出的APK是否生成在app/build/outputs/apk/debug/目录下。
5.4 第四步:升级或更换Unity版本前想清楚
网上很多帖子会让用户升级Unity版本、重新安装Android模块来解决签名报错,但实战之下,这种做法成功率并不高。平台的签名流程相对稳定,版本升级很少直接治愈配置缺失带来的问题。除非你确认了自己当前的SDK tool版本和Unity版本之间存在已知兼容性问题,否则建议先把前面几类配置问题排除干净,再做版本切换的打算。
而且升级Unity版本本身有风险:项目里的代码可能需要调整、插件兼容性需要测试、构建管线有可能发生变化,这些都是额外的时间成本。为了一个配置问题冒大版本升级的险,不划算。
6. 日常使用中的建议与实际排查记录
6.1 关于签名信息的状态管理
调试密钥库虽然叫“调试”,但它跟项目绑定得很深。只要项目切换了签名,或者电脑上重新生成过keystore,打包出来的应用就会跟之前安装过的包“失联”——也就是无法覆盖安装,只能先卸载再装。这个坑在团队协作中尤其常见:开发者A用自己的调试签名打包给测试,开发者B又用自己机器上生成的另一个调试签名打包,测试手机上的应用就会不停地提示版本冲突或者安装失败。
比较合理的做法是:团队内约定一套统一的调试签名文件,放到共享的位置,大家统一使用这一个。正式签名的文件更是要严格管理,建议存到密码管理器里,同时保留一份离线备份,没有备份的正式签名不能用,否则应用以后没法更新。这些看似和报错没关系,但整个项目中因为签名不一致导致的“打包报错”,大概率都能归根到这一层。
6.2 一次真实的排查过程回顾
前段时间有个做数字孪生的朋友,项目里接了K2流程、串口通信、Web服务等一系列模块,在发布Windows客户端之前先打个Android包用于现场演示,结果就撞上了这个签名报错。他第一时间怀疑是不是Android SDK装坏了,按网上说的重新安装了SDK,结果照样报错。后来我远程帮他看:项目里确实设置了自定义keystore,路径指向的也是个真实存在的文件,但Key Alias填写的那串文字根本不在这个keystore里。密码没问题、文件没问题,就是alias不对,Unity在读取密钥时找不到对应的条目,最终报出来的仍然是这个“provide passwords”的文案。
把他引导到Keystore Manager界面,让他重新选择了正确的alias,保存后重新打包,一次性通过。这个案例说明,报错文案虽然只有一行,但背后可能是一个链条上任何一个环节出了问题。排查的时候别只看一个点,要按文件能不能找到→密码对不对→alias对不对→工具链能不能调用的顺序查一遍。
6.3 顺手整理了签名相关报错速查表
| 报错关键词 | 常见原因 | 解决方向 |
|---|---|---|
| Unable to sign the application; please provide passwords! | 签名信息缺失、密码没填、alias错误 | 检查Player Settings签名配置,补齐密码 |
| Keystore was tampered with, or password was incorrect | keystore文件损坏或密码错误 | 用keytool验证,必要时重建keystore |
| Failed to read key from keystore | alias不存在或密码不匹配 | 重新选择正确的alias,核对key密码 |
| INSTALL_PARSE_FAILED_NO_CERTIFICATES | APK未正确签名 | 重新执行签名,或改用apksigner手动签名 |
| INSTALL_FAILED_UPDATE_INCOMPATIBLE | 新旧包签名不一致 | 卸载旧版本后重新安装 |
| CMD ERROR: keytool not found | JDK环境异常 | 检查Java环境变量,确认keytool在PATH中 |
这张表里列的这些坑,我在实际项目里一个个踩过。很多问题一眼看上去毫无关联,但本质都是同一个签名体系在不同环节的投影。把签名这条链路彻底理解透了,这些报错都不再是玄学。
6.4 如何让打包流程更顺滑
最后分享几个日常能减少这类报错的操作习惯。
第一,首次创建项目后、开发中期以前,就把正式签名配置好。很多项目都是临到打包才发现签名没配,慌慌张张创建一个keystore,从填充到上传都容易出错。建议在项目初期直接按照上架标准创建签名文件,并录入到Unity配置里,后面一直沿用,能省掉大量切换签名的破事。
第二,搭建打包脚本时把签名密码改成环境变量输入。Unity是支持通过命令行传参数构建的,可以把密码放到环境变量或者CI系统的Secret里,避免明文写进脚本仓库。既安全,又能在不同机器上保持一致的构建配置。基础的调用方法是:
Unity -batchmode -projectPath 项目路径 -buildTarget Android -executeMethod 你的构建方法 -quit具体把密码注入配置的逻辑可以在构建方法里动态写入PlayerSettings。
第三,定期检查电脑上的SDK组件完整性。签名报错的另一种触发方式,是Android SDK目录下的build-tools被某些清理工具误删,或者不同版本之间路径切换导致Unity找不到工具。每过一段时间用SDK Manager看一次组件列表,成本很低,收益很直观。
7. 写在最后的经验分享
这个签名报错,在Unity所有打包相关的报错里算是高频但低难度的那种——前提是你能在正确的位置找到正确的开关。我见过太多人在这个报错上兜圈子,有人在命令行里反复试证书,有人重装了三次JDK,最后发现只是在Unity面板里勾选一下、填两行密码的问题。
我自己第一次遇到这个报错时也绕了弯路,甚至把构建日志翻到了最底层去研究apksigner的源码出参。后来冷静下来,把签名配置面板从头到尾捋了一遍才发现,是自己新建的keystore文件里alias名填错了。从那之后,我遇到这种乱七八糟的构建报错,都坚持一个原则:先看配置,再查环境,最后才怀疑工具链本身。很多时候问题的根源,就在你觉得“不可能出错”的那一步。
如果你是刚接触Unity打包,建议把这篇里关于签名机制的那一段多读两遍,理解keystore、alias、storepass、keypass这四个概念之间的关系,后面再遇到任何签名相关的坑,都会有一个清晰的排查方向。就算你这次没有遇到这个报错,我建议你也去Project Settings > Player > Publishing Settings看一眼,确认自己项目当前的签名状态。等打包真的报错时再去做这件事,心态和体验是完全不一样的——顺手的功夫,能帮你省下半天查日志的时间。