为了推动安卓系统运行效率更高的64位,谷歌商店要求开发者2019年8月开始新应用必须提交64位的版本,而已经上架的Unity 5.6或更早版本引擎制作的游戏除外,他们可以只提供32位版本直到2021年8月,到时间点后需提供应用的64位版本。 本身项目也在走海外市场,现在项目用的Unity版本是5.6的,所以最近把项目Untiy版本升级,把一些遇到的问题在这里记录下供参考。
首先先了解什么是安卓64位,这是通过安卓设备的CPU类型来区分的,通常有以下几种类型,更详细的可以看下该博主的文章
- arm64-v8a: 第8代、64位ARM处理器,未来趋势
- armeabi-v7a: 第7代及以上的 ARM 处理器,也是目前主流的版本
- armeabi: 第5代、第6代的ARM处理器,早期的手机用的比较多
- x86/x86_64: 平板、模拟器用得比较多
总的来说ARM 64位架构拥有很多优点:更强的安全性、更好的性能、更大的可寻址内存、更高的数字精度以及更丰富的指令集,从开发者的角度来说迁移到64位Android是必然要的。如何查看自己安卓机CPU类型,可以在AS里输入 adb shell getprop ro.product.cpu.abi 来查看:
因为项目一些插件以及稳定性的原因,升级选择了Unity 2017.4.30f1 LTS版本。看下下面编辑器的一些设置选项,可以看出Mono是不支持ARM64的,所以要支持AMR64我们打包的时候要设置成IL2CPP。
那Mono跟IL2CPP到底是什么?我们知道Unity引擎是支持多平台,但是我们开发时用的c#语言本身是不具有跨平台能力的只能在Windows运行,就是因为Mono和IL2CPP才使得我们用Unity开发的游戏才可以发布到不同平台,这两者分别是什么做到的,原理上有啥区别?
- Mono是使用Mono VM作为运行时库,我们编写的c#被Mono编译器编译成中间语言IL,运行时IL被加载到Mono VM运行时库,由VM动态的将IL编译成汇编代码然后再执行,所以用Mono运行时是属于JIT(Just In Time)编译。
- IL2CPP同样是先将c#编译成中间语言IL,不过不同于Mono的是在转为IL后,IL2CPP又将IL重新变回C++代码,然后再由各个平台的C++编译器直接编译成能执行的汇编代码,所以用IL2CPP是属于AOT(Ahead Of Time)编译。
通过上面两者对比可以看出两者的区别,因为一些平台包括IOS,微软的Xbox等为了系统安全是不允许JIT的,所以只能选择使用IL2CPP,它的优点就是因为最终使用的是CPP,所以执行的效率相对来说更快,而且通过各个平台C++编译器对我们的代码编译时的优化,我们的程序尺寸相对也会的缩小。
这次升级Unity版本除了常规的第三方插件检查是否可继续使用,Unity API变化修改之外,遇到的主要问题有以下几个:
- 首先是项目使用的是Unity + 腾讯的xLua进行开发,所以要游戏支持Android64,对应的xlua也要升级最新版本以支持Android64升级最新xLua 2.1.14版本还有一点需要注意的是lua的协程API改变,所以客户端lua脚本有用到协程有也要稍微改下,具体最新使用写法可参考GitHub 同样如果你项目是使用 Unity + tolua开发的,也要对应的升级tolua
- 如果项目有使用c++封装底层库,那也要修改 Application.mk 文件配置 APP_ABI := armeabi-v7a x86 arm64-v8a 生成对应的安卓64位 .so 文件
- 在导出AS工程的时候出现错误,错误大概意思是c#脚本未定义这两个接口原来是因为之前为了解决IOS IPV6的问题,通过定义IOS原生外部接口去处理的时候未加平台宏标识,导致打包安卓时编译出错,解决之后如下:
- 使用IL2CPP打安卓包的时候要求配置NDK r13b版本的安装路径
- 修改AS项目级 build.gradle 配置文件支持64位
ndk {
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a'
}