
上周有个做独立开发的朋友在群里吐槽Android Studio里点了半天APK终于出来了结果上传到应用市场半天不到就被打回原因写了三条——签名证书不对、隐私政策链接打不开、没有64位的so库。这情况我太熟了几乎每个第一次发布APP的人都会踩一遍。很多人以为发布就是把代码跑起来点一下Build就能拿到一个能装的文件实际上从开发机到用户手机屏幕中间隔着签名、构建配置、渠道规范、隐私合规还有各种自查细节每一环都可能让你的提审卡壳。这篇就把我这些年用Android Studio发布APP的完整流程、踩过的坑和可用指令都整理出来从零开始照着做大部分返工都能绕开。1. 发布前先想清楚你的APP要上哪个渠道1.1 不同分发渠道的规则差异发布APP之前第一步不是打开Android Studio而是想清楚这个包要发到哪里去。不同分发渠道对安装包格式、签名方式、隐私政策甚至版本号的要求都不太一样。国内主流的应用市场像华为、小米、OPPO、vivo、腾讯应用宝、百度手机助手这类每家都有自己的开发者后台需要先注册开发者账号、完成实名认证再按平台要求准备相应的资质材料。提交流程上每个市场都是独立审核同一个APK不一定能原封不动上传到所有平台因为有的市场要求targetSdkVersion达到指定版本有的市场强制要求隐私政策链接有的市场还需要你提供应用软著或者功能截图说明。而面向海外市场走Google Play规则又是另一套新应用通常要求使用AAB格式而不是APK开发者账号要注册费还会对应用的数据安全、广告SDK声明做严格审查。如果你只是做企业内部使用不走应用市场那可以用企业签名直接分发安装包这种形式不经过商店审核但必须自己管理好签名证书和设备白名单不能让安装了应用包的人随便把文件扩散出去。我的建议是个人开发者第一次发布别一口气铺十几个渠道先集中精力把一两个主流市场跑通等流程熟悉了再扩大范围。否则每次都要在各个开发者后台上传截图、填隐私政策、等审核光这些重复劳动就够消耗耐心了。1.2 多渠道发布时签名策略怎么定很多新手会问我发多个市场能用同一个签名文件吗这要分情况看。同一个应用包名相同的情况下必须使用同一个签名证书不然用户从A市场更新到B市场时系统会认为这是两个不同的应用出现“应用未安装”或者“覆盖安装失败”的问题。如果你给不同市场设置了不同的包名后缀那其实相当于两个独立应用签名自然可以不同。实际项目中我通常会给不同渠道定义不同的包名变体比如com.example.app.huawei、com.example.app.xiaomi用Android Studio里的productFlavors来做区分。这种做法的好处是每个市场一个包互不影响甚至某个渠道要单独配置SDK或者统计通道都能通过flavor单独处理。缺点是每次发版都要打多个包维护成本高一点。如果你不想包名不一样只想让应用在运行时知道自己是从哪个渠道下载的那就可以用同一个包名、同一个签名只通过manifest里的渠道占位符来区分。这个后面讲打包的时候再详细说。2. 签名这块硬骨头搞懂它你才不会返工2.1 签名到底做了什么APK本质上是一个ZIP压缩包但它不能随便改因为系统要验证它是不是来自可信的开发者、有没有被篡改过。Android的签名机制你可以理解成在包裹上贴一道防拆封条系统在安装时会检查封条是否完好、是不是你贴的那张。如果APK里任何内容被改动过校验值对不上系统就直接拒绝安装。签名文件按版本分为v1、v2、v3。v1是早期基于JAR签名的方案校验的是压缩包里的每个文件v2从Android 7.0开始使用对整个APK文件做摘要校验更安全也更快v3是在Android 11后引入的支持密钥轮换允许你在不改变包名的情况下更换签名证书。现在Android Studio打包release版本时默认会同时勾选v1和v2有些情况下还会勾v3。我的做法是targetSdk低于30时勾选v1和v2如果targetSdk是30或更高那我倾向于v1、v2、v3全勾上这样兼容性最好。有一个特别容易踩的坑如果你用了加固服务加固工具会改动APK内容所以加固操作必须在签名之前进行。你先把原始APK交给加固平台加固完成后它会返还一个需要重新签名的包这时候再用你的正式签名做一遍v2签名才能上传市场。如果你先签名再加固加固后的包校验不通过安装时会报签名不一致。2.2 用Android Studio生成正式签名文件正式签名文件不要用项目自动生成的debug.keystore。debug签名是开发调试用的密码都是公开的用debug签名发布的APP任何人都能用同样的签名伪造一个版本而且后续想切换到正式签名时需要卸载重装用户数据全丢。刚入门的开发者最容易犯这个错直接在Build菜单里选Build APK(s)觉得能出包就行结果出来的包其实是debug签名的测试包根本不能提交到应用市场。在Android Studio里生成正式签名文件可以走图形界面点击菜单栏的Build → Generate Signed Bundle / APK在弹出窗口里选择Create new然后填写Key store path、Alias、密码等信息。也可以用命令行生成命令这样写keytool -genkeypair -v \ -keystore myrelease.jks \ -keyalg RSA \ -keysize 2048 \ -validity 10950 \ -alias mykey \ -storepass your_store_password \ -keypass your_key_password \ -dname CNYourName, OUYourOrg, OYourOrg, LYourCity, STYourProvince, CCN这里有几个参数值得多说一句。-validity 10950是证书有效天数10950天就是30年。很多人图省事填10年等你应用活了超过10年要发新版本的时候签名证书已经过期了想升级都难。建议至少填25年以上。-keysize 2048是RSA密钥长度现在不建议用1024安全强度不够。Alias就是钥匙别名后面签名配置里要用的别随手乱填。文件生成后把这个jks文件复制到项目的keystore目录下然后把整个keystore目录加到.gitignore里绝对不要提交到Git仓库。签名文件和密码泄露了别人就能冒充你发布带恶意代码的版本。我把签名文件放在三个地方项目目录、移动硬盘、加密压缩包备份任何单一位置坏了都不会导致无法发版。2.3 用Gradle签名配置替代手动勾选签名文件生成好之后不需要每次都通过Android Studio的对话框手动选文件、输密码。更省事的方式是在build.gradle里配置signingConfigs让Gradle在打包时自动读取签名信息。android { signingConfigs { release { storeFile file(keystore/myrelease.jks) storePassword your_store_password keyAlias mykey keyPassword your_key_password } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro } } }密码直接写在build.gradle里方便归方便但有个明显的隐患如果项目是多人协作任何一个拉取代码的人都能看到你的密码。稳妥一点的做法是把密码写到gradle.properties文件里然后用变量引用def storePass gradle.properties里的变量名更高阶的做法是配置环境变量让Gradle从系统环境变量里读取签名文件本身也放在本机路径里这样仓库里完全看不到敏感信息。我个人建议至少做到第一步把密码放进gradle.properties并且这个文件不提交到Git。养成这个习惯后面合作开发时能省掉很多扯皮。3. 打包全流程实录从Gradle配置到APK生成3.1 打包前的版本与构建配置检查打包之前先打开build.gradle检查几个关键配置项这些地方出了问题轻则审核被拒重则用户安装失败。versionCode是内部的版本号必须是整数每次发布新版本都要比上一次大应用市场靠它判断能不能覆盖更新。versionName是展示给用户看的版本号比如1.0.0这个相对自由但不能乱改成新版本号却让versionCode不变那样用户永远收不到更新推送。minSdkVersion决定你的应用最低支持到哪个Android版本targetSdkVersion决定你针对哪个系统版本做了适配。各应用市场对targetSdk有硬性要求近两年的主流市场都要求至少能编译到Android 12或更高的targetSdk。适配新版本系统的同时还要检查Android 12开始强制要求的android:exported属性只要你的manifest里有四大组件包含intent-filter没有设置这个属性就会直接编译失败。我把日常要检查的清单列在下面versionCode是否比上一个版本大minSdk、targetSdk是否满足目标市场要求是否配置了release版本的正式签名是否启用了代码混淆和资源压缩是否声明了所有用到的权限且没有多余权限是否包含目标市场要求的64位so库架构3.2 Build菜单打release包的详细步骤配置没问题打包就很快了。Android Studio打开项目点击菜单栏的Build → Generate Signed Bundle / APK弹窗里会有两个选项Android App Bundle和APK。第一次发布建议先选APK因为APK文件可以直接安装到手机测试也可以上传到国内各渠道。点Next进入签名信息填写页选择你之前创建好的.jks文件输入storePassword、keyAlias和keyPassword。这里很多人会忘记Release签名顺手选了debug配置结果打包出来后签名不对。如果你在build.gradle里已经配置好了signingConfigs这一步也可以直接选已有的配置不用重新输密码。接下来选择构建类型一定看清楚Bundle Type选的是release不是debug。Signature Versions这里v1和v2建议都勾上。如果你的targetSdk在30以上建议把v3也勾上毕竟很多新机型对v3的兼容性已经没任何问题了。点击Finish后Gradle会跑一遍编译任务输出路径默认在app/build/outputs/apk/release/下文件名通常是app-release.apk。你可能会好奇为什么同样的项目用Build → Build APK(s)出来的是app-debug.apk不能上传就是因为那个命令构建的是debug变体用的也是debug签名不是你正式发布的release变体。要上架就必须用Generate Signed Bundle / APK这个入口或者用Gradle命令行执行gradlew assembleRelease。3.3 多渠道包怎么打如果你的应用要发多个市场又希望同一个包名可以区分用户来源渠道信息通常写在manifest文件里用一个占位符代替。先在AndroidManifest.xml里加一个meta-datameta-data android:nameCHANNEL android:value${channel_id} /然后在build.gradle里给不同渠道定义不同的channel_idflavorDimensions channel productFlavors { huawei { dimension channel manifestPlaceholders [channel_id: huawei] } xiaomi { dimension channel manifestPlaceholders [channel_id: xiaomi] } oppo { dimension channel manifestPlaceholders [channel_id: oppo] } }这样执行gradlew assembleHuaweiRelease就能打出携带huawei渠道标识的release包。如果你想统一管理APK命名还可以在输出文件名的配置里加一段动态命名逻辑让生成的APK自动带上版本号和渠道名比如app-1.0.0-huawei-release.apk后续就算几十个包堆在一个文件夹里也不会搞混。3.4 AAB和APK到底选哪个Android App Bundle是Google推的格式和APK不是一个类型。AAB不是一个可直接安装的文件它等于是把应用的所有资源和代码打成一个“半成品”由应用市场根据用户的设备配置动态生成对应版本的APK好处是安装包更小只下载当前设备需要的资源和so库。Google Play已经要求新应用必须使用AAB上传。国内大部分渠道目前还是以APK为主但很多也开始支持AAB了。建议是第一版发布按照目标市场的要求来发Google Play上传AAB发国内传统市场上传APK。后面如果Android Studio提示你某个市场不支持AAB就切回APK导出两边都要兼顾。4. 上架前的自查清单很多开发者都栽在这些地方4.1 图标、名称、截图和隐私政策应用市场审核第一眼看到的就是图标、名称、截图这些表层信息。图标要按主流市场的要求准备一般需要512x512像素的高清版本同时要在Android Studio里通过Image Asset生成各密度目录下的自适应图标包括mdpi、hdpi、xhdpi、xxhdpi和xxxhdpi。不少项目只在mipmap下放了一个默认图标结果应用安装后图标模糊或者直接变形审核也很容易被打回。应用名称也有讲究。不同市场对名称长度有限制通常不超过30个字符而且要和应用内的功能一致。比如你本来是个工具类应用名称里非要带什么“神器”“大师”之类的词人工审核时反而容易觉得有夸大宣传的嫌疑。隐私政策这块是很多独立开发者的硬伤。只要应用收集了任何用户信息哪怕只是设备型号和建议安装的软件列表各市场都会要求你提供一个可公开访问的隐私政策页面并且这个链接必须真实有效。我见过最可惜的一次打回是有人把隐私政策链接写成了公司内部测试地址审核人员点开根本打不开直接拒。建议的做法是如果没条件部署独立网站至少用云文档发布一个公开链接把收集什么数据、怎么使用、怎么联系你写清楚链接放到应用市场和APP内关于页面两个位置同步更新。4.2 权限申请与合规权限是Android审核里最严肃的一环。很多新手会干脆在manifest里把所有常见权限都写上想着“反正写上就能用”结果审核正好抓住了你申请了与核心功能无关的权限直接以“权限与业务功能不符”退回。我的原则是只申请当前版本真正用到的权限。比如一个计算器应用根本没理由申请通讯录权限或者定位权限。定位、相机、麦克风、通讯录这些敏感权限在Android 6.0之后都要在运行时动态申请并且用户拒绝后程序不能崩溃。Android 13把通知权限单独拆了出来Android 14对照片和视频的选择权限也做了限制如果你在targetSdk 34上开发这部分适配工作一定要做。提审前把manifest从头到尾读一遍每看到一个权限就问一句这个权限在哪个功能里用到了答不上来就删掉。删完后在真机上跑一圈确认核心功能不受影响再上传。4.3 64位支持与包体瘦身2023年后主流应用市场普遍要求新应用和更新应用必须支持64位arm架构也就是APK里要包含arm64-v8a目录下的so库。如果你的应用只用了Java和Kotlin代码没有集成第三方so库那一般没有这个问题但凡你用了某些视频播放器、地图、扫码、加密SDK这些SDK的so库里如果只有armeabi-v7a那要检查SDK版本找支持arm64的版本替换。检查APK里有没有64位so库最直接的办法是把APK后缀改成zip解压后看lib目录下有哪些文件夹。只用armeabi-v7a没有arm64-v8a的包上传市场基本都会被拦下来。在没有拿到64位so库之前可以用Gradle里的abiFilters暂时过滤掉部分不支持的架构但这不是长久之计只能作为临时方案。包体瘦身也有很多琐碎但有效的路子。开启minifyEnabled true做代码混淆开启shrinkResources true做无用资源移除替换大体积的图片为WebP格式把不常用的第三方库懒加载化。这些操作叠加下来包体从几十兆降到十几兆很正常。4.4 应用加固别忘了先把APK上传到某个应用市场提审之前我强烈建议先做一次加固。加固的实际作用是对代码做保护让逆向分析和破解的难度大幅提高尤其对那种接入了支付、登录功能的APP不加固相当于把核心逻辑裸奔。各大应用市场都提供免费的加固服务比如腾讯云、阿里聚安全、360加固保你把原始release包传上去加固完成后下载加固后的包因为加固过程改了包内容需要你在加固平台里用正式签名重新签名一次或者上传签名信息由平台代签。这里的顺序千万别反过来先加固再签名最后上传的包才是完整的。要注意的是加固后一定再完整回归一遍核心功能。有些加固方案会和特定的混淆规则、反射代码冲突导致某个页面打不开、启动崩溃。我的习惯是加固完把包安装到一台干净测试机上登录、支付、扫码这些高频操作用户怎么点我就怎么点一遍。5. 发布时最容易遇到的10个问题附自查命令5.1 高频报错与解决方案我把发布过程中经常遇到的问题整理成了一个速查表带有可操作的排查路径提审前逐项过一遍可以少走很多弯路。问题现象最可能的原因处理方式安装时报INSTALL_PARSE_FAILED_NO_CERTIFICATESAPK没有签名或签名不完整用Generate Signed APK重新打包覆盖安装时报INSTALL_FAILED_UPDATE_INCOMPATIBLE新旧包签名不一致确认正式签名文件与上一个版本一致上传后提示签名证书指纹不符上传的keystore和平台记录的不是同一个找到最初注册平台时使用的keystore比对指纹提审被拒隐私政策链接无法访问链接失效或用局域网地址换成公网可访问的页面提审被拒申请权限与业务无关manifest里申请了多余权限删除无关权限重新检查所有权限用途安装后提示“应用未安装”包体损坏或so库缺失targetSdk兼容问题真机安装测试解压APK查看lib目录编译报Could not determine the dependencies网络原因导致依赖下载失败清理Gradle缓存gradlew clean检查网络与代理配置Android 12以上系统启动崩溃targetSdk 31 但manifest缺少android:exported给含intent-filter的组件补上android:exported应用市场要求64位架构so库缺少arm64-v8a更新第三方SDK版本重新打包验证上传AAB时提示文件格式不支持目标市场不支持AAB改导出APK后再上传第6条里提到的“检查代理配置”指的是开发环境里网络访问配置的问题大家自己排查网络的时候注意用合规合法的网络环境操作即可。5.2 几个能救命的命令行工具Android SDK的build-tools里自带一些命令行工具发布前用来验证APK很管用。我最常用的有三个。查签名证书信息用keytoolkeytool -printcert -jarfile app-release.apk这条命令会输出APK的签名证书指纹和有效期和开发者后台里的证书指纹对一下就能确认签名文件是不是同一个。用apksigner验证签名格式apksigner verify --print-certs app-release.apk它会明确告诉你APK的v1、v2、v3签名是否都有效。如果某个版本签名缺失这里会直接显示NO。用aapt查看APK的基本信息aapt dump badging app-release.apk | head -n 20这条命令能一次性看到包名、版本号、targetSdk、权限列表提审前扫一眼能发现很多配置上的遗漏。这些工具都在SDK的build-tools目录下Android Studio本身没有可视化入口但命令行用起来很快熟悉之后比鼠标点来点去高效得多。5.3 我建议你保存的发布检查清单每次提审前我会按这个固定顺序走一遍大概十分钟但能让返工概率大幅下降确认versionCode比上一次发布大versionName展示正确用正式签名打出release包用apksigner验证v1、v2签名都有效在至少两台安卓真机上安装覆盖安装和全新安装各测一遍跑一遍登录、支付、文件上传下载等核心流程检查manifest权限确认没有多余权限打开隐私政策链接确认公网可访问解压APK确认包含arm64-v8a目录用加固平台完成加固并重新签名上传目标应用市场填写资料和截图这套流程从我用Android Studio做开发一直用到现在中间经历过几次审核新规变化但大方向基本没变过。有几次我自己赶时间跳过了某一步比如觉得“这次只改了个文案不用重新测权限”结果提审后被“多轮对话中重复出现隐私权限声明不一致”这种问题打回教训都是当场学的。发布APP这件事做第一次的时候会觉得全是坑每个环节都很陌生等你把签名、打包、自查这套动作重复三五次以后整个流程就会变成肌肉记忆。我最想叮嘱你的一句话就是签名文件一定多重备份密码一定别写进公开仓库版本号规则一定提前定好隐私政策链接一定别随意改。这四件事做好了发布流程里至少一半的返工都和你无关了。