专栏首页程序亦非猿【连载】聊聊 APK(四) —— 脱离 AS 手工创造 APK 文件

【连载】聊聊 APK(四) —— 脱离 AS 手工创造 APK 文件

想进大厂,就关注「 程序亦非猿 」 时不时 8:38 推送优质文章,觉得有用,置顶加星标

船长导读:「聊聊 APK」系列共 4 篇,本篇是最后一篇啦。

【连载】聊聊 APK——直接运行 Dex文件的黑魔法【连载】聊聊 APK(二)——Dex 热修复与 Classpath【连载】聊聊 APK(三) —— Android 资源编译的秘密

终于来到了这一个章节,其实这个是之前一个小的“梦想”,但是真正到实现它的时候,感觉还蛮简单的,但是做完一件事总会有一些成就感,所以,我们今天就来完成这个事情,如果你还不知道 Dex 文件和资源文件怎么生成,请参考前面几篇文章。

创建工程

首先,我们构造工程,昨天的工程如果还在的话就很简单,我们写一个MainActivity.java,如下

请无视这个波浪线,因为我没设置 classpath,这里的代码纯靠记忆手打=。=,导入包想了半天。我们就新加了一个MainActivity.java,然后新建了一个build目录,供一会生成classes文件用。同时,为了MainActivity能使用,我们需要在AndroidManifest.xml中对MainActivity进行声明,然后要为 App 提供一个 Icon。因此,经过改造后,我们目录如下:

重新编译资源

我们因为新加了资源,修改了 AndroidManifest.xml,这时候需要重新调用aapt2 compileaapt2 link,但是之前我们编译过activity_main.xml,所以不需要编译,我们只需要编译drawable/ic_launcher就行了,命令如下:

aapt2 compile src/main/res/drawable/ic_launcher.png -o compiled

compiled 目录下,就会出现drawable_ic_launcher.png.flat这个文件了,这时候重新调用 link。

aapt2 link -o resources.ap_ \
-I $ANDROID_HOME/platforms/android-28/android.jar \
compiled/layout_activity_main.xml.flat \
compiled/drawable_ic_launcher.png.flat \
--java src/main/java \
--manifest src/main/AndroidManifest.xml

开始编译

好了,这样我们就开始使用javac编译了。首先我们要知道,java工具链中是没有 android sdk 的,所以我们需要在编译的时候导入 classpath。

文件准备好了之后,编译命令如下:

javac -d build -cp $ANDROID_HOME/platforms/android-28/android.jar src/main/java/**/*.java

其中-d表示输出目录,-cp表示 classpath,后面跟着输入文件,src/main/java 目录下面所有的 java 文件。我们打开 build 目录:

dx 化

执行命令:

dx --dex --output=classes.dex build

我们在当前目录下就得到了一个 classes.dex 文件。

生成 APK 之前的检查

接下来其实我们代码上的准备工作基本做完了,在进行最后几步之前,我们再来温习一下一个正常 apk 的结构

  1. classes.dex
  2. 资源文件
  3. resources.arsc
  4. 签名摘要
  5. 可选的 assets 等

那么我们还剩下签名没做,这个暂时可以等一下,我们先把前面3个合起来,这个很简单,首先对我们利用 aapt 构造出来的ap_文件,复制一份,重命名成 apk 文件

cp resources.ap_ app-debug.apk

拿到了一个 apk(其实是zip文件),然后把 classes.dex 加进去。

zip -ur app-debug.apk classes.dex

输出

1 adding: classes.dex (deflated 47%)

其实现在我们的 app-debug-unsigned.apk 是做完了。可以安装试一下,但是输出如下:

1adb: failed to install app-debug.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed to collect certificates from /data/app/vmdl110235550.tmp/base.apk: Attempt to get length of null array]

签名 apk

啊噢,没有证书信息,我们其实可以用android debug key进行签名,这样最简单,我们可以看一下怎么签名呢,我们要用到apksigner这个工具,首先输出下帮助

apksigner --help

得到如下信息:

USAGE: apksigner <command> [options]
       apksigner --version
       apksigner --help

EXAMPLE:
       apksigner sign --ks release.jks app.apk
       apksigner verify --verbose app.apk

apksigner is a tool for signing Android APK files and for checking whether
signatures of APK files will verify on Android devices.


        COMMANDS

sign                  Sign the provided APK

verify                Check whether the provided APK is expected to verify on
                      Android

version               Show this tool's version number and exit

help                  Show this usage page and exit

它可以进行签名,也可以进行验证。OK,这时候使用 linux/macOS 的同学就很简单了,android 的 debug.keystore 默认在 ~/.android/debug.keystore 下,密码是 android。那么我们调用如下命令:

apksigner sign -ks ~/.android/debug.keystore app-debug-unsigned.apk

这时候会让我们输入密码,我们输入android即可。

Keystore password for signer #1:

这时候,你的 apk 名字还是app-debug-unsigned.apk,其实已经签名了,我们可以检查一下:

apksigner verify --verbose app-debug-unsigned.apk

看到如下输出:

Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Number of signers: 1

好了,签名成功。

再次安装 APK

到了激动人心的时候了,这时候我们调用安装,安装成功!

再看手机桌面上,有我们的图标了:

大胆点击它!

好了,至此聊聊 APK 系列完结了,感谢 Gemini 老师的付出。想看更多他的博客请访问:

https://geminiwen.com/

本文分享自微信公众号 - 程序亦非猿(chengxuyifeiyuan)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 喝杯咖啡了解下zookeeper的基本操作

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为...

    技术从心
  • Java开发环境系列:消息队列ActiveMQ的安装与配置(linux/windows)

    1)以ActiveMQ 5.15.2 Release为例:在下载页面的Change Log处

    架构师小跟班
  • Java开发环境系列:版本控制Git&GitHub实用教程

    网上的教程,大多数都是通过命令来实现远程仓库的克隆、修改、提交等操作,但是真正在公司里,大多数时候都是将Git集成在IDE(如Idea、Eclipse),或使用...

    架构师小跟班
  • Python基础 | 一个被忽视的神器tqdm(续)

    上一次为介绍了神器tqdm,主要用来解决及时方便查看任务执行进度,使用的是一个for循环结构。但是现实开发中往往会出现多个循环结构。

    算法与编程之美
  • Python将PDF转成图片—PyMuPDF和pdf2image

    前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。

    软测小生
  • Spring消息监听器无法注入bean的问题

    在activemq的监听器中,通过注解@Autowired或@Resource注入bean时,获取到的bean为null。调用该bean的方法时会报空指针异常。

    架构师小跟班
  • Python将PDF转成图片PNG和JPG

    前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。

    软测小生
  • Scala 学习笔记之数组

    对于那种长度按需要变化的数组,Java有 ArrayList.Scala中等效数据结构为 ArrayBuffer.

    smartsi
  • Scala 学习笔记之文件操作

    读取文件,可以使用 scala.io.Source 对象的 fromFile 方法.如果读取所有行可以使用 getLines 方法:

    smartsi
  • Android加载Base64编码格式的图片

    Base64是传输字节码的编码,Android开发过程中,图片的加载多数是请求URL路径或者加载本地的图片,当然也有加载服务器用Base64编码过的图片,比如图...

    SoullessCoder

扫码关注云+社区

领取腾讯云代金券