Updated Oct 19, 2026

Utilities

Compare APK size, resources and DEX changes

diffuse-apk-diff is a two-APK comparison adapter using Diffuse.

Agent

overview

What diffuse-apk-diff does

Compare an earlier and later APK to inspect changes in package size, resources and DEX contents. This is static artifact comparison; neither app is installed or executed.

A FILE containing native UTF-8 Diffuse comparison text, with APK size/resource and DEX member sections. This is not JSON. The owned changed-pair and identical-pair fixtures passed; native parsing failure and invalid ZIP input were rejected separately.

Each APK ZIP is limited to 20 MiB and 2000 entries, with at most 64 MiB declared expanded data. AndroidManifest.xml is required; repeated raw paths, absolute paths, parent traversal and symlinks are refused. Native execution has a 120-second timeout. The 4 MiB text-output cap is checked after execution, not a guarantee of peak memory or temporary-disk use.

Pinned upstream version: 0.3.0. Upstream license: Apache-2.0; first-party adapter licensing is separate. Local native positive and negative fixtures passed. Native and platform fixtures, public Library identity and source/notices delivery were verified.

source github.com/JakeWharton/diffuse/tree/d1d4939038ca521ee650e1ddb1a7c8e396e5d2b7

use cases

Where diffuse-apk-diff fits

Review package growth

Compare two owned builds to inspect size changes before a release review.

Locate artifact changes

Read the native report for differences in resources and DEX members.

Establish an unchanged baseline

Use the same package on both sides when validating the comparison workflow; the native identical-pair result still needs acceptance.

reference

diffuse-apk-diff inputs and flags

2 inputs
NameTypeFlagDescription
old-apkFILE--old-apkEarlier owned APK ZIP file.
new-apkFILE--new-apkLater owned APK ZIP file.

Showing key inputs. diffuse-apk-diff exposes 2 inputs in total.

example

Run diffuse-apk-diff

diffuse-apk-diff · command
python3 /app/run.py --old-apk ./before.apk --new-apk ./after.apk ./output
sample output
OLD: old.apk (signature: none)
NEW: new.apk (signature: none)

          │         compressed         │         uncompressed         
          ├─────────┬─────────┬────────┼─────────┬─────────┬──────────
 APK      │ old     │ new     │ diff   │ old     │ new     │ diff     
──────────┼─────────┼─────────┼────────┼─────────┼─────────┼──────────
      dex │   392 B │   431 B │  +39 B │   492 B │   560 B │    +68 B 
     arsc │   784 B │   784 B │    0 B │   680 B │   680 B │      0 B 
 manifest │   622 B │   622 B │    0 B │ 1.2 KiB │ 1.2 KiB │      0 B 
      res │     0 B │     0 B │    0 B │     0 B │     0 B │      0 B 
    asset │     0 B │   453 B │ +453 B │     0 B │   4 KiB │   +4 KiB 
    other │    22 B │    22 B │    0 B │     0 B │     0 B │      0 B 
──────────┼─────────┼─────────┼────────┼─────────┼─────────┼──────────
    total │ 1.8 KiB │ 2.3 KiB │ +492 B │ 2.3 KiB │ 6.4 KiB │ +4.1 KiB 

 DEX     │ old │ new │ diff       
─────────┼─────┼─────┼────────────
   files │   1 │   1 │  0         
 strings │   6 │   8 │ +2 (+2 -0) 
   types │   3 │   4 │ +1 (+1 -0) 
 classes │   1 │   1 │  0 (+0 -0) 
 methods │   1 │   2 │ +1 (+1 -0) 
  fields │   0 │   0 │  0 (+0 -0) 

 ARSC    │ old │ new │ diff 
─────────┼─────┼─────┼──────
 configs │   1 │   1 │  0   
 entries │   2 │   2 │  0   

=================
====   APK   ====
=================

   compressed   │    uncompressed    │                              
───────┬────────┼─────────┬──────────┤                              
 size  │ diff   │ size    │ diff     │ path                         
───────┼────────┼─────────┼──────────┼──────────────────────────────
 453 B │ +453 B │   4 KiB │   +4 KiB │ + assets/fixture-padding.bin 
 431 B │  +39 B │   560 B │    +68 B │ ∆ classes.dex                
───────┼────────┼─────────┼──────────┼──────────────────────────────
 884 B │ +492 B │ 4.5 KiB │ +4.1 KiB │ (total)                      


=================
====   DEX   ====
=================

STRINGS:

   old │ new │ diff       
  ─────┼─────┼────────────
   6   │ 8   │ +2 (+2 -0) 
  
  + I
  + answer
  

TYPES:

   old │ new │ diff       
  ─────┼─────┼────────────
   3   │ 4   │ +1 (+1 -0) 
  
  + I
  

METHODS:

   old │ new │ diff       
  ─────┼─────┼────────────
   1   │ 2   │ +1 (+1 -0) 
  
  + org.trickest.fixture.Fixture answer() → int

guidance

Choosing diffuse-apk-diff

Use Diffuse when the comparison between two package builds matters. JADX reconstructs Java from one APK, while Apktool decodes smali and resources. A package delta is not a runtime behavior or compatibility test.

faq

diffuse-apk-diff questions

old-apk: Earlier owned APK ZIP file. new-apk: Later owned APK ZIP file.

A FILE containing native UTF-8 Diffuse comparison text, with APK size/resource and DEX member sections. This is not JSON. The owned changed-pair and identical-pair fixtures passed; native parsing failure and invalid ZIP input were rejected separately. The registered contract also exposes a FOLDER output; the primary report is the FILE artifact verified in the platform fixture run.

Each APK ZIP is limited to 20 MiB and 2000 entries, with at most 64 MiB declared expanded data. AndroidManifest.xml is required; repeated raw paths, absolute paths, parent traversal and symlinks are refused. Native execution has a 120-second timeout. The 4 MiB text-output cap is checked after execution, not a guarantee of peak memory or temporary-disk use.

Use Diffuse when the comparison between two package builds matters. JADX reconstructs Java from one APK, while Apktool decodes smali and resources. A package delta is not a runtime behavior or compatibility test.

Yes. This Library tool uses the tested image and supplied-file contract. Native fixtures and the private platform fixture-tool-verifier run passed; the image, adapter source and notices are publicly downloadable through the repository directions below.

The public repository overview provides immutable image and ORAS source/notices download commands, the exact bundle SHA256 and pinned upstream source directions. The bundle includes the adapter, Dockerfile, dependency locks where applicable, corresponding source, installed notices and owned fixture harness. Diffuse also includes embedded Java notices and matching Debian OpenJDK source payloads. First-party adapter licensing is separate from upstream licensing. Follow its local-tag alias directions to run the fixture without a GHCR account. Image, source and license notice downloads.

Run diffuse-apk-diff yourself

Complete retained native Diffuse text from two self-owned APK fixtures. The later build adds one method and a 4 KiB asset; an identical pair has zero method delta. A corrupt DEX inside a valid ZIP caused native failure and adapter exit 2. Invalid ZIP rejection is separate adapter preflight. Separate private platform fixture runs and exact public Library readbacks also passed.

Facts on this page come from the live Trickest tool library.