不自重者,取辱。不自长者,取祸。不自满者,受益。不自足者,博闻。
【工具】统计apk中指定package下的java方法数 进入全屏
line

在之前的文章“【工具】统计jar包和apk中的java方法数”中,给大家分享了两个统计工具,分别是统计jar包种的java方法数工具jarmethod,和统计apk文件中所有的java方法数工具apkmethod。但在项目中,我发现这个还不够,因为我还想要去统计每个package中的java方法数,当然,这个工具就比前面两个要复杂一点点了。

首先,我们可以利用之前提到的工具,可以很轻松从dex文件中统计出java方法数,所以,只要我们能想办法从apk文件中分离出需要统计的package,问题就迎刃而解了!借助 baksmalismali 两个工具,实现的思路就会变得清晰很多了,可以按照这个逻辑去实现:

1、解压apk包,得到classes.dex;这一步zip命令即可完成!

2、用baksmali分解classes.dex文件,得到和原工程目录结构一致的文件列表;这一步的命令示例:

# 将classes.dex分解到classes_dir目录下
java -jar baksmali-2.0.3.jar -o classes_dir/ classes.dex

3、用smali将需要统计方法数的package再转换为dex包,即可完成;这一步的命令示例:

# 将com.baidu.tieba.pb包转换为同名的dex文件
java -jar smali-2.0.3.jar classes_dir/com/baidu/tieba/pb -o com.baidu.tieba.pb.dex

4、利用之前文章中提到的方法,直接从dex文件中获得java方法数;这一步的命令示例:

# 统计com.baidu.tieba.pb.dex中的方法数
method=`dexdump -f com.baidu.tieba.pb.dex | grep method_ids_size`
echo $method

5、当然,上面命令得到的结果不是一个纯数字,而是类似这样的:

method_ids_size    : 2063

所以,为了让结果变得更干净,可以用很简单的shell脚本将数字提取出来:

# 替换掉method_ids_size关键字
method_num=${method_num//method_ids_size/}
# 替换掉冒号
method_num=${method_num//:/}
# 对结果进行trim处理,得到纯数字
method_num=`echo $method_num | sed -e 's/\(^ *\)//' -e 's/\( *$\)//'`

OK,几个核心的部分已经完成,接下来组装shell脚本即可,完整版的工具如下:pkgmethod.sh

#!/bin/bash
  
# 得到命令行的所有参数
tool_name="$0"
apk_path=$1
pkg_list=$2
  
# 检验参数的合法性
if [ x"$apk_path" == x ] || [ x"$pkg_list" == x ] ;then
    echo -e "\n\t用法:"
    echo -e "\tpkgmethod your_apk_path \"your_package_list\""
    echo -e "\n\t例:"
    echo -e "\tpkgmethod ../../tieba.apk \"com.baidu.tieba.frs com.baidu.tieba.pb\"\n"
    exit 1;
fi
  
# 得到工具的原始目录
prog=$tool_name
while [ -h "${prog}" ]; do
    newProg=`/bin/ls -ld "${prog}"`
    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
    if expr "x${newProg}" : 'x/' >/dev/null; then
        prog="${newProg}"
    else
        progdir=`dirname "${prog}"`
        prog="${progdir}/${newProg}"
    fi
done
  
# 这就是工具的目录了
tool_dir=`dirname "${prog}"`
  
# 以此得到两个jar文件的完整路径
baksmali_jarfile=$tool_dir/baksmali-2.0.3.jar
smali_jarfile=$tool_dir/smali-2.0.3.jar
  
# 下面要做的事情是:在当前目录下创建临时文件夹,将目标apk文件拷贝进来并解压
# 创建一个临时目录,来解压这个apk文件
rm -rf apk_temp
mkdir apk_temp
cp $1 apk_temp/
cd apk_temp
echo "创建临时目录成功..."
  
# 获得apk的名称
apk_name="$(basename *.apk)"
  
# 重命名为zip
mv $apk_name $apk.zip
  
# 解压apk,得到classes.dex包
unzip -x $APK_NAME.zip > /dev/null
echo "解压apk文件并提取dex文件成功..."
  
# 在当前目录下,就可以得到classes.dex文件了
# 接下来要做的事情就是:
# 1、使用baksmali将classes.dex中的class导出(smali文件)
java -jar $baksmali_jarfile -o classes_dir/ classes.dex
echo "反编译dex文件成功..."
echo -e "开始进行package下方法数量的统计...\n"
  
# 2、用smali对各个package进行转换:smali to dex
for pkg_item in $pkg_list ;do
    target_pkg_name=$pkg_item
    # 将.替换成/得到路径,比如:com.baidu.tieba.pb替换为com/baidu/tieba/pb
    target_pkg_path="classes_dir/${pkg_item//.//}"
  
    if [ -d "$target_pkg_path" ];then
        # 编译得到以包名命名的dex文件,如:com.baidu.tieba.pb.dex
        java -jar $smali_jarfile $target_pkg_path/ -o $target_pkg_name.dex
  
        # 从dex文件中统计方法数
        method_num=`dexdump -f $target_pkg_name.dex | grep method_ids_size`
        # 为了得到纯数字部分,咱们吧不相干的东西删掉
        method_num=${method_num//method_ids_size/}
        method_num=${method_num//:/}
        method_num=`echo $method_num | sed -e 's/\(^ *\)//' -e 's/\( *$\)//'`
        echo -e "  $target_pkg_name \t: $method_num"
    else
        echo -e "  $target_pkg_name \t: 包不存在"
    fi
done
  
# 删除临时目录,结束
# cd ../ && rm -rf apk_temp
echo -e "\n删除临时目录成功,方法数量统计结束!"

和之前的工具一样,chmod一下,然后建一个软链接到/usr/bin下,以后就可以直接通过pkgmethod命令在任意目录直接使用了,比如,我们来统计一下tieba.apk中com.baidu.tieba.frs、com.baidu.tieba.pb、以及protobuf几个目录下的java方法数量,命令就可以这样了:

# apk可以在任意目录,package也可以是单个、多个
pkgmethod tieba.apk "com.baidu.tieba.frs com.baidu.tieba.pb protobuf"

得到的结果是:


如果你的项目中也需要统计方法数,不妨把工具拿去试一试!



趣店(原趣分期)技术学院
重点关注技术架构、服务化、优秀工具、自动化平台、开发全流程一体化解决方案、新人培养、工程师进阶之道等方面
这里环境优雅、氛围年轻、主要是福利还多,还等什么?我们敞开技术的大门,欢迎各种工程师加入!

评论区域

line