利用 Python 脚本与 Lint 工具清理 Android 项目无用资源

小满
小满
发布时间:2026-10-11| 3人浏览过
原创

本文介绍如何使用 Python 脚本结合 Android Lint 工具自动清理项目中的无用资源。通过解析 Lint 生成的 XML 报告,脚本能识别未使用的 Drawable、XML 布局等资源,并根据节点数量执行文件删除或节点移除操作,有效减小应用体积并优化构建速度。

原理与准备工作

在 Android 开发中,未使用的资源文件(如图片、布局 XML)会增加应用体积并拖慢构建速度。Android SDK 自带的 lint 工具可以扫描项目并生成详细的报告。为了自动化清理过程,我们可以编写一个 Python 脚本 delUnused.py,将其放置在项目根目录下直接运行。

该脚本的核心逻辑分为两步:首先调用 Lint 命令生成 XML 格式的检查结果,然后解析该 XML 文件,识别出三类无用资源(如 Drawable、Layout 等),并执行相应的删除或节点移除操作。

执行 Lint 命令

脚本首先通过 subprocess 模块执行 Lint 命令。我们需要指定检查项为 UnusedResources,输出格式为 --xml,并提供结果保存路径和项目路径。

lint --check UnusedResources --xml [resultPath] [projectPath]

在 Python 中,这通过 exec_lint_command 函数实现。它启动子进程,读取标准输出并打印结果,确保命令执行无误。

def exec_lint_command():
 cmd = 'lint --check UnusedResources --xml %s %s' % (_get_lint_result_path(), _get_project_dir_path())
 p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
 c = p.stdout.readline().decode()
 while c:
  print(c)
  c = p.stdout.readline().decode()

解析 Lint 报告

Lint 生成的 XML 报告包含具体的问题描述。例如,一个典型的 issue 节点如下所示,其中 id 标识问题类型,message 描述具体资源,location 指向文件路径和行号。

<issue
  id="UnusedResources"
  severity="Warning"
  message="The resource `R.layout.activity_all_player` appears to be unused"
  category="Performance"
  priority="3"
  summary="Unused resources"
  explanation="Unused resources make applications larger and slow down builds."
  errorLine1="<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
"
  errorLine2="^"
  quickfix="studio">
  <location
   file="res\layout\activity_all_player.xml"
   line="2"
   column="1"/>
 </issue>

脚本使用 xml.dom.minidom 解析生成的 XML 文件。核心函数 _parse_lint_report 获取根节点,并调用 _parse_xml 遍历子节点。对于每个 issue 节点,脚本提取 id、severity 和 message 属性,并进一步解析 location 子节点以获取文件路径、行号和列号。

def _parse_lint_report():
 file = minidom.parse(_get_lint_result_path())
 root = file.documentElement
 beans = _parse_xml(root)
 return beans
def _parse_xml(element, beans=None):
 if beans is None:
  beans = []
 for node in element.childNodes:
  if node.nodeName == ISSUE_KEY and node.nodeType is node.ELEMENT_NODE:
   lint_bean = _LintBean()
   lint_bean.id = node.getAttribute(ID_KEY)
   lint_bean.severity = node.getAttribute(SEVERITY_KEY)
   lint_bean.message = node.getAttribute(MESSAGE_KEY)
   _parse_location(node, lint_bean)
   lint_bean.print()
   beans.append(lint_bean)
 return beans

为了存储解析结果,脚本定义了 _Location 和 _LintBean 两个类。前者存储文件路径、行号和列号,后者封装完整的 lint 信息,并提供 print 方法用于调试输出。

class _Location(object):
 def __init__(self):
  self.file = ''
  self.line = 0
  self.column = 0

class _LintBean(object):
 def __init__(self):
  self.id = ''
  self.severity = ''
  self.message = ''
  self.location = _Location()

 def print(self):
  print('find a %s, cause: %s. filePath: %s. line: %s' % (
   self.id, self.message, self.location.file, self.location.line))

执行清理操作

解析完成后,脚本遍历所有 lint 结果。只有当 id 为 UnusedResources 时才进行处理。根据 location.line 是否为空,脚本区分两种情况:

  1. 单节点资源:如果 line 字段存在,说明该资源在 XML 中仅有一个引用节点。此时直接调用 del_file 删除整个资源文件。
  2. 多节点资源:如果 line 字段为空,说明该资源在 XML 中可能有多个引用节点(例如一个布局文件中包含多个同名控件)。此时需要调用 del_node 删除特定的 XML 节点,而不是删除整个文件。
for lint in lint_result:
 total_unused_resource += 1
 if lint.id != 'UnusedResources':
  continue
 if lint.location.line != '':
  is_single = _is_single_node(lint.location.file)
  if is_single:
   total_del_file += 1
   del_file(lint.location.file)
  else:
   total_remove_attr += 1
   node_name = get_node_name(lint.message)
   del_node(lint.location.file, node_name)
 else:
  total_del_file += 1
  del_file(lint.location.file)

删除文件的操作通过 os.remove 实现,并捕获 FileNotFoundError 以处理文件已被手动删除的情况。删除 XML 节点时,脚本重新解析目标文件,遍历子节点,找到匹配 name 属性的节点后调用 removeChild,最后使用 writexml 将修改写回文件。

def del_file(file_path):
 try:
  os.remove(file_path)
  print('remove %s success.' % file_path)
 except FileNotFoundError:
  print('remove %s error.' % file_path)
def del_node(file_path, node_name):
 file = minidom.parse(file_path)
 root = file.documentElement
 nodes = root.childNodes
 for node in nodes:
  if node.nodeType in (node.TEXT_NODE, node.COMMENT_NODE):
   continue
  if node_name == node.getAttribute('name'):
   root.removeChild(node)
   file.writexml(open(file_path, 'w', encoding='UTF-8'), encoding='UTF-8')
   print('remove %s, node_name:%s. success!' % (file_path, node_name))
   return

注意事项与风险

在执行此类自动化清理脚本前,请务必注意以下风险:

  • 备份项目:删除操作不可逆,建议在运行脚本前对项目目录进行完整备份或使用版本控制系统(如 Git)提交当前状态。
  • 验证结果:Lint 报告可能存在误报,特别是对于动态加载的资源或反射引用的资源。建议在正式环境使用前,先在测试分支或小规模项目中验证脚本的准确性。
  • 权限问题:确保运行脚本的用户对项目目录及资源文件具有读写权限。

以上就是利用 Python 和 Lint 删除项目无用资源的详细内容,更多关于 Android 开发优化、Python 自动化脚本的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。