U
章 05导出到手机7 课 — 点击打开
07 / 07 · 26 分钟
导出到手机★ 练习

期末练习:发布游戏

到目前为止的项目▸ Arena.unity

everything from tab 01–05 · signed release build on a real phone

练习3–5 小时

课程的最后一道练习:把 Arena —— 波次、敌人、触控操作全都算上 —— 以签好名的 release build 装到一台真手机上,连续五分钟稳住帧率(手机扛得住就 60 FPS,任何时候都不低于 30),杀掉 App 重开还记得你的进度。

复用的东西

Everything from tabs 01–04tab 01–04 的全部内容Android build setupAndroid 构建设置Player SettingsURP mobile qualityURP 移动端画质Save / load JSONJSON 存档读写adb logcat查看真机日志Keystore + .aabkeystore 签名与打包
动态图解

不是编辑器里的截图 —— 而是手机上那个别人也能装的 App 图标。

第 1 部分 —— 清理场景

  • 打开 Arena.unity —— 这是你从第 01 部分一路养大的那个场景 —— 检查 GameDirector 还留着那些出生点。

  • 把测试时留下的东西删干净:多余的相机、乱放的灯、你挪到一边的方块。

  • 场景里必须正好只有一个 AudioListener、一个 EventSystem 和一个 CinemachineBrain。

  • 确认第 03 部分的触屏 Canvas 还在,而且游戏跑在手机上时它会自动开启。

第 2 部分 —— 配置 build

the settings you must change
Project Settings → Player
  Company Name            your studio               // not DefaultCompany
  Product Name            Arena
  Package Name            com.yourstudio.miniarena  // permanent
  Version / Bundle Code   1.0.0 / 1
  Default Orientation     Landscape Left
  Scripting Backend       IL2CPP
  Target Architectures    ARMv7 + ARM64             // ARM64 is mandatory
  Minimum API Level       24
  Managed Stripping       Medium
  Graphics APIs           Vulkan, OpenGLES3         // remove OpenGLES2

URP Asset (mobile)
  Shadow Max Distance     40
  Cascade Count           1
  HDR                     off
  MSAA                    disabled
  Render Scale            0.85

Assets/link.xml
  preserve SaveData       // or stripping deletes it
MobileBoot.cs — must exist in the first scene
void Awake()
{
    Application.targetFrameRate = 60;
    QualitySettings.vSyncCount = 0;
    Screen.sleepTimeout = SleepTimeout.NeverSleep;
    DontDestroyOnLoad(gameObject);
}

第 3 部分 —— 第一次 build 一定有问题

这在你预料之中。先出一个 Development Build,装到手机上,边玩边读 adb logcat。只在真机上才出现的 bug,才是这道练习真正的重点。

terminal
adb devices                          # is the phone actually connected?
adb logcat -c && adb logcat -s Unity # clear, then watch only Unity

# after the build
adb install -r Builds/arena-dev.apk
adb shell monkey -p com.yourstudio.miniarena 1

几乎人人都会踩的五个坑

  • 材质变粉色 —— shader 没转成 URP。转换材质后重新 build。

  • 按钮点了没反应 —— 要么缺 EventSystem,要么有个铺满全屏的透明 Image 把 raycast 全吃了。

  • 存档是空的 —— IL2CPP stripping 把 SaveData 裁掉了。把它加进 link.xml。

  • 真机 20 FPS,编辑器 200 FPS —— 是实时阴影和后处理。检查一下 URP asset。

  • UI 被刘海切掉 —— 触屏 Canvas 上少了 SafeAreaFitter。

第 4 部分 —— 正式版 build

  • 创建 keystore,存到项目外面,备份两份。弄丢了你可能就没法再更新这个 App。

  • 在提交任何东西之前,先把 *.keystore 加进 .gitignore。

  • 取消勾选 Development Build,勾上 Build App Bundle,然后 build 出 .aab。

  • 另外留一个签好名的 .apk —— 你发给朋友装的就是它。

怎样算做完

  • ✓App 装在真手机上,从它自己的图标启动,而不是从 Unity。
  • ✓只用触屏就能打完完整一圈:移动、转向相机、放出全部三个技能、击杀一个敌人。
  • ✓在带刘海的手机上每个 UI 元素都在安全区内,而且锚点设得让平板也不会把布局撑坏。
  • ✓把 App 切到后台再强杀,重开后血量、位置和金币都还在。
  • ✓连续玩五分钟仍然不低于 30 FPS —— 量的是第 5 分钟,不是第 1 分钟。
  • ✓整局玩下来,adb logcat -s Unity 里一条 exception 都没有。
  • ✓有一个签好名的 .aab,是在没勾 Development Build 的情况下 build 出来的。
  • ✓别人把 .apk 装到他们自己手机上,跑起来了。

需要达到的数字

指标目标值原因
第 5 分钟的 FPS≥ 30手机发热会降频,只有第 5 分钟的数字才算数。
.aab 包体大小≤ 150 MB超过 150 MB,Google Play 就要额外配置分包下载。
冷启动到可操作的耗时≤ 5 s黑屏时间再长一点,玩家就会直接关掉 App。
内存占用≤ 600 MB超过这个数,3 GB 内存的手机一切后台就会杀掉你的 App。
logcat 里的异常0每帧一个 NullReference,是个悄无声息的帧率杀手。

想再多做点

加分项 1

把 .aab 以 internal test 上传到 Play Console,再从 Play Store 装到自己的手机上。

加分项 2

加一个设备档位判断,在内存低于 3 GB 的手机上降低 render scale 和阴影距离。

加分项 3

同一份工程再 build 一版 iOS,在档次相近的硬件上对比帧率。

加分项 4

加一个可开关的游戏内 FPS 和内存浮层,这样测试的人就能报给你真实数字。

整门课到这里就结束了

  • 你从“变量是什么”起步,最后做出一个跑在手机上的签名 build。整条流水线你已经走通了一遍。

  • 从这往后的功课是深度而不是广度:更好的动画、更聪明的敌人、真正的关卡设计、属于自己的美术风格。

  • 下一个该做的是这样一款游戏:一种玩法机制、五分钟内容,但你真的把它做完了。在这一行里,最稀有的技能就是把东西做完。