1.背景

项目需要根据用户提交的apk地址,自动的获取apk的相关信息,比如包名称、版本信息、Icon图、binary xml and manifest xml file、sign等,因此就搜索和研究了一下,接下来就提供几种方式来解决这个问题。

2.可行性方案

  1. 解压后读取AndroidManifest.xml,根据xml信息获取
  2. 官方sdk中提供的工具aapt

3 apk-parser工具包

pom.xml文件中增加依赖配置

<dependencies>
    <dependency>
        <groupId>net.dongliu</groupId>
        <artifactId>apk-parser</artifactId>
        <version>2.6.10</version>
    </dependency>
</dependencies>

然后maven安装

public static void main(String[] args) {
        // Press Opt+Enter with your caret at the highlighted text to see how
        // IntelliJ IDEA suggests fixing it.

        String apkUrl = "./2.apk";
        try {
            ApkFile apkFile = new ApkFile(apkUrl);

            String manifestXml = apkFile.getManifestXml();
            // System.out.println(manifestXml);
            ApkMeta apkMeta = apkFile.getApkMeta();
            // 获取包name
            System.out.println(apkMeta.getPackageName());
            // 获取app名称
            System.out.println(apkMeta.getName());
            // 获取版本信息
            System.out.println(apkMeta.getVersionCode());
            System.out.println(apkMeta.getVersionName());

            // 获取全部icon
            apkFile.getAllIcons();
            // 能从iconFace.getData获取文件流
            for (IconFace iconFace : apkFile.getAllIcons()) {
                System.out.println(iconFace.getPath());
                saveIcon("/Downloads/", iconFace);
            }
        } catch (java.io.IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    public static void saveIcon(String savePath, IconFace iconFace) throws IOException {
        String iconPath = iconFace.getPath();
        String iconName = iconPath.substring(iconPath.lastIndexOf("/") + 1);
        File file = new File(savePath + iconName);
        if (!file.exists()) {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
        }
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(iconFace.getData());
        fos.close();
    }

com.xingye.app
星野
1350003
1.35.003
res/u3P.png
res/SDC.png
res/jyj.png
res/D21.png
res/CGK.png
res/EtS.png

4.aapt工具

#!/bin/bash

if [ ! -s "${1}" ];then
    echo "apk file is not exist";
    exit;
fi

cons=`aapt d badging $1 | grep -E "application-icon|application:" | sed -e 's/.*\(res\/\w\{1,\}\-\w\{1,\}\/\w\{1,\}\.png\).*/\1/' | uniq`;
# echo $icons;
for icon in $icons;do
    echo $icon;
done

echo "-----apk name----";
name=`aapt d badging $1 | grep -E "application:" | sed -e "s/.*label='\(\w*\)'.*/\1/"`;
echo $name;

echo "-----apk versionCode----";
#获取apk versionCode
versionCode=`aapt d badging $1 | grep -E "package:" | sed -e "s/.*versionCode='\(\w\{1,\}\)'.*/\1/"`;
echo $versionCode;

echo "-----apk versionName----";
#获取apk versionName
versionName=`aapt d badging $1 | grep -E "package:" | sed -e "s/.*versionName='\(\S\{1,\}\)'.*/\1/"`;
echo $versionName;

echo "-----icon xml-----------";
iconXml=`aapt dump badging $1 | grep -E "application-icon|icon" | grep -oP "icon='([^']+)'" | cut -d"'" -f2`
echo "-----get backgroud and foreground-----------";
pic=`aapt dump xmltree $1 $iconXml | grep -oP "@0x[0-9a-zA-Z]+" | cut -d'@' -f2`
echo $pic
code=`aapt dump xmltree $1 $iconXml | grep -oP "@0x[0-9a-zA-Z]+" | cut -d'@' -f2 | tr '\n' '|' | awk -F "|" '{print $2}'`
echo $code
anchor=`aapt dump --values resources $1 | grep -iC4 $code `
echo $anchor


IFS='|' read -r -a array <<< "$anchor"
for element in "${array[@]}"; do
if [[ "$element" == *.png* ]]; then
    echo `echo $element | cut -d' ' -f2`
fi
done

echo "-----unzip apk-----------";
out="./test/" #解压到当前目录下的test目录
unzip "$1" -d $out

#那么icon图的路径为 ./test/res/u3P.png

输出内容如下

-----apk name----
这是测试名称
-----apk versionCode----
1350003
-----apk versionName----
1.35.003
-----icon xml-----------
-----get backgroud and foreground-----------
0x7f0806ae 0x7f0f0001
0x7f0f0001
-----get icon-----------
“res/u3P.png”
“res/0yn.png”
“res/7cF.png”
“res/SDC.png”
“res/MbV.png”
“res/tfl.png”
“res/jyj.png”
“res/kbF.png”
“res/1Sy.png”
“res/D21.png”
“res/_eu.png”
“res/5QH.png”
“res/CGK.png”
“res/EtS.png”
“res/C9M.png”

分为mdpi、hdpi、xhdpi、xxhdpi,、xxxhdpi类型。其中
ic_launcher: 这是应用的主图标,用于应用抽屉(Launcher)和主屏幕。它代表了应用的主要视觉元素,因此通常需要具有较高的辨识度和设计感。

ic_launcher_foreground: 这个资源用于Android 8.0(API级别26)及以上版本的自适应图标。自适应图标可以根据不同设备的主题和用户设置动态改变形状。ic_launcher_foreground 通常包含图标的主要视觉元素,而背景则由系统提供,可以是圆形、方形或其他形状。

ic_launcher_round: 这也是用于自适应图标的资源,专门用于圆形图标。在支持自适应图标的设备上,系统可能会选择使用 ic_launcher_round 而不是 ic_launcher 或 ic_launcher_foreground,以适应设备图标的圆角设计。

这样就可以获取icon图的地址了,到此完毕。从工程化的角度看,还是使用封装好的包更简单。

在这里插入图片描述

参考文档

  1. https://zpp0196.me/2018/11/23/java-apk-parser/
  2. https://blog.csdn.net/chenqioulin/article/details/119357526
  3. https://code.google.com/p/android-apktool
  4. https://sq.sf.163.com/blog/article/172788280990601216

如有侵权,烦请联系删除

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐