[Android Software/Hacking General [Developers Only]] osm0sis:
Just in time for the impending Magisk v19.1 stable!

Signing zips and APKs on-device has always been a tricky proposition due to memory requirements of the old SignApk.jar, running a Java jar on an Android device, and other complications for signing script-based zips. Android has always been missing a zip binary (for unzip see my Busybox Installer), and zipalign is also handy if you do APK work. To remedy this once and for all, I'm introducing my new zip/module to push my dexed version of @topjohnwu's brilliant zipsigner.jar (which streams the zips so memory isn't the bottleneck, processing power is and even a massive zip just needs time) and static compiles of zip and zipalign to /system/(x)bin and uses a command wrapper to run zipsigner with Android's own dalvikvm. :cowboy:

Very cheekily it should also satisfy the zip and zipalign requirements of my experimental gappsintegrator su.d/post-fs-data.d script. ;)

I work on these projects in my limited time off, so if you like the progress I'm making, or enjoy anything else I've done on xda, please do hit the donate link from my profile. Thanks for your support!

99-flashafterupdate.sh:

- update for Magisk v19.0+ with no sbin_tmp; check for a running "magisk/addon.d.sh" directly

- skip subdirectories when processing zips to be flashed

- create a "disabled" subdirectory for ease of use for end-users

- add support for alternate /cache /persist and /data/flashafterupdate directories to give people built-in options for encrypted storage issues

UPDATE-adb.Installer.v1.0.39-signed.zip;

UPDATE-Adreno.Systemless.Installer-signed.zip;

UPDATE-Busybox.Installer.v1.30.1-ALL-signed.zip;

UPDATE-Nexus.Media.Installer-signed.zip:

- fix false positive Magisk detection with non-Magisk Manager booted installs

UPDATE-nano.Terminal.Editor.v4.2-signed.zip:

- update to latest nano official source

- fix false positive Magisk detection with non-Magisk Manager booted installs

UPDATE-ZipSigner.Installer.v3.0-signed.zip:

- installs my dexed version of topjohnwu's zipsigner.jar, a wrapper to run it from terminal using simply `zipsigner`, and builds of zip and zipalign for good measure

- supports virtually all versions of SuperSU, Magisk or unrooted system install, as all my installers do

Android Image Kitchen (AIK) saw a big update to v3.5, and AnyKernel2 got some great fixes and is getting the last couple planned updates right now before the big rewrite with magiskboot. :cool: GN Synapse Injector AK2 zip has gotten and will get these last final fixes to the old AK2 template, but I will no longer update it post-rewrite. :good:

Edit

: New special zip features

You may add keywords to zip filename or in a file at /data/.zipsigner:

1) system or System or SYSTEM to force a system installation.

2) uninstall or Uninstall or UNINSTALL to uninstall busybox from the zip's detected target location (/su/xbin > /magisk/zipsigner/system/xbin > /data/adb/su/xbin > /data/adb/modules/zipsigner/system/xbin > /system/xbin, unless system forced per above).

Edit 2

: Zip build/bundle script added, now that I build arm and arm64 zip myself!

~/zip-build.sh:

#!/bin/bash
# ahoyhoy!

# zip-build.sh
#
# osm0sis @ xda-developers
#
# requires (in addition to the default basic Ubuntu WSL packages):
# make, zip, default-jre
#
# ~/zipalign/build.sh for arm/arm64 zipalign compiles

RC=0;
MAGISK=$HOME/magisk-modules;

bold() { echo -e "\033[1m"$@"\033[0m"; }

reset() {
bold "--- Removing zip build environment ...";
rm -rfv $MAGISK/UPDATE-ZipSigner.Installer* $(dirname $HOME/zip-*/README)/ zipsigner-*.jar zip-*.zip UPDATE-ZipSigner.Installer.*-signed.zip;
rmdir $MAGISK 2>/dev/null;
}

init() {
local name source tarball zipsigner;
reset;
bold "--- Initializing zip build environment ...";
bold "- Downloading latest official zip release tarball ...";
source=$(wget -qO- "https://packages.ubuntu.com/search?keywords=zip&searchon=sourcenames&exact=1&suite=all&section=all" | grep -o 'source/.*/zip' | tail -n1);
tarball=$(wget -qO- "https://packages.ubuntu.com/$source" | grep -o '".*/zip/.*.orig.*"' | cut -d\" -f2);
name=$(basename "$tarball");
wget -O $HOME/$name "$tarball";
tar -xzvf $name;
mv -fv zip30 zip-3.0;
rm -f $name;
chmod 755 zip-3.0/unix/configure;

bold "- Cloning zip installer git repository ...";
mkdir -p $MAGISK;
git clone https://github.com/Magisk-Modules-Repo/zipsigner $MAGISK/UPDATE-ZipSigner.Installer;

bold "- Downloading zipsigner ...";
zipsigner="opengapps/opengapps/raw/master/scripts/zipsigner-resources/zipsigner-2.2.jar";
wget -O $HOME/$(basename $zipsigner) https://github.com/$zipsigner;
}

update() {
local curtag name source tarball;
bold "--- Updating zip ...";
source=$(wget -qO- "https://packages.ubuntu.com/search?keywords=zip&searchon=sourcenames&exact=1&suite=all&section=all" | grep -o 'source/.*/zip' | tail -n1);
tarball=$(wget -qO- "https://packages.ubuntu.com/$source" | grep -o '".*/zip/.*.debian.*"' | cut -d\" -f2);
curtag=$(basename $tarball .debian.tar.xz | cut -d_ -f2);
if [ "zip-${curtag}" != "$(basename $PWD)" ]; then
name=$(basename "$tarball");
bold "- Downloading latest official Ubuntu upstream zip patches tarball at $curtag ... ";
wget -O $name "$tarball";
bold "- Setting up directory and patching ...";
tar -xJvf $name;
rm -f $name;
for i in debian/patches/*.patch; do
echo $i;
patch --forward -p1 < $i;
done;
cd $HOME;
mv -f $ZIP zip-${curtag//v/};
else
echo "Already up to date.";
fi;
}

config() {
local host sysroot opts ldflags cflags;
opts="-DUNIX -DLARGE_FILE_SUPPORT -DZIP64_SUPPORT";
ldflags="-Wl,--gc-sections -s -static";
cflags="-std=c89 -D__ANDROID_API__=21 -O3 -ffunction-sections";
host=aarch64-linux-android; # Any Android toolchain "works" here
bold "--- Configuring ...";
export PATH="$(echo $HOME/x-tools/$host* | rev | cut -d\ -f1 | rev)/bin:$PATH";
LDFLAGS="$ldflags" unix/configure clang "$cflags -I. $opts";
export RC=$?;
cp -fv flags flags.android;
}

clean() {
bold "--- Cleaning ...";
make -f unix/Makefile clean;
rm -f zip-arm zip-arm64;
export RC=$?;
}

build() {
local host suffix;
for host in arm-linux-androideabi aarch64-linux-android; do
bold "--- Building $host ...";
export PATH="$(echo $HOME/x-tools/$host* | rev | cut -d\ -f1 | rev)/bin:$PATH";
cp -fv flags.android flags;
make -f unix/Makefile generic;
export RC=$?;
case $host in
arm*) suffix=arm;;
aarch64*) suffix=arm64;;
esac;
cp -fpv zip zip-$suffix;
make -f unix/Makefile clean;
done;
}

bundle() {
local ver curdir modver modcode newmodver newmodcode iteration skipmodprop;
bold "--- Bundling ...";
rm -f zip-*.zip UPDATE-ZipSigner.Installer.*-signed.zip 2>/dev/null;
ver=$(echo "$ZIP" | cut -d- -f2-);
if [ -f "$ZIP/zip-arm" ]; then
bold "- Copying new zip $ver builds ...";
curdir=$(basename $MAGISK/UPDATE-ZipSigner.Installer*);
cp -fp $ZIP/zip-arm $MAGISK/$curdir/bin;
cp -fp $ZIP/zip-arm64 $MAGISK/$curdir/bin;
if [ "$curdir" != "UPDATE-ZipSigner.Installer.v$ver" ]; then
mv $MAGISK/$curdir $MAGISK/UPDATE-ZipSigner.Installer.v$ver;
fi;
fi;
if [ -f "$HOME/zipalign/zipalign-arm" ]; then
bold "- Copying new zipalign builds ...";
cp -fp $HOME/zipalign/zipalign-arm $MAGISK/UPDATE-ZipSigner.Installer.*/bin;
cp -fp $HOME/zipalign/zipalign-arm64 $MAGISK/UPDATE-ZipSigner.Installer.*/bin;
fi;
modver=$(grep -o "^version=.*$" $MAGISK/UPDATE-ZipSigner.Installer.*/module.prop | cut -d= -f2);
modcode=$(grep -o "^versionCode=.*$" $MAGISK/UPDATE-ZipSigner.Installer.*/module.prop | cut -d= -f2);
if [ "$ver" == "$modver" ]; then
newmodver="$modver";
newmodcode="$((modcode + 1))";
iteration=1;
else
newmodver="$ver";
newmodcode="${ver//.}0";
test ${#newmodcode} == 3 && newmodcode="$newmodcode"0;
fi;
if [ "$iteration" ]; then
echo -ne "\033[1m\n*** Update Magisk module version code ($modcode -> $newmodcode) (y/n)? \033[0m";
read n; echo;
case $n in
Y|y) ;;
*) skipmodprop=1;;
esac;
fi;
if [ ! "$skipmodprop" ]; then
sed -i -e "s/version=.*/version=$newmodver/" -e "s/versionCode=.*/versionCode=$newmodcode/" $MAGISK/UPDATE-ZipSigner.Installer.*/module.prop;
sed -i -e "s/version\".*/version\": \"$newmodver\",/" -e "s/versionCode\".*/versionCode\": \"$newmodcode\",/" $MAGISK/UPDATE-ZipSigner.Installer.*/update.json;
fi;

bold "- Packing \"zip-$ver.zip\" ...";cd
cd $MAGISK/UPDATE-ZipSigner.Installer.*;
zip -9 -x .git -x .github -x update.json -r -q $HOME/zip-$ver.zip *;
cd $HOME;
bold "- Signing as \"UPDATE-ZipSigner.Installer.v$ver-signed.zip\" ...";
java -jar zipsigner-*.jar zip-$ver.zip zip-$ver-signed.zip;
mv -f zip-$ver-signed.zip UPDATE-ZipSigner.Installer.v$ver-signed.zip 2>/dev/null;
rm -f zip-*.zip /tmp/signAPK*.tmp 2>/dev/null;
}

test ! "$1" && set -- help;
until [ ! $1 ]; do
ZIP=$(readlink -f `find $HOME -maxdepth 1 -type d -name 'zip-*'` 2>/dev/null);
if [ ! "$ZIP" ]; then
case $1 in
help|init|reset) ;;
*) echo "zip-build: zip source not found, run 'init' option"; exit 1;;
esac;
elif [ "$ZIP" == "$HOME/zip" -o ! -d "$ZIP/debian" ]; then
case $1 in
help|init|reset|update|all) ;;
*) echo "zip-build: zip source not patched, run 'update' or 'all' option"; exit 1;;
esac;
elif [ ! -f "$ZIP/flags.android" ]; then
case $1 in
help|init|reset|update|config|clean|all) ;;
*) echo "zip-build: zip source not configured, run 'config' or 'all' option"; exit 1;;
esac;
fi;
case $1 in
config|build) SAVEDPATH="$PATH";;
esac;
case $1 in
init|reset|bundle) cd $HOME; $1;;
update|config|clean|build) cd $ZIP; $1;;
all) set -- "$0" update config clean build bundle;;
help) echo "zip-build.sh init update config build bundle all clean reset"; exit 1;;
*) echo "zip-build: invalid option -- '$*'"; exit 1;;
esac;
case $1 in
config|build) export PATH="$SAVEDPATH";;
esac;
shift;
done;

exit $RC;