#!/usr/bin/env python3 """Minimal zipalign: uncompressed entries start on 4-byte boundaries (like the SDK's `zipalign 4`). Safe after v1 (JAR) signing, which covers entry contents, not zip layout. usage: zipalign.py in.apk out.apk""" import struct import sys import zipfile src, dst = sys.argv[1], sys.argv[2] with zipfile.ZipFile(src) as zin, open(dst, "wb") as f: with zipfile.ZipFile(f, "w") as zout: for info in zin.infolist(): data = zin.read(info.filename) out = zipfile.ZipInfo(info.filename, info.date_time) out.compress_type = info.compress_type out.external_attr = info.external_attr if info.compress_type == zipfile.ZIP_STORED: header_end = f.tell() + 30 + len(info.filename.encode("utf-8")) out.extra = b"\0" * ((4 - header_end % 4) % 4) zout.writestr(out, data) with open(dst, "rb") as raw, zipfile.ZipFile(dst) as z: for info in z.infolist(): if info.compress_type == zipfile.ZIP_STORED: raw.seek(info.header_offset + 26) n, m = struct.unpack("