ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

新建 Android 项目:Gradle Sync 与环境配置完整避坑

新建 Android 项目:Gradle Sync 与环境配置完整避坑 上周帮一个学弟看他新装的 Android Studio他遇到的问题很有代表性装完 IDE点了 New Project选好模板点 Finish然后卡在 Gradle Sync 的进度条上整整四十分钟最后弹出一屏红字他直接把窗口关了。第二天他又试了一次这次 Sync 过了但点 Run 之后模拟器迟迟不出来他以为是自己电脑太差。第三天他给我发消息说是不是我根本不适合写安卓。其实这三件事——Sync 慢、模拟器起不来、跑不起来——跟适不适合一点关系都没有它们全都是环境配置和项目结构认知的问题。创建第一个 Android 项目这件事看起来只是点几下向导按钮实际上它一次性把 JDK、Gradle、AGP、Android SDK、模拟器加速方案这几层东西全绑在了一起任何一层版本对不上你看到的都是同一句Gradle sync failed。这篇文章我会把从装环境到跑起来、再到能点一下按钮有反应的完整链路拆开讲重点是每一步背后的原理和真实踩过的坑而不是把官方向导的截图再复述一遍。适合完全没接触过 Android 开发的新手也适合以前用过 Eclipse 时代 ADT 插件、现在被 Gradle 搞得有点晕的老手。1. 先搞清楚一个 Android 项目长什么样再动手新建1.1 从源码到 APK构建链路到底串了哪几环很多人新建项目失败根本原因是脑子里没有这条链路你写的 Kotlin/Java 源码和 XML 资源先被Kotlin 编译器和AAPT2分别处理产出.class文件和编译后的资源然后交给D8转成 dex 字节码再被APK Packager打包最后用apksigner签名。这整条流水线全部由Gradle调用AGPAndroid Gradle Plugin来编排。所以你就明白了Gradle 是干活的工头AGP 是懂安卓业务的施工队长JDK 是他们的工具箱Android SDK 是仓库里的原材料。四者缺一不可且版本必须互相认识。新手最容易忽略的是工具箱这一环——AGP 8.x 强制要求 JDK 17你系统里如果只有一个 JDK 8很多老教程让人装的就是 8Gradle 会直接拒绝启动报错信息里通常会有Unsupported class file major version或者Android Gradle plugin requires Java 17。我第一次遇到这个问题时直觉是去升级系统环境变量里的 JAVA_HOME折腾了半天发现没用因为 Android Studio 默认用的是它自己捆绑的 JBRJetBrains Runtime。真正该改的地方在Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle JDK。这里选jbr-17或者Embedded JDK问题当场消失。这个位置建议你新建第一个项目之前就去看一眼能省掉后面一半的莫名其妙。1.2 工程目录里你真正天天要碰的只有六个地方向导生成的目录结构看起来很吓人其实 90% 的时间你只会打开这几个位置app/src/main/java/.../MainActivity.kt主界面代码Kotlin 默认放这里app/src/main/res/layout/activity_main.xml界面布局用 XML 描述控件树app/src/main/res/values/strings.xml所有文案中文英文都放这儿硬编码字符串是坏习惯app/src/main/AndroidManifest.xml应用清单声明 Activity、权限、应用名和图标app/build.gradle.kts模块级构建脚本加依赖、开 ViewBinding、配签名都在这里gradle/libs.versions.toml新版向导会生成这个版本目录文件依赖版本集中管理剩下那些gradlew、.gradle/、build/、proguard-rules.pro之类的不是不能用而是第一个项目阶段完全不需要碰。我见过新手一上来就去改settings.gradle.kts里的仓库配置改完 Sync 挂了又不知道从哪回滚最后只能删项目重建。第一个项目阶段的正确心态是只碰上面六个文件其余一律当黑盒。1.3 三个版本号决定的不是能不能跑而是能装在哪些手机上新建项目时会看到compileSdk、targetSdk、minSdk三个数字新手通常随手就用默认值但它们的含义完全不同版本号含义影响范围建议取值compileSdk用哪个版本的 SDK 编译只影响编译期能用到哪些新 API取最新稳定版如 35targetSdk声明应用适配到哪个版本影响运行时的行为兼容策略尽量跟 compileSdk 一致minSdk最低支持到哪个版本决定能装到多老的手机上24 是比较舒服的平衡点minSdk设成 24Android 7.0意味着放弃了 Android 6 及更早的设备但换来的是不用再写运行时权限的兼容分支、可以直接用 Java 8 的部分 API。目前 Android 7 以下的存量设备占比已经非常低除非你明确知道目标用户群体里有一批老旧机型否则没必要为了那几个百分点把minSdk压到 21 甚至 19那会让你在权限、通知、文件访问上多写一大堆兼容代码。targetSdk则完全不同的逻辑它不限制安装但决定了系统用哪套行为规则对待你的应用。比如targetSdk低于 31 时声明了 intent-filter 的 Activity 不需要写android:exported一旦升到 31 及以上缺这个属性会直接编译失败。这就是为什么你从网上抄来的老代码在新项目里跑不起来——不是代码错了是规则变了。2. 开工前的环境盘点JDK、SDK、IDE 三件事2.1 JDK 装在哪、用哪个是两回事系统里可以装很多个 JDK但 Android Studio 只认你在 Gradle 设置里指定的那一个。判断当前用的是哪个最简单的办法是在 Android Studio 里打开Terminal 面板敲./gradlew -version输出的内容里会明确写出JVM: ...那个路径就是实际生效的 JDK。如果显示的是 1.8 或者 11而你用的是 AGP 8.x那 Sync 必然失败。顺带说一个高频现象命令行敲java -version显示 17但 Android Studio 里 Sync 依然报 JDK 版本错。原因是命令行读的是系统JAVA_HOMEIDE 读的是自己的配置两者互不干扰。别在这上面浪费时间互相验证直接在 IDE 里改就完了。2.2 装完 IDE 之后有三件事推荐立刻做第一件是确认 SDK 路径。默认在 Windows 上是C:\Users\你的用户名\AppData\Local\Android\SdkmacOS 上是~/Library/Android/sdk。这个路径绝对不要有中文、空格或特殊符号后面 Gradle 处理 NATIVE 库路径时对空格很敏感会报AAPT2 error: ... No such file or directory这种错误极难定位。第二件是装 Chinese Language Pack 插件如果英文界面让你读报错很吃力。在Settings → Plugins → Marketplace搜Chinese装官方那个重启生效。但我个人的建议是菜单汉化没问题报错信息千万别依赖翻译。Stack Overflow 和官方 Issue Tracker 上全是英文关键词把Could not resolve翻译成无法解析之后你再去搜基本搜不到有效答案。第三件是打开 SDK Manager 把必要组件补齐。至少要有对应版本的 SDK Platform、Android SDK Build-Tools、Android SDK Platform-Tools含 adb、Android SDK Command-line Tools、以及一个 System Image模拟器要用。System Image 建议选x86_64架构带 Google APIs 的版本跟自己compileSdk对应的那个大版本对齐。提示SDK 组件是按需下载的不用一次全勾。但 Command-line Tools 强烈建议装上后面sdkmanager和avdmanager命令行工具都靠它。2.3 磁盘空间和代理设置的现实问题一个完整的 Android 开发环境SDK 加上 AVD 虚拟设备镜像轻松吃掉 20 到 30 GB。如果 C 盘吃紧可以在系统环境变量里设一个ANDROID_SDK_ROOT指向 D 盘的目录然后 Android Studio 会自动识别。AVD 镜像同理在Settings → Tools → Device Manager或者环境变量ANDROID_AVD_HOME里改。至于依赖下载的加速思路是给 Gradle 配国内镜像仓库。常见的做法是在settings.gradle.kts的dependencyResolutionManagement块里把maven.aliyun.com系列的仓库加在前面。这个配置很常规无数开源项目都在用具体地址去阿里云 Maven 官方页面拿最新的即可我这里不贴死地址因为仓库地址偶尔会调整。3. 新建项目向导每个选项都在决定后面几天的命运3.1 模板怎么选Empty Activity 还是 Empty Views Activity新版 Android Studio 的模板列表里跟空项目沾边的通常有两个Empty Activity和Empty Views Activity。名字很像但生成的代码体系完全不同。前者生成的是Jetpack Compose项目界面全部用 Kotlin 函数描述没有 XML 布局后者才是传统的View 体系生成activity_main.xml加MainActivity.kt的经典组合。选哪个取决于你的目标。如果这是学校课程作业教材大概率还在讲 XML 布局和findViewById那就老老实实选 Empty Views Activity否则你会发现自己和全班的代码对不上号。如果你是自己想学现代写法直接上 Compose 也完全可以只是要接受一个现实网上很多老教程的代码粘贴进去会编译不过。还有一个容易被忽略的点向导生成的模板代码本身就在示范最佳实践。比如它默认用 ViewBinding 而不是findViewById默认把文案放strings.xml而不是硬编码默认在themes.xml里统一配主题。这些约定值得你照着学而不是上手就改回自己习惯的写法。3.2 包名一旦定了后面改起来很麻烦向导里的Package name通常默认是com.example.xxx。这个东西不是随便填的它是应用的唯一身份标识同时决定了设备上的数据目录路径/data/data/包名/R资源类的包路径错了会Unresolved reference: R应用市场里的唯一标识上架后基本不能改FileProvider的 authority 一般写成包名.fileprovidercom.example这个前缀在 Google Play 上是不能上架的所以如果你的项目有朝一日要发布最好一开始就用真实域名倒写比如cn.yourname.myfirstapp。改包名在 Android Studio 里不是简单改个字符串涉及目录结构重命名、build.gradle.kts里的namespace、applicationId、Manifest 里的引用非常容易漏。第一个练手项目用com.example无所谓第二个开始就要认真起名了。3.3 Kotlin 还是 JavaKotlin DSL 还是 Groovy DSL语言选项上Kotlin 现在是官方主推新模板默认就是它。Java 依然可用生态里大量老代码是 Java 的看懂了不亏。两者可以在同一个项目里共存不需要纠结选错了会不会死。构建脚本语言这个选项更值得注意。新版向导默认生成build.gradle.ktsKotlin DSL和libs.versions.toml。Kotlin DSL 的好处是有类型检查和自动补全写错属性名 IDE 会直接标红代价是你从网上抄来的 Groovy 写法compileSdkVersion 34这种粘进去不认必须改成compileSdk 34。我用 Kotlin DSL 踩的第一个坑是单引号和双引号Groovy 里com.example和com.example都能用Kotlin DSL 里必须双引号。这个细节看似无聊但足以让一次 Sync 报出一屏看起来毫无关联的错误。3.4 minSdk 的取舍顺便说下 Gradle 版本对齐向导里最低支持版本的下拉框实际映射的就是minSdk。我在 1.3 节说的 24 是个稳妥选择。但如果你要做的是那种给工厂老旧平板用的内部工具可能要压到 21反过来如果只用公司内部新设备直接 26 或 28 也行能少写很多兼容代码。另外强烈建议记一下这张对应关系它解释了 90% 的版本不兼容报错Android Studio 大版本AGP 版本要求的 Gradle要求的 JDKHedgehog 2023.18.28.217Iguana 2023.28.38.417Jellyfish 2024.18.48.617Koala 2024.1.28.58.717Ladybug 2024.28.78.917Meerkat 2024.38.98.1117这张表是大致对应而非精确约束官方发布说明里会有微调但方向是对的IDE 版本决定了它自带哪个 AGPAGP 版本决定了它需要哪个 Gradle 和哪个 JDK。你从别人那里拷来一个项目跑不起来八成是这三层里有一层错位了。4. 第一次 Gradle Sync卡住、超时与镜像配置的完整排查4.1 Sync 阶段 Gradle 到底在干什么很多人把 Sync 当成加载项目其实它在干四件很重的活第一下载并启动gradle-wrapper.properties里指定的那个 Gradle 发行版几十到上百 MB第二解析所有仓库把依赖的 AAR/JAR 拉下来第三执行 AGP 的配置阶段生成BuildConfig、R类、Manifest合并结果第四把项目结构信息回传给 IDE你才能看到蓝色的小文件夹图标和代码补全。四个阶段里最慢的通常是第一个和第二个。所以当你看到 Sync 卡住时先去Build 窗口看当前停在哪个任务上。如果是Download https://services.gradle.org/distributions/gradle-x.x-bin.zip那是发行版下载慢如果是Download https://dl.google.com/dl/android/maven2/...那是依赖仓库慢。两者解法不同。4.2 依赖下载慢的三层解法从轻到重第一层换个更快的 Gradle 发行版下载源。改gradle/wrapper/gradle-wrapper.properties里的distributionUrl把services.gradle.org换成国内镜像地址。改完别忘了 Sync 一次改这个文件需要重新触发下载。第二层给依赖仓库加镜像。在settings.gradle.kts的dependencyResolutionManagement里把镜像仓库放在google()和mavenCentral()前面。注意顺序很重要镜像仓库放前面才会优先命中。第三层离线模式。如果依赖已经全部下载过一次Sync 又因为网络原因失败可以打开Gradle 面板右上角的 Toggle Offline Mode小图标强制走本地缓存。这是个应急手段不适合长期开因为新加的依赖会解析不到。顺带说一个真实踩过的坑公司网络里如果有内网的源Gradle 可能因为证书问题报PKIX path building failed。这种报错看着吓人本质是证书链校验失败处理方式要么是把内网证书导入 JDK 的 cacerts要么改走公共镜像。别在这个报错上怀疑人生它不是你的代码问题。4.3 三张最常见的错误脸以及怎么读第一张脸Could not resolve com.android.tools.build:gradle:x.x.x。意思是在你配置的所有仓库里都找不到这个 AGP 版本。原因通常是版本号写错了或者仓库列表里少了google()。检查settings.gradle.kts的pluginManagement块。第二张脸Unsupported class file major version 65或 61、60。数字跟 JDK 版本一一对应65 是 JDK 2161 是 JDK 1760 是 JDK 16。看到这个直接去改 Gradle JDK 设置。第三张脸Manifest merger failed。第三方库的 Manifest 和你的冲突了错误信息里会明确写Element ... at ... merged from ...。解决办法是在AndroidManifest.xml的对应节点加tools:replace属性名并在根节点声明xmlns:tools。这个错误看起来最复杂其实最好修因为报错信息直接告诉你去哪一行改。注意读 Gradle 报错永远从最底部往上找第一段Caused by:那才是根因。上面几十行 Task :app:xxx FAILED都是连锁反应不要从头开始读。5. 把应用跑到屏幕上模拟器与真机的取舍5.1 模拟器加速方案的坑以及 Hyper-V 冲突创建 AVD 的时候如果 Windows 上装过 Hyper-V、WSL2、Docker Desktop模拟器的加速驱动会打架。老方案是 Intel HAXM但它和 Hyper-V 互斥现在官方推荐的是AEHDAndroid Emulator Hypervisor Driver或者在 Windows 上启用WHPXWindows Hypervisor Platform。判断当前用的哪个方案看SDK Manager → SDK Tools里装了哪个。如果装的是 HAXM 又开了 Hyper-V模拟器启动时会报一串关于HAXM is not installed或emulator: ERROR: x86 emulation currently requires hardware acceleration的错误。解决路径大致是关掉 HAXM装 AEHD或者干脆在 Windows 功能里打开Windows 虚拟机监控程序平台和虚拟机平台让模拟器走 WHPX。改完之后要重启电脑这个步骤容易被跳过。还有一个纯硬件层面的硬性要求模拟器需要 CPU 支持 VT-x/AMD-V而且要在 BIOS 里打开。品牌笔记本通常默认关闭这一步在 Windows 的任务管理器 → 性能 → CPU 里能看到虚拟化已启用/已禁用。5.2 真机调试比模拟器靠谱前提是 adb 通了我个人的建议是第一个项目优先用真机模拟器只当补充。真机的性能、网络、传感器行为都更接近真实而且不用跟加速驱动斗智斗勇。真机调试的完整流程是手机开启开发者选项连点七次版本号→ 打开 USB 调试 → 数据线连电脑 → 手机上弹窗点允许调试。然后在 Android Studio 的 Terminal 里敲adb devices正常情况下会列出设备序列号加device状态。如果显示unauthorized说明授权弹窗没点或者被拒绝了如果列表是空的说明 adb 没识别到设备。再补几个新手该知道的高频命令adb install -r app-debug.apk # 覆盖安装保留数据 adb uninstall com.example.app # 卸载 adb shell pm list packages | grep 关键词 # 查已安装包名 adb logcat -s MyTag # 只看某个 Tag 的日志 adb shell dumpsys dropbox --print # 查看系统级崩溃记录adb install和直接点 Run 的区别在于Run 会先编译再安装再启动还会挂载调试器adb install只做安装。当你要反复测试一个已经打好的 APK 时后者快得多。5.3 设备连不上按这个顺序排查现象可能原因处理方式adb devices 为空数据线只供电不传数据换一根支持数据传输的线显示 unauthorized手机端授权弹窗被拒撤销 USB 调试授权后重连显示 offlineadb 服务状态异常adb kill-server后重启设备列表有但 IDE 看不到多个 adb 版本冲突统一用 SDK 目录下的 adb每次连都断省电策略杀后台关闭电池优化允许后台活动多个 adb 版本冲突这条特别隐蔽。如果你装过某些手机助手类软件它可能自带一个老版本 adb 并占用了 5037 端口导致 Android Studio 用的 adb 连不上自己的服务。排查方法是在终端敲adb version看版本号如果不是 SDK 目录下那个就把环境变量里的 PATH 顺序调一下或者干脆卸掉那个助手类软件。6. 第一个能交互的界面布局、绑定与点击事件6.1 从 XML 到 ViewBinding绑定链路是怎么走的模板生成的activity_main.xml里通常是ConstraintLayout包一个TextView。你要加控件直接在里面写Button android:idid/btnStart android:layout_widthwrap_content android:layout_heightwrap_content android:textstring/btn_start / ProgressBar android:idid/progressBar style?android:attr/progressBarStyleHorizontal android:layout_width0dp android:layout_heightwrap_content android:max100 android:progress0 /android:id前面的id/里那个加号表示如果不存在就新建这是新手最容易疑惑的语法点。android:text用string/xxx而不是直接写中文好处是以后要做多语言时不用改代码而且避免编码问题。要在代码里拿到这些控件需要先开 ViewBinding。在app/build.gradle.kts的android块里加android { buildFeatures { viewBinding true } }Sync 之后编译器会为每个布局文件生成一个同名驼峰类activity_main.xml对应ActivityMainBinding。这个类在你完整的 Activity 里可以直接用。用 ViewBinding 而不是findViewById的核心好处是编译期就有类型检查控件删了或者 ID 改了代码立刻标红不会等到运行时空指针崩溃才发现。6.2 一个最小可用页面点击按钮驱动进度条下面这段代码把按钮、进度条、文本串起来你可以直接粘到MainActivity.kt里对照理解class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private var progress 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.btnStart.setOnClickListener { progress (progress 10).coerceAtMost(100) binding.progressBar.progress progress binding.tvStatus.text getString(R.string.status_fmt, progress) } } }这里有几处值得注意的设计。lateinit var binding而不是可空类型是因为它一定会在onCreate里被赋值用lateinit可以省掉后面每次用的!!。coerceAtMost(100)是 Kotlin 的标准库函数把值限制在不超过 100等价于 Java 里写Math.min(progress 10, 100)但更顺眼。getString(R.string.status_fmt, progress)对应strings.xml里的string namestatus_fmt已完成 %1$d%%/string。注意百分号要转义成%%%1$d是占位符。硬编码中文拼接字符串是新手通病一旦要做多语言或者targetSdk升上去遇到 lint 检查就得回头改一堆地方。6.3 Logcat 是你在 Android 上唯一的眼睛桌面开发有断点调试的完整界面Android 也能打断点但更多时候你会依赖Logcat。打开方式在 IDE 底部的 Logcat 面板它按进程、Tag、级别过滤日志。几个实用技巧过滤框里输入package:mine可以只看自己应用的日志用level:error只看错误多个条件用空格连接表示 AND。代码里打日志推荐用Log.d(MainActivity, progress $progress)然后用adb logcat -s MainActivity或者 Logcat 面板按 Tag 过滤。不要用 println它在部分设备上根本不进 Logcat 缓冲区你会以为自己代码没执行。还有一个新手常遇到的困惑Logcat 面板一直刷其他应用的日志刷得飞快看不清自己那行。原因是设备上所有进程的日志都在同一个缓冲区里。解决办法就是前面说的package:mine过滤或者用 Tag 过滤。养成先过滤再打日志的习惯能省掉大量翻日志的时间。7. 六个高频翻车现场与对应处理7.1 从别人那里拉下来的项目Project 面板是空的这个现象很典型项目在磁盘上明明有文件IDE 左侧却不显示源码树。原因一般是Gradle Sync 没成功IDE 拿不到项目结构信息所以只能显示一个空壳。还有一种情况是项目里缺少.idea目录或者它被.gitignore忽略了IDE 需要重新识别。处理顺序是先点Sync Project with Gradle Files大象图标等它完整跑完如果还是空的去File → Project Structure确认模块是否被正确识别再不行就关掉 IDE删掉项目根目录的.gradle/和.idea/重新用Open打开项目根目录注意是根目录不是app目录。用 Open 打开错目录是另一个高频原因。Android Studio 对项目根目录的判断依赖settings.gradle.kts的位置如果你的打开路径比它高一层或者低一层就会出现能打开但没有模块的状态。7.2 中文乱码和 strings.xml 的编码问题Android Studio 默认文件编码是 UTF-8但如果你从 Windows 的记事本或者老编辑器里拷代码过来文件可能是 GBK 编码打开就变乱码。检查方式在右下角状态栏会显示当前文件编码。批量修复可以在Settings → Editor → File Encodings里把三个编码全设为 UTF-8并勾选Transparent native-to-ascii conversion。值的一提的是gradle.properties里加一行org.gradle.jvmargs-Dfile.encodingUTF-8也很有必要能避免构建过程中 javac 用系统默认编码读文件导致的乱码。我在 Windows 上遇到的代码里好好的中文跑到模拟器上变成问号根因就是这个。7.3 项目路径含中文或空格这是个看起来无关紧要、实际能卡死你的问题。Gradle 在处理 native 库和某些路径拼接时对空格和中文的处理不完善典型报错是AAPT2 aapt2-xxx-windows: ... No such file or directory或者 NDK 相关的ninja: error。正确的做法是一开始就把工作区放在纯英文、无空格的路径下比如D:\Projects\Android\MyFirstApp。不要放在桌面、文档这些路径里带用户名可能含中文的地方。这个坑一旦踩了改路径意味着重新配 SDK 路径、重新 Sync、重新配签名代价不小。7.4 targetSdk 31 以上必踩的 exported 报错升级targetSdk到 31 或更高之后凡是声明了intent-filter的组件必须显式写明是否对外暴露activity android:name.MainActivity android:exportedtrue intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity报错信息通常是android:exported needs to be explicitly specified for activity。这不是 bug是安全策略——防止应用无意中把内部组件暴露给外部调用。主入口 Activity 必须是true其他内部使用的 Activity 写false。7.5 R 文件变红 / 资源找不到Unresolved reference: R这个错误的原因特别多XML 里有语法错误导致 AAPT2 编译中断、namespace和实际包结构不一致、资源文件名含大写字母资源名只允许小写字母、数字和下划线、或者 Sync 没跑完就被中断了。排查顺序是先看Build 窗口有没有更底层的 AAPT2 报错R 文件报红往往只是表象再检查所有资源文件名是否全小写再确认build.gradle.kts里的namespace和AndroidManifest.xml里的package如果还有以及源码目录结构是否一致。改完之后点Build → Clean Project再Rebuild Project很多时候清理一下就好了。7.6 用了 CoordinatorLayout 之后控件位置全乱CoordinatorLayout是个聪明的容器它会根据子 View 的layout_behavior做联动。新手直接把ConstraintLayout里的代码搬进去会发现约束属性全部失效控件叠在一起。原因是CoordinatorLayout不认app:layout_constraintXXX这套约束它需要app:layout_anchor、app:layout_behavior这些。如果你只是想加个可折叠的顶部栏或者轮播图Banner 组件通常就依赖 CoordinatorLayout 做联动那就用如果只是普通页面布局老老实实用ConstraintLayout或者LinearLayout。混用两套布局系统的约束属性是最容易产生说不清哪里不对的界面问题。8. 从能跑到能交付签名、打包和后续可扩展的方向8.1 生成签名密钥与打包 APK/AABDebug 版本能跑不代表能交付。正式交付要给应用签名流程是Build → Generate Signed Bundle / APK。选 APK 是直接给安装包选 AAB 是给应用商店用的格式部分市场支持。第一步是创建 keystore 文件。这个文件包含了你的密钥和证书信息丢了就再也没法给同一个包名发布更新所以务必备份而且不要提交到 Git 仓库。创建时需要填 key alias、密码、有效期一般 25 年以上以及证书里的组织信息。第二步选择签名版本。V1JAR 签名是兼容老版本用的V2APK Signature Scheme v2是 Android 7.0 引入的校验更快更安全现代项目两个都勾上就行。签名之后建议用命令行验一下apksigner verify --verbose app-release.apk输出里会列出验证通过的签名方案以及证书的 SHA-256 指纹。这个指纹在很多第三方服务比如推送、地图里都要填所以生成之后一定要记下来。8.2 上架前该自查的几项别等被打回第一项是targetSdk。各大应用市场对targetSdk都有最低要求而且逐年提高上架前一定去查该市场当年的规则。第二项是隐私合规应用有没有在用户同意前就收集设备信息、有没有明文列出用到的权限、有没有提供隐私政策链接。第三项是权限最小化申请了定位权限就一定要在界面上说明为什么用否则审核时会被质疑。还有一件容易被忽略的事应用图标。现在推荐用自适应图标adaptive icon在res/mipmap-anydpi-v26/下用ic_launcher.xml配前景和背景两层。如果只放一张静态 PNG在部分启动器上会被裁成圆形或方形显示效果很怪。跟动态图标相关的还有主题色适配系统在开启主题图标功能时会把图标转成单色这属于进阶级内容第一个项目不用管但知道自己后面要学什么心里会踏实。8.3 往下可以练手的三条线第一条线是文件分享。你用相机拍张照想分享出去或者把应用生成的日志导出都会碰到FileProvider。它的核心是在 Manifest 里声明一个 providerandroid:authorities一般写成包名.fileprovider然后在res/xml/file_paths.xml里定义哪些目录可以共享。之后用FileProvider.getUriForFile()拿到一个content://开头的 URI配合Intent.ACTION_SEND发给其他应用。这条线能让你彻底搞懂安卓的权限和 URI 体系。第二条线是列表与网络。从写死的数据列表到用 Retrofit 拉接口再到用 RecyclerView 展示这是绝大多数应用的核心骨架。中间会顺带学会协程、状态管理和加载状态处理。第三条线是剪贴板与系统交互。用ClipboardManager读写剪贴板、监听电量变化、响应返回手势这些小功能能让你体会到应用和系统之间是怎么对话的。抄一段文本到剪贴板再粘出来是你验证自己理解是否到位的最快方式。我个人的体会是第一个 Android 项目最大的价值不是那个界面有多好看而是它让你亲手趟过了一遍环境配置 → 构建 → 部署 → 调试的完整闭环。后面你遇到的所有问题本质上都是这个闭环里某一环的变体Sync 慢是依赖解析环模拟器起不来是运行环境环闪退是代码环。把这个闭环里每一环的工具和排查手法摸熟比背多少 API 都有用。我自己到现在保留的习惯是每建一个新项目第一件事就是跑一次./gradlew -version和adb devices两个命令十秒钟能提前发现八成环境问题。
返回列表