From ff11ab292f8b9a24d4fc1976b0d7c65fa005242a Mon Sep 17 00:00:00 2001 From: Madis Pink Date: Tue, 10 Oct 2017 22:56:52 +0300 Subject: [PATCH 1/5] Reduce size to 1497 bytes Use smallest possible manifest, use DSA keystore with keysize=512 --- .gitignore | 1 + README.md | 2 +- app/AndroidManifest.xml | Bin 660 -> 27 bytes app/classes.dex | 0 app/keystore.jks | Bin 0 -> 890 bytes build.sh | 29 +++++++++++++++++++++++++++++ signed-release.apk | Bin 1757 -> 1498 bytes 7 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .gitignore delete mode 100644 app/classes.dex create mode 100644 app/keystore.jks create mode 100755 build.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/README.md b/README.md index b2bf523..50a0331 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ApkGolf -This repository hosts the smallest Android APK in the world. The current size of the APK is *1757 bytes*. +This repository hosts the smallest Android APK in the world. The current size of the APK is *1497 bytes*. To learn more about how this was achieved, please read the [blog post](https://fractalwrench.co.uk/posts/playing-apk-golf-how-low-can-an-android-app-go/). diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index 81f89c9332fad753cbfb5e7bc618b9286839b85d..a471caffc00874eb293f29f8522890a142636322 100644 GIT binary patch literal 27 icmcD?P0Y(oOD!%@C`e4sPE1d=RZ7-NR#MQn;{pJOS_q5) literal 660 zcmZQ(;9!`-#K6GFAj2TS$iTqI00lsH2#igDPDYZS2V}2A;!}fZWQNC-WIbf-@hC)> z;^4?l%*#wmEiPeTXD>)h&Q45E#ZUtb6&!$3fI$L_6cbQ90Zp76$QJ=ZW;Ag^-2Xtp s160I;qELXr2Zc{QhnWF~AAsT(Sd0bv0UH3i59~Eu<}u(1D@GjR005a01^@s6 diff --git a/app/classes.dex b/app/classes.dex deleted file mode 100644 index e69de29..0000000 diff --git a/app/keystore.jks b/app/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..8d53c71cb162246cdc1dbb91aff4428caea5cddd GIT binary patch literal 890 zcmezO_TO6u1_mY|W&~sQ#JrTE{LB;}Kc4+E%V8kRY0$*TYQV?FrOn33!l=b0$jHdb zz|#0>VXgVh&NzC`J=Z_ly*mfQDZj!xghz4;)o zYSQmpa%U4|thCt<>tD^DV^g4h?$~3#-tC^#1x#lfZ!D6ooBu{j@vKrwl2DOxf^*{j z!1=RVwOe}pdn?yn+i1PkYJ2uxW&*8fNpuU%{ z_``3{$x)A6Wna&{Q!298WW~*=)3UaSz#N=>^Bd;zlv$(hWiKq@Z zgjgf=Obsl7VWw%&#H0!gn@0Tu5wgBsMdUZ6GJkYiMq00ECt%W=3XFK&}OlX949>(Wb@^28}CV zo?tX+oWtbE@Ml@mxjvy&yVTyF`7X#8l)Ir~L)^X7XXUmm;`qEyOne>V=je$`>TO_Mx}qf8Fz zErpw^=6vycDdl-oq;})VRi9iwL^=DWv`v=P6;YR-XUfc7__z3$_=L>OdYY!md@>42 zroOz3xN;ox0`^t9n}DQ9`0tL@-?tvvKmF<7qc{GT`>Yjv^D)ay zRz~Xkmr&KJvpddDu@F;H3cS%YMQF{IGQXRyJ9Fl0_$Dn@G>|ut1xAxBABz}^h?>V{ zt0je1WwT#1PjKzEFVH&jPYfkmnGF~WbeTk$?+G|P{-jR}GbUEATIgx>4Cv7* td&RS@LN}R71)dGQq7@&b#F9PngZi}E`HMf!(zxC|QPeW{q_+L_eE{3`JT?FT literal 0 HcmV?d00001 diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..14ad7ea --- /dev/null +++ b/build.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +rm -rf build +mkdir -p build/apk + +set -x + +#TODO ensure that ANDROID_HOME is set + +echo "Creating base AndroidManifest.xml" +$ANDROID_HOME/build-tools/26.0.2/aapt p -M app/AndroidManifest.xml -I $ANDROID_HOME/platforms/android-26/android.jar -f -F build/base.apk +unzip build/base.apk -d build/apk + +echo "Creating empty classes.dex" +touch build/apk/classes.dex + +echo "Creating unsigned archive" +zip -j -r build/app-unsigned.apk build/apk + +KEYSTORE_PASS=android $ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --ks app/keystore.jks --out build/signed-release.apk --ks-pass env:KEYSTORE_PASS --ks-key-alias android build/app-unsigned.apk + +set +x + +echo +echo +echo +echo "#######################################" +echo "RESULTING APK SIZE: $(stat -f '%z' build/signed-release.apk)" + diff --git a/signed-release.apk b/signed-release.apk index 3b1970fde980b04a131507c909ec487e56ced452..ef09bd16dd7a38929a5b433dab9249060d8ad359 100644 GIT binary patch literal 1498 zcmWIWW@Zs#U|`^2V31H`U|TTt!d4(JgOPzjm_dfYF)yVkKQqNQF)uSMwYWsDA~z>A zgp+}pVc9t$5H79YW?*Fb3RDd?WNQCezJm@Tt^3PfrE4Z#>`2cz;zEy9R4?`{k4mRdc z7B*qVWEh(RiOr70=0aj~Be9u*Yy&xQUPE(310b|CF*7oY0&*>YJPRn7iZ(TVFlbx> z^8}+o;~XYOhCj=i&h-hM+NJjX%y&V)pxg}=8{+PrJ}b9n5y$6sV&dx)k063XF!im z*(;uH6}rhxD)4OZ6|MLfC6?@oz%<2R4aDX^3`%7BKpJR-D8tl$@79-GZ(3*Bvm#G{ z-S&ie-ew^t5$ zf{9UpHzSiAGp@2x0vK2ju&oh9V=XCJAtfbRSphK^SCNA-cu6A@uwX?gfPe;KDSQIF SS=m5tU;@HbKw63w!~+12pX2rb literal 1757 zcmWIWW@Zs#U|`^2STWbq+b)=YUI&mjg^7Vd7)U$jr4;37ruZi2Wu~PTm*`dG<|L;* zNSJZx$bkbV6b>sKI&t8@aRye0G7jcK1<6iZ{*G{=mHiP3DQ)MA_NLfus$gJu&r6C+ zi^?kGWVWt$Oe!i%s?utcN?7rLp@)e_D57O%!z0d&q&p5eOf6?rc73oH_|OpB$ipI0 z<6*)so{)CnA^UBvA8(3ST7~Df`K8C6(ZvZrKQ?A3oU_cQy~5h^r;R|S_6og85tN9fb`z!Mty28 zxlXB82TtjgaEJ*1%A`8?Be&|Yr7lNuzZ_EE57e_8hz**Uwi`4t&R@XH#K^?N!doxC z&48DUQ>)FR?K>|cBR4C90goY<0S6m%C=0VNW3qvqIIp3(fu)hDp@pfTk$IFjuZfX? zrJ*I1i>A7XQ3=^NMpg#qCPsdst&ChuO^l2TQywq1Seg6434W5wy?jIVrWNgfzw~-PZ443F#?i9r!aME_I_8&5LO(F9 z;H|rpqsX1+q_XBf&0PPInWasCj%<%S{q0|zN9!)d+!M;xXVafvWp`LvmSY&c`M|&Q zf?M;q{oSLb8f_@SzCU7beyBuHZspn(KZE7l`nI1wFSOwj%hcOTmwtb{f1_5#x_Lg) z%3rUo+4&_o?Nk3|?!CGFES1XlqFy`Awv*lLwAJZsM!ELnd|$yCQ2{ctUN?8$y)-py z&c}kOvBqy)-2S(}*m3Tmx)ozyy8pK?>mF>}Y4b=@YgK>On<`EwV0&II4yg?@RnBUxS?yR0p6;7h8?+rqEq{FU+c^LWEH!wfVV<$X1an?PJVK>f{9UpHzSiA xGw$jHl Date: Tue, 10 Oct 2017 23:11:28 +0300 Subject: [PATCH 2/5] Remove junk from manifest Reduces size to 1415 bytes --- README.md | 2 +- app/res/layout/manifest.xml | 1 + build.sh | 11 +++++++++-- signed-release.apk | Bin 1498 -> 1415 bytes 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 app/res/layout/manifest.xml diff --git a/README.md b/README.md index 50a0331..da4eba7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ApkGolf -This repository hosts the smallest Android APK in the world. The current size of the APK is *1497 bytes*. +This repository hosts the smallest Android APK in the world. The current size of the APK is *1415 bytes*. To learn more about how this was achieved, please read the [blog post](https://fractalwrench.co.uk/posts/playing-apk-golf-how-low-can-an-android-app-go/). diff --git a/app/res/layout/manifest.xml b/app/res/layout/manifest.xml new file mode 100644 index 0000000..a471caf --- /dev/null +++ b/app/res/layout/manifest.xml @@ -0,0 +1 @@ + diff --git a/build.sh b/build.sh index 14ad7ea..5d73204 100755 --- a/build.sh +++ b/build.sh @@ -8,16 +8,23 @@ set -x #TODO ensure that ANDROID_HOME is set echo "Creating base AndroidManifest.xml" -$ANDROID_HOME/build-tools/26.0.2/aapt p -M app/AndroidManifest.xml -I $ANDROID_HOME/platforms/android-26/android.jar -f -F build/base.apk +$ANDROID_HOME/build-tools/26.0.2/aapt p -M app/AndroidManifest.xml -S app/res -I $ANDROID_HOME/platforms/android-26/android.jar -f -F build/base.apk unzip build/base.apk -d build/apk +# Don't use the original manifest with all the generated junk, use the compiled xml from layout instead +rm build/apk/AndroidManifest.xml +rm build/apk/resources.arsc +mv build/apk/res/layout/manifest.xml build/apk/AndroidManifest.xml +rm -rf build/apk/res + echo "Creating empty classes.dex" touch build/apk/classes.dex echo "Creating unsigned archive" zip -j -r build/app-unsigned.apk build/apk -KEYSTORE_PASS=android $ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --ks app/keystore.jks --out build/signed-release.apk --ks-pass env:KEYSTORE_PASS --ks-key-alias android build/app-unsigned.apk +echo "Signing archive" +KEYSTORE_PASS=android $ANDROID_HOME/build-tools/26.0.2/apksigner sign --v1-signing-enabled false --ks app/keystore.jks --out build/signed-release.apk --ks-pass env:KEYSTORE_PASS --ks-key-alias android --min-sdk-version 24 build/app-unsigned.apk set +x diff --git a/signed-release.apk b/signed-release.apk index ef09bd16dd7a38929a5b433dab9249060d8ad359..ea31e385e7c8fa2fd1c627aa453d9f65d4bc5a42 100644 GIT binary patch delta 384 zcmcb`-Oeo$;LXe;!oa}5!N4G)$PiTMbSW9g+rThU!n8iOXCt43gMiEZolQY53j?~n z-Ue?`>fo68A@SdYo!u>m^3u}FCP{i9;gl$n+W2(tr^Uhx1)R*HtkUjIjPpC9wAaY+ z#eK^fZ+BIPgruzd{MU{BmPdUqu|8k;;P!^TwM94m-?4$L=K@;Dz>u)h%Nxvq65I@v zCuVsUY5v0h4QMQ8{s19PzE>V>U9UIybt3Df$i{b%_OI*7FHFME})nRKxu zJ>!Ve8c!YFwWd)fA`8vr4&A!+xRU#vk6L2lW3%*gXRcSjKVxcglSSadV@{JFM_y## zpSJ8$=q}Ilmk&SnFVVS~6+5~6h?4bOtuPsjK%-|)iqj0kk9BVLWB=x}C9VG2nJJ;W zW-YT3)eM>Zx?VNyi_;{RrU{JBmA=6$U*_htICis^#Z~+?xK;i|(tdU7HRW<{wNE+) ze`T^uZMmP8&QHI)qW;g~|I#2IaRL3nz;Jxq#63y|X{vW4LAbPnn}Lz#DN9MW)Y;rzdY6I5{V= dxHz>~FD11iG=!CbIZbtP0;?jM6f4jG1^{rFsB8cL From cb8db65e4c87895d5fba5375d962103c7d379c62 Mon Sep 17 00:00:00 2001 From: Madis Pink Date: Tue, 10 Oct 2017 23:16:41 +0300 Subject: [PATCH 3/5] Use shorter dname for the certificate Reduces size to 1295 bytes --- app/keystore.jks | Bin 890 -> 768 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/keystore.jks b/app/keystore.jks index 8d53c71cb162246cdc1dbb91aff4428caea5cddd..edee27427da917ad1d2b9164266d88c9514d8937 100644 GIT binary patch delta 583 zcmeyx*1$GFuKt~QF9QQ3hd~n~ivb@Smo^(C3!@g3AR{9y154w_1zE=yW{ONb!trra z=!!Ith58$U#1vM)x;1Inei4;rj~dnU9eh&xk63@-FS&YZh{3JpQp;8f%{85OEtB_d zv+3^E!@uUcUYXf=CRFr_BBSYoD6un-c{3*8tbU}U-+Oe&W_`u_Z*%OG?y+9UYB+bj zxtQbKVYA<#LfOjKyt*Qw`A@u^@A{8Cw&zI+1`}Ja&%K?Qtk(2U^w{0x+tJIHdsMF~ zzTKwaUfWx&RLBy3ed@m{PmSLHjk;R-?cs|9lV`5G5j(Hoh^W-*lPt?7dhFO;ZrOg` z(QuP<{`14v5+fe{JkPbyY2Kgu9p~2VKgrY88T)MEWX_)fb{`pl!NI^9p=WAf31n>m z2Fw~D&RoFE#K^?N;$-^W#ekcQU8~LGoCOOrD}w>IA*TU58*?ZNvoM2!oH(zcxuJof zfsuisnW0e>kZS?tSwOj{iW@%~G)@*{T2=4Dz~so#>7e@H`KM(oO)6Yf4OOf2eQWnA z*eE`>(h6P4#y(r+02A}9#lBPjGcj%XvwPhm**7VVPWbO!cc1;_zH(NNtKYa6D;mff z$O0WA%f}+dA`+mp#Pq=pTanwrO`Re)Z#A^6S#O5oaApGr16?MO)W4E8ZG|Ppubnvl zOw_RJ;;ePvcZW%oVd_Q6JxWZhyxPUSEk8mle)Po7y81_Kx!?O8@(vpx^|Tcq+p^=? H)2S-~MwscR delta 710 zcmZo*`^7dvuKqI1VFm_9PJ<>!Rs%jZE^RhO7Dg>5K}JSa2A0N83v111F8_JBX^vrW z)BnQ6Bb(mv*?;-7`=t-TXINif5Hdl7xzk6Py$G2hOjb-KyQv=RkHOu&tm&~=}8VYAUw#F!E{_U`7QDV^LIk%T3?ri>=L)N#N)fXelbr^u*!N3}!XKG-{z`&$w z(8Qz)44p>{n3))vm{{D`U+*&DW@FcC^EhY0!pzEG;9Gb6JoAlCxOvw(6bvkJwg#t#OKD}cV3JfCq{ zy)y%ogZ^<_rPJF4Bt^o1cdY)t^}zn=PyZgh@yFa}t=OB7SzfX-Qs2LXs#cxdaej)0 zn2J*1jixC=Yqpg6-E`fVGgremX|bY#yn!q*7-aca#8^bsJT_Y`DXc1+{hE1#Yp;EQ z){%c=D8a^Tz+j-uB*J`8sL^`b*SM|sCw*F&F|m5pLQk7#Ori`^_KIg)g>EvF3OpNp hMJql=i6wjD2lZ*S^A~@drE$G`qNru?Np1V<`v8vw@@fD8 From f155a326fe44486b2ce1189266c3e65cb05e5214 Mon Sep 17 00:00:00 2001 From: Madis Pink Date: Tue, 10 Oct 2017 23:18:31 +0300 Subject: [PATCH 4/5] Update readme to reflect new size --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da4eba7..d5e99e3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ApkGolf -This repository hosts the smallest Android APK in the world. The current size of the APK is *1415 bytes*. +This repository hosts the smallest Android APK in the world. The current size of the APK is *1295 bytes*. To learn more about how this was achieved, please read the [blog post](https://fractalwrench.co.uk/posts/playing-apk-golf-how-low-can-an-android-app-go/). From e6c6f4d2e19ed5a6bf03aebe19f800122a3dd91b Mon Sep 17 00:00:00 2001 From: Madis Pink Date: Tue, 10 Oct 2017 23:18:31 +0300 Subject: [PATCH 5/5] Add generated apk with size=1295 --- signed-release.apk | Bin 1415 -> 1295 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/signed-release.apk b/signed-release.apk index ea31e385e7c8fa2fd1c627aa453d9f65d4bc5a42..c2be19b5363a8560649feab2f2bec9de741d4047 100644 GIT binary patch delta 578 zcmZqY?&q4Yi^+D^#63#&U$yQ=f^caCHv=QfS4IW~77+#ph9G7j0R%=+TB@D1Pz%Ub z1L8M8MLIw^4IpL&@)dyeZ9R6>&$-nj1C$G-)r zX9Ex$G%>CL;>-oiOpHuSEKa_r-(3v2+1Rz(JkD9LFtaika2s+Ou(L6TvM>uX7|4n9 z8k!p#7#bKE7@8RxMFF`MK%NDZi>kQsd~89aJAY|FmqSNrkJbp=x!$ zZ|yz>8^y;~TA?f1*k`L8U}B!N*mvrGCZ;WacCULR`zGbl3ICnz?z5lVSI+8j^&9tM zMFV*QS)emy`B=nQL;`e{m_E2+D{?!ysZ-?Ut%jC0>&;M{&1}G6pvxqZ`d6~Pt+1r{ zwG+pmi5hlYoVCvT?l6fmOuZ<%M~R7*SG(A^N!7u0qJP` vXwbL<7J!Tfjg!wZ&vTW=CRkA+foU*vvq-ft)z6p}C;}5L%j;8JR@^xfVd41(XZ6$%8spHGY`9ig8W7 zGXs-@{&8ES)7u0jMZ$k~tp2|B!2an^{~o>Z$J}SF*qe`8Ua~S$-@k;aR-N5(eu{;d zic;W>rYS;ewv_qZblsUVSHm}Hv7&*zfh;fpWcgUcSVYu3Hd`$ztSX!Rnt6h2uYG~m zk$+++0mf{=V4%w+!hBDtQGMFixUKgmeOj0?v3k`)Pn%~chr=IUDznz|x?c29=CNYTwf6y!`cW~Ouc`IE1oxntc suC~QrKLg{}0OCVeYWVQfWDAxWVDg*1jm3Z|Sab3V7Dcw>EI>;b0HZ_49RL6T