首页 存档 技术 查看内容

Android 自己动手生成 Apk 了解Apk生成的种种细节

2018-3-30 13:00 |来自: 互联网 618 0

摘要: 每日推荐 相册和视频app是最常见的app之一,任何一个安卓设备上都能看到。是否好奇过它们是如何实现的呢?LeafPic是你可以尝试和学习的最佳开源相册程序之一。 它非常简单,容易理解,适合任何一个初级开发者。从 ...

每日推荐




相册和视频app是最常见的app之一,任何一个安卓设备上都能看到。是否好奇过它们是如何实现的呢?LeafPic是你可以尝试和学习的最佳开源相册程序之一。

它非常简单,容易理解,适合任何一个初级开发者。从这个app中我发现的最好的东西就是它实现动态主题的方式。这可是许多开发者费劲千辛万苦想要做好的东西。


https://github.com/HoraApps/LeafPic


介绍来自泡网:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0214/7114.html


本文作者


本文由ChuckChenLw投稿。

ChuckChenLw的博客地址:

http://blog.csdn.net/chenkai19920410


本文仅做学习使用,比较简单,没有实际项目复杂。


掌握Apk生成的过程,对于我们是非常重要的。而该过程平时都是由IDE自动帮我们完成的。IDE可以给我们带来很大的便利,但是也是一把双刃剑,有时候会让我们忽视一些重要的实现步骤。


所以我们在使用IDE自动编译打包Apk时,也应该知道Apk是怎么一步步由我们项目中的Java文件,资源文件等变成我们所熟知的Apk的。


不管使用什么IDE,Android打包生成Apk主要都是由以下几步完成:


  1. 根据资源文件和AndroidManifest.xml生成R.java文件

  2. 处理aidl,生成对应的java文件,如果没有aidl,则跳过

  3. 编译工程源码(主项目,库)src目录下所有的源码,同时上边生成的R.java和aidl生成的java文件也会被编译生成相应的class文件

  4. 将第3步生成的class文件打包生成.dex文件

  5. 将资源文件打包,生成初始的apk

  6. 将第4步生成的.dex文件加入到apk中生成未签名的包

  7. apk签名


以上即为主要的步骤。盗用一张官方经典的打包流程图


 


如果看懂了这张图,那么基本上就算理解了Apk的打包过程。这里需要用到好几个sdk提供的工具,为了方便可以将sdk/build-tools路径添加到环境变量中。


注意以下操作认为你已经编写了一个简单的项目。


为了能够清楚的看到每一步我们生成了结果,可以在项目app/src/main下建几个目录:

$ mkdir -p app/src/main/{gen,build,out}

接下来我们就先看第一步生成R.java文件。


1

生成R.java


R.java对于Android开发同学,肯定非常熟悉,它是一个非常重要的一个类,并且它是自动生成的,主要是包含了res目录下所有资源的ID,我们可以在程序中通过它来获取资源ID,然后通过Android Api来获取具体的资源。

TextView tv = (TextView) findViewById(R.id.tv_text);
tv.setText(R.string.app_name);


R.java是由SDK中提供的aapt(sdk/build-tools/ 中对应的版本下,本文使用的25.0.0,那么具体的路径就是sdk/build-tools/25.0.0)工具生成的。


aapt是非常重要的工具,它不仅可以生成R.java,还能将res下除assets目录外其他的目录下普通的xml文件编译成二进制xml文件,并将这些文件打包成初始包。


如果了解过插件化,相比都知道插件化有一个非常重要的问题就是如何保证宿主程序和插件程序的资源ID不会冲突,其中有一种思路就是通过修改aapt源码来修改资源ID的PP段来保证资源ID不冲突。


具体可以参考插件化开源项目ACDD

(https://github.com/bunnyblue/ACDD)


或者携程的DynamicAPK

(https://github.com/CtripMobile/DynamicAPK)。


关于aapt源码分析可以参考罗升阳老师的文章

http://blog.csdn.net/luoshengyang/article/details/8744683。


这里只讲解使用aapt工具生成R.java。


在Android Studio中切换到terminal(如果使用终端也是可以的,可以将当前路径切换到实验项目的根路径下)中。


输入以下命令:


参数的含义如下:

  • -f : #如果编译出来的文件已经存在,强制覆盖

  • -M : AndroidManifest.xml #AndroidManifest.xml 的路径

  • -I : xx/android.jar #某个版本平台的android.jar 的路径,具体是在你放sdk目录的sdk/platforms/android-XX/android.jar

  • -S : res/ #资源文件res 文件夹路径

  • -J :gen/ #生成 R.java 的输出目录

  • -m : #使得生成的包的目录放在 -J 参数指定的目录


如果提示没有aapt命令,请检查一下aapt环境变量,或者直接通过绝对路径引用。


如果没有问题,那么在gen文件下会生成相应的R.java文件。

      
     
关于R.java在合并资源和掌握Android资源管理非常重要,应该好好的掌握它的结构。可以自行参考上边推荐的文档,这里不做详细介绍。我们接着看一下aidl的编译。


2
编译aidl文件

  

我们在使用aidl时一般是先创建一个**Inte**ce.aidl文件,然后IDE会自动的帮我们生成一个**Inte**ce.java文件,其实IDE也是通过sdk提供的aidl工具实现的。


为了方便演示,我在main目录下创建一个aidl文件夹,里边新建一个IMyAidlInte**ce.aidl文件。


然后就可以使用aidl工具来编译了,该工具同aapt路径一样。使用如下命令进行编译:

 $aidl -Iapp/src app/src/main/aidl/com/chuck/manualapk/aidl/IMyAidlInte**ce.aidl 

注意这里的-I和”app/src”中间没有空格,否则无法成功运行,[无奈],


可以参考How do I use AIDL tool from command line using SDK sample code?

http://stackoverflow.com/questions/2179453/how-do-i-use-aidl-tool-from-command-line-using-sdk-sample-code


成功后会在.aidl目录下生成java文件,当然你也可以通过-o指定java文件的生成路径。  
      


如果没有aidl文件可以跳过这一步。


3
javac 编译所有java文件

  

这一步其实就是使用jdk的javac将项目中所有的java文件编译成class文件。

javac 
  -source 1.7 
  -target 1.7 
  -encoding UTF-8 
  -bootclasspath ~/Library/Sdk/platforms/android-25/android.jar 
  -d app/src/main/build/ 
  app/src/main/java/com/chuck/manualapk/*.java app/src/main/gen/com/chuck/manualapk/*.java 
  app/src/main/aidl/com/chuck/manualapk/aidl/*.java


请将所有的换行认为是“空格”


-source 1.7 -target 1.7:指定编译的jdk版本,如果不指定的话,会报错。
-encoding :编码方式,这里设置UTF-8
-bootclasspath :引导类文件的路径,这里需要使用到android.jar中的Android API。
-d :生成的class文件存放路径


接下来需要把生成的class文件打包生成dex文件。


4
打包生成.dex文件

  

dex文件是Android虚拟机可运行文件,可以使用dx工具生成。


具体如下:

$dx --dex --output=app/src/main/build/classes.dex app/src/main/build/


dx工具会将上一步app/src/main/build/中生成的class文件全部打包,得到classes.dex,apk包中包含的classes.dex就是这样生成的,当然实际项目可能类会很多,但是过程是一样的。

        


有了classes.dex,开始要打包apk了,我们先将资源文件做成初始包


5
打包资源文件

  

apk包中的资源文件都是经过编译过的,是二进制文件。我们还是使用aapt工具:


$ aapt package -f 
  -M app/src/main/AndroidManifest.xml 
  -I ~/Library/Sdk/platforms/android-25/android.jar
  -S app/src/main/res/ 
  -F app/src/main/out/res.apk


将AndroidManifest.xml与res目录除了assets目录以为的文件进行编译,生成resource.arsc和若干二进制的xml文件。


资源ID和资源文件的对应关系都是在resource.arsc中的。这些文件都会被打包到res.apk中。

      
      
如图,将res.apk后缀改为.zip然后解压,可以得到刚刚提到的文件。

接下来的任务就是将classes.dex文件打进apk中,这样就可以得到没有签名的apk。


6
将.dex将包到apk

  

以前可以直接使用apkbuilder工具直接打包,但是目前sdk将该工具移除了,不过没有关系,我们可以自己生成一个,也可以直接使用apkbuilder的实现类,该类是sdk/tools/lib/sdklib.jar文件中的

com.android.sdklib.build.ApkBuilderMain。


为了方便我们可以生成一个apkbuilder,将当前目录切换到sdk的tools目录下,执行以下命令:


$ cat android | sed -e 's/com.android.sdkmanager.Main/com.android.sdklib.build.ApkBuilderMain/g'
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部