参考文章 https://wetest.qq.com/lab/view/324.html
分成以下四个部分:
Unity工程中的Plugin/Android文件夹
Android打包工具
如何把上述个文件夹打包到APK文件的
APK中的assets\bin\Data文件夹
Unity工程中的Plugin/Android文件夹
先介绍一下Unity打包apk的重要文件夹Plugin/Android,下面是某个项目中的Plugin/Android文件夹根目录:
1. 红框部分是一个Android工程的常规目录:libs、res、assets文件夹以及AndroidManifest.xml文件
2. GCloudVoice 和 resProject 文件夹是我们引用的第三方库,他们也会被打包到APK中,文件夹里面的目录里结构也是Android工程的一些常规目录:
特别注意 project.properties文件一般只有在库项目里面能看得到,里面的内容极少,一般就只有一句话android.library=true。有了这句话里面的东西才会被打包进apk中。否则就不会认为这个文件夹里面是个Android的库项目,整个文件夹都将被忽略,不要忘了写。
3. cos.aar 和 TakePhoto.aar 也是两个库文件(可以查看文章Android中的AAR包),解压可以查看内容,是一个Android库工程。
4. 那两个AndroidMannifest_xxxx.xml(AndroidMannifest-CellphoneCollector.xml 和 AndroidMannifest-ImagePickerRes.xml) 不知道干啥的,还没搞明白,估计没用?
5. UnityWebView.jar jar包 直接放在了外面jar包,会跟根目录下libs文件夹下的jar包一起打包到classes.dex里面的(下面会介绍classes.dex)。除了Plugin/Android文件夹下的jar包外,Unity打包的时候还会引入自己的Android的jar包——classes.jar,里面包含了Unity需要的库类,关键类UnityPlayerActivity就是Android程序的默认入口类。classes.jar的位置在:Windows:Unity\Editor\Data 以及 Mac:/Applications/Unity 的以下三个文件夹中均有一份:
C:\unity5\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes
C:\unity5\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Development\Classes
C:\unity5\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes
Android打包工具
Android提供了一个叫做aapt的工具(可以查看文章Android打包工具aapt),Unity构建apk的时候需要androidsdk和jdk路径的(可以查看文章打包android的设置),而aapt就是在androidsdk目录下(我的C:\Android\android-sdk\build-tools\28.0.3),这个工具完成了上述大部分的对资源文件处理的工作。
除了aapt,还有其他的Android提供的工具链(Android Build Tools),都在build-tools目录下,Unity通过对Android提供的工具链的一系列调用从而完成打包APK的操作。可以当作Unity写了个bat/bash脚本,这个脚本按照顺序调用Android提供的工具来完成打包APK(常见的Android IDE里面,这样的“bat/bash脚本”往往是一个完整的构建系统,比如Eclipse 用的Ant,Android Studio IDE用的gradle)。
如何把上述个文件夹打包到APK文件的
Unity打包apk的注意过程把libs、res、assets文件夹以及AndroidManifest.xml文件这些内容以固定的方式组织起来压缩到APK文件里面(包括第三方库中的这几个文件夹)
可以先了解下apk下都是什么目录结构(查看文章APK直接解压看内容 和 APK的反编译方法)
1.libs文件夹 ————》 .jar打包成classes.dex,.so文件不打包。
libs文件夹里面有很多.jar文件,以及三个文件夹armeabi,armeabi-v7a,x86:
*.jar文件——.jar是Java编译器把.java代码编译后的文件。这里用的jar包一般是由其他Android的IDE生成完成后再拷贝过来的。Android在打包的时候会把项目里面的所有jar文件进行一次合并、压缩、重新编译变成classes.dex文件被放在APK根目录下。当应用被执行的时候Android系统内的Java虚拟机(Dalvik或者Art),会去解读classes.dex里面的字节码并且执行。总之就是把众多jar包编译成classes.dex文件。
armeabi-v7a、armeabi、x86等几个固定的文件夹——里面存放的同样名字的so文件,是针对不同的CPU架构生成的*.so文件。so是动态库文件,直接放在APK根目录下的lib目录下的对应的文件夹中。(查看文章Android中的so文件)
2.assets文件夹————》原封不动的被拷贝到APK根目录下的assets文件夹
这些文件里面的内容不会在R文件注册。这个文件夹有几个特性。
√ 里面的文件基本不会被Android的打包工具修改,应用里面要用的时候可以读出来。
√ 打出包以后,这个文件夹是只读的,不能修改。
√ 读取这个文件夹里面的内容的时候要通过特定的Android API来读取,参考getAssets()。
√ 基于上述两点,在Unity中,要读取这部分内容要通过WWW来进行加载。
除此之外,最终apk中的assets文件夹中还将包括StreamingAssets目录下的文件(项目打AB包出来的时候最终存放AssetBundle包路径就是:Assets/StreamingAssets,所以这些ab包也是直接放到了apk的assets目录下。)
该目录用于存放项目相关的资源文件,这个目录和res包含的xml文件差不多,也是应用中引用到的一些外部资源。但主要区别在于这些资源是以原始格式保存,且只能用编程方式读取。例如文本文件,视频文件,MP3音频等媒体文件。
3.res文件夹————》xml文件转化为二进制格式,其他一般不处理;生成资源映射文件resources.arsc;目录结构不变存放APK根目录下的res文件夹中
存放的是xml文件以及一些图片素材文件。可以先了解一下文章Android工程的资源管理。
1. xml文件在被打包的时候会被转换成一种读取效率更高的一种特殊格式(也是二进制的格式,所以直接解压出来看是乱码了),命名的时候还是以xml为结尾被放到APK包里面的res文件夹下,其目录结构会跟打包之前的目录结构相对应。xml文件一般来说有以下几种:
layout文件夹——布局文件,文件里描述的一般都是原生界面的布局信息。(Unity游戏的显示是直接通过GL渲染指令来完成的,一般不会涉及到这些文件。但是在接sdk的时候会用到。)文件的命名规范全部小写,采用下划线命名,一般按照组件名_功能名_属性名方式,具备较高的可读性。如:activity_login,fragment_constact_child(某个ConstactFragment类中的child视图)。这样规范命名的话,在Activity的onCreate中使用R.layout.的时候就只需筛选activity开头的xml文件;在Fragment的onCreateView中使用R.layout.的时候就只需筛选fragment开头的xml文件,
values文件夹——字符串定义文件,key-value对,定义一些字符串,方便程序做国际化还有本地化用(XX_strings.xml)。还有一些其他的颜色(XX_color.xml)、度量(XX_dimens.xml)等,还有其他xml会引用到的字符串,一般常见的是app的名称。
动画文件,一般定义的是Android原生界面元素的动画,对于Unity游戏,我们一般也不会涉及他。
其他目录下的xml文件,如上面的xml 和 color
2.建立res文件夹下的资源文件跟代码静态引用到的资源文件的映射,放到APK根目录的resources.arsc文件。所以在打包后的比如xml中的资源路径相关的配置由原来的可读路径都变成了id值。
3.图片资源——在打包过程中会被放到APK的对应文件夹内的对应目录
drawable为开头的文件夹——图片资源,用于存储.png、.9.png、.jpg等图片资源(.9.png是Android特有的图片格式,可以根据情况进行拉伸,达到不变形的效果),后缀一般会根据手机的像素密度来来进行区分,这样我们可以往这些文件夹内放入对应像素密度的图片资源。后缀为ldpi的drawable文件夹里面的图片的尺寸一般来说会是整个系列里面最小的,因为这个文件夹的内容会被放到像素密度最低的那些手机上运行。而一般1080p或者2k甚至4k的手机在读取图片的时候会从后缀为xxxxhdpi的文件夹里面去读,这样才可以保证应用内的图像清晰。
4.其他资源——直接存放到对应目录下
raw文件夹——用于存放应用程序所用到的声音比如wav等资源。raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;而如果是放到assets文件夹下,则不会被映射到R.java中,访问的时候需要AssetManager类。
以上的资源由于有资源映射,所以最终只有在程序中用到的资源文件才会被打包进最终的apk中。
4.AndroidManifest.xml————》各个文件夹或者包中的AndroidManifest.xml合并成一个存放APK根目录下
在Android系统安装以及启动应用的时候,会首先来读取AndroidManifest.xml这个文件的内容,分析出这个应用分别使用了那些基本的元素,以及应该从classes.dex文件内读取哪一段代码来使用,应该往桌面上放哪个图标,这个应用能不能被拿来debug等等。
打包工具在处理Unity项目里面的AndroidManifest文件时会将所有AndroidManifest文件的内容合并到一起,也就是说主项目引用到的库项目里面如果也有AndroidManifest文件,都会被合并到一起。这样就不需要手动复制粘贴。需要说明的是,这份文件在打包Android程序的时候是必不可少的,但是在Unity打包的时候,他会先检查Plugins目录下有没有这份文件,如果没有就会用一个自带的AndroidManifest来代替。此外,Unity还会自动检查项目中AndroidManifest里面的某些信息是不是默认值,如果是的话,会拿Unity项目中的值来进行替换。例如,游戏的App名称以及图标等。
如果在Plugins/Android,不存在AndroidManifest文件,会使用Unity默认的AndroidManifest文件。默认的AndroidManifest文件目录在:Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk
关于AndroidManifest.xml具体内容可以查看这篇文章。
APK中的assets\bin\Data文件夹
最终打出来apk中的assets文件夹的内容除了之前说的Plugin/Android/下的assets,以及Unity工程下StreamingAssets外,还有一个bin文件夹,下面看看内容:
bin\Data这里存放的是Unity的代码资源,场景资源,和比如Resource文件夹下面的资源。下面是一个简单的demo工程,只包含一个场景,就是level0,Assembly-CSharp.dll库就是C#代码逻辑。(这里面的dll还有待仔细看,还不是很懂都是干嘛的)
在一些大的工程中打包成apk后,assets\bin\Data目录下看到大量的文件名很长而且无意义的文件,这些就是Unity中的Resources目录下的资源。当打包成APK发布的时候,Unity把这些资源全都打散了,然后把资源的文件名都变成了上图中显示的文件Hash值: