获取apk的包名、版本号、版本名-->命令(python)

547 阅读4分钟

前言

   临近下班前的两小时,背靠椅子、手持82年的白开水、翘着二郎腿,正津津有味的浏览着自己手写的代码。心里不禁乐道,今天这不得提前下班!?嘴角微微上扬。然而,天有不测风云,令人想不到会如此之快被"打脸"。 这xxxxx,都要下班了,还来搞事情。。。没办法,紧急事件,推不了,只能加班开搞。

需求:获取所有平台下的所有游戏包名。(游戏将近一万款)
ps:手机安装不了没有备案的游戏(四月份开始执行),游戏备案需要用到包名

   听到这个需求,对于会点反编译的人儿来说,这不简单?直接反编译获取包体的AndroidManifest,然后解析这个文件获取包名不就行了?(不会还有人为手动一个一个包体看吧)

   这个办法虽然说可以实现,但是不是完美的方案,时间开销太大。那么有没有一种时间消耗较少且不需要反编译等这些多余操作就能直接获取到包体包名的办法呢?

正文

命令(获取包体信息)

aapt dump badging xxx.apk

例子

if __name__ == '__main__':
    get_apk_info = "aapt.exe dump badging D:/apk/test.apk"
    output = os.popen(get_apk_info).read().encode('utf-8')
    print(output)

完整代码(获取单个apk包名)

import os,re

#获取包名
def getPackageName(apk_path, aapt_path):
    # 使用命令获取版本信息
    get_apk_info = "%s dump badging %s" % (aapt_path, apk_path)
    try:
        output = os.popen(get_apk_info).read().encode('utf-8')
    except UnicodeDecodeError:
        try:
            # 解决错误 UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 1254: illegal multibyte sequence
            buffer_stream = os.popen(get_apk_info)
            output = buffer_stream.buffer.read().decode('utf-8')
        except Exception:
            print(Exception.__name__)
            output = ''
    if len(output) == 0:
        print('获取失败')
        return
    # 通过正则匹配,获取包名,版本号,版本名称
    match_string = r"package: name='(\S+)' versionCode='(\d+)' versionName='(\S+)'"
    match = re.compile(match_string).match(output)
    if not match:
        print('正则表达式匹配失败')
        return

    packagename = match.group(1)
    versionCode = match.group(2)
    versionName = match.group(3)
    print(" 包名:%s \n 版本号:%s \n 版本名称:%s " % (packagename, versionCode, versionName))

if __name__ == '__main__':
    apk_path = os.path.join(os.getcwd(), r'apk/test.apk')
    aapt_path = os.path.join(os.getcwd(), r'jarLib/aapt.exe')
    getPackageName(apk_path, aapt_path)

创建excel表单

def create_xlsx():
    xls_path = os.path.join(os.getcwd(), r'package_name.xlsx')
    xls2 = xlsxwriter.Workbook(xls_path)
    sht1 = xls2.add_worksheet()
    # 添加字段
    sht1.write(0, 0, '游戏id')
    sht1.write(0, 1, '包名')
    gameid = [5, 15, 20, 154]
    row = 1
    col = 0
    for indexId in gameid:
        # 给字段中加值   考虑使用循环
        sht1.write(row, col, str(indexId))
        sht1.write(row, col + 1, r'包名')
        row += 1
    xls2.close()

读取excel表单

def read_xlsx():
    xls_path = os.path.join(os.getcwd(), r'package_name.xlsx')
    # 打开要读取的 Excel 文件
    workbook_read = openpyxl.load_workbook(xls_path)
    sheet_read = workbook_read.active
    # 读取数据
    for row in sheet_read.iter_rows():
        print(row[0].value)
        # for cell in row:
        #     value = cell.value
        #     print(value)

创建txt文本并写入内容(追加模式)

def add_content_txt():
    stringList = ['111111', 'aaaaaa', 'bbbbbb']
    txt_path = os.path.join(os.getcwd(), r'write_txt.txt')
    file = open(txt_path, r'a', encoding='utf-8')
    for string in stringList:
        file.write('%s\n' % string)
    file.close()

读取txt文本内容(只读模式)

def read_txt():
    txt_path = os.path.join(os.getcwd(), r'read_txt.txt')
    if os.path.exists(txt_path):
        file = open(txt_path, 'r', encoding='UTF-8')
        data = file.readlines()
        file.close()
        for bean in data:
            print(str(bean).strip())

操作txt文本的操作符

**‘r’**:**只读**。该文件必须已存在。

**‘r+’**:**可读可写**。该文件必须已存在,写为追加在文件内容末尾。  

**‘rb’**:表示以二进制方式读取文件。该文件必须已存在。  

**‘w’**:**只写**。打开即默认创建一个新文件,如果文件已存在,则覆盖写(即文件内原始数据会被新写入的数据清空覆盖)。

**‘w+’**:**写读**。打开创建新文件并写入数据,如果文件已存在,则覆盖写。

**‘wb’**:表示以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件;如果文件已存在,则覆盖写。

**‘a’**:**追加写**。若打开的是已有文件则直接对已有文件操作,若打开文件不存在则创建新文件,只能执行写(追加在后面),不能读。

**‘a+’**:**追加读写**。打开文件方式与写入方式和'a'一样,但是可以读。需注意的是你若刚用‘a+’打开一个文件,一般不能直接读取,因为此时光标已经是文件末尾,除非你把光标移动到初始位置或任意非末尾的位置。

   上面分别列出了读取apk包名的逻辑,创建、读取excel和txt的逻辑,在实际开发中可以根据需要进行结合操作输出内容。