code: private void writeSignatureFile(SignatureOutputStream out)
              throws IOException, GeneralSecurityException {
          Manifest sf = new Manifest();
          Attributes main = sf.getMainAttributes();
          main.putValue("Signature-Version", "1.0");
          main.putValue("Created-By", "1.0 (Android)");
  
          Base64.Encoder base64 = Base64.getMimeEncoder();
          MessageDigest md = MessageDigest.getInstance(DIGEST_ALGORITHM);
          PrintStream print = new PrintStream(
                  new DigestOutputStream(new ByteArrayOutputStream(), md),
                  true, SdkConstants.UTF_8);
  
          // Digest of the entire manifest
          mManifest.write(print);
          print.flush();
          main.putValue(DIGEST_MANIFEST_ATTR, base64.encodeToString(md.digest()));
  
          Map<String, Attributes> entries = mManifest.getEntries();
          for (Map.Entry<String, Attributes> entry : entries.entrySet()) {
              // Digest of the manifest stanza for this entry.
              print.print("Name: " + entry.getKey() + "\r\n");
              for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
                  print.print(att.getKey() + ": " + att.getValue() + "\r\n");
              }
              print.print("\r\n");
              print.flush();
  
              Attributes sfAttr = new Attributes();
              sfAttr.putValue(DIGEST_ATTR, base64.encodeToString(md.digest()));
              sf.getEntries().put(entry.getKey(), sfAttr);
          }
  
          sf.write(out);
  
          // A bug in the java.util.jar implementation of Android platforms
          // up to version 1.6 will cause a spurious IOException to be thrown
          // if the length of the signature file is a multiple of 1024 bytes.
          // As a workaround, add an extra CRLF in this case.
          if ((out.size() % 1024) == 0) {
              out.write('\r');
              out.write('\n');
          }
      }
docs: Writes a .SF file with a digest to the manifest.