"""zipalign replacement: rewrites an APK so every STORED entry's data starts on a 4-byte boundary. Re-compressing deflated entries doesn't break the v1 (JAR) signature, which covers uncompressed contents only. """ import struct import sys import zipfile ALIGN = 4 def align(src, dst): zin = zipfile.ZipFile(src) with zipfile.ZipFile(dst, "w") as zout: for info in zin.infolist(): data = zin.read(info.filename) zi = zipfile.ZipInfo(info.filename, date_time=info.date_time) zi.compress_type = info.compress_type zi.external_attr = info.external_attr zi.create_system = info.create_system extra = b"" if info.compress_type == zipfile.ZIP_STORED: offset = zout.fp.tell() name_len = len(zi.filename.encode("utf-8")) base = offset + 30 + name_len + 6 # 6 = our extra-field header + alignment value pad = (ALIGN - base % ALIGN) % ALIGN # 0xD935 is the extra-field id Android's own zipalign uses for padding extra = struct.pack("