First To Sign Or First To Align? Answered.

First, the answer:

  1. Sign using JDK‘s jarsigner.exe and your keystore, SHA1 and timestamp.
  2. Align using zipalign.exe -v 4 (from Android SDK Tools). 4-bytes, is to provide a 32-bit alignment.

Do not align-again (after signing),
not having the archived changed in any way.
You may extract/delete the content of META-INF (not com/*)
and create a new archive (which you may sign/align later).

Simple right? – So why the confusion?

those two lines

Signing and aligning are both actions that would changes the archive,
If you’re smart- you’ve must have wondered how is it possible for a
signing of an already aligned-archive able to go through, without modify the alignment,
or alternatively how is it that aligning a signed archive will not cause the signature-checksum to fail.

While jarsigner is a pretty basic application,
but apksigner will take existing alignment into calculation,
you can align your archive before, but when you use apksigner,
the apksigner application will rearrange bytewise so the signature
will keep 32bit over 4-bytes boundaries. It will not align your archive (although it
probably can, but I guess actual-aligning as a function will requires explicit support
by R&D, which is always hated…)

What happens if you forget to align before using apksigner?
the signature block will be 4-bytes aligned, but the rest of the data will
“overflow around”..

….Imagine holding a cup full of chocolate pudding in your open palm,
and right in the middle some marshmallows a floating around, perfectly enclosure
within themselves but still unstable as a whole… :]

Being slightly more technical than holding some jelly..

mmap and munmap (Linux/C+ based libraries/native Java
..and Android apps..) will map or unmap files or devices into memory,
in the virtual address space of the calling process.
The starting address for the new mapping is specified in addr (the length argument
specifies the length of the mapping).

So basically, aligning it both for a more efficient mapping and also
to avoid hard-codded programs with the 4-bytes value from failing/lag/became sluggish,
here is an example for such program (C++):

The following program prints part of the
file specified in its first command-line argument
to standard output. The range of bytes to be printed
is specified via offset and length values in
the second and third command-line arguments.

The program creates a memory mapping of the required pages
of the file and then uses write to output the desired bytes.

Program source
   #include <sys/mman.h>
   #include <sys/stat.h>
   #include <fcntl.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>

   #define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

   main(int argc, char *argv[])
       char *addr;
       int fd;
       struct stat sb;
       off_t offset, pa_offset;
       size_t length;
       ssize_t s;

       if (argc < 3 || argc > 4) {
           fprintf(stderr, "%s file offset [length]\n", argv[0]);

       fd = open(argv[1], O_RDONLY);
       if (fd == -1)

       if (fstat(fd, &sb) == -1)           /* To obtain file size */

       offset = atoi(argv[2]);
       pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
           /* offset for mmap() must be page aligned */

       if (offset >= sb.st_size) {
           fprintf(stderr, "offset is past end of file\n");

       if (argc == 4) {
           length = atoi(argv[3]);
           if (offset + length > sb.st_size)
               length = sb.st_size - offset;
                   /* Can't display bytes past end of file */

       } else {    /* No length arg ==> display to end of file */
           length = sb.st_size - offset;

       addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
                   MAP_PRIVATE, fd, pa_offset);
       if (addr == MAP_FAILED)

       s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
       if (s != length) {
           if (s == -1)

           fprintf(stderr, "partial write");

       munmap(addr, length + offset - pa_offset);