private void buildApk() throws Exception {
    // Do NOT use ApkBuilder's embedded JarSigner
    PrivateKey privateKey = null;
    X509Certificate x509Cert = null;

    ApkBuilder apkbuilder =
        new ApkBuilder(
            S.apkUnsigned, S.ap_Resources, S.dexClasses, privateKey, x509Cert, System.out);

    if (setProgress(65, R.string.addLibs)) {
      return;
    }
    apkbuilder.addNativeLibraries(S.dirLibs);

    int percent = 65;

    for (File jarLib : S.dirLibs.listFiles()) {

      // skip native libs in sub directories
      if (!jarLib.isFile() || !jarLib.getName().endsWith(".jar")) {
        continue;
      }
      apkbuilder.addResourcesFromJar(jarLib);

      if (setProgress(++percent)) {
        return;
      }
    }

    if (setProgress(75, R.string.zipAssets)) {
      return;
    }
    Util.zip(S.dirSrc, S.zipSrc);
    Util.zip(S.dirRes, S.zipRes);
    Util.zip(S.dirLibs, S.zipLibs);
    Util.zip(S.dirDexedLibs, S.zipDexedLibs);

    if (setProgress(80, R.string.addAssets)) {
      return;
    }
    String strAssets = S.dirAssets.getName() + File.separator;
    apkbuilder.addFile(S.xmlMan, strAssets + S.xmlMan.getName());
    apkbuilder.addFile(S.zipSrc, strAssets + S.zipSrc.getName());
    apkbuilder.addFile(S.zipRes, strAssets + S.zipRes.getName());
    apkbuilder.addFile(S.zipLibs, strAssets + S.zipLibs.getName());
    apkbuilder.addFile(S.zipDexedLibs, strAssets + S.zipDexedLibs.getName());

    apkbuilder.setDebugMode(true);
    apkbuilder.sealApk();
  }
  /**
   * Creates the APK file using the internal APKBuilder.
   *
   * @param outputFile the output file
   * @param dexFile the dex file
   * @param zipArchive the classes folder
   * @param sourceFolders the resources
   * @param jarFiles the embedded java files
   * @param nativeFolders the native folders
   * @param signWithDebugKeyStore enables the signature of the APK using the debug key
   * @throws MojoExecutionException if the APK cannot be created.
   */
  private void doAPKWithAPKBuilder(
      File outputFile,
      File dexFile,
      File zipArchive,
      ArrayList<File> sourceFolders,
      ArrayList<File> jarFiles,
      ArrayList<File> nativeFolders,
      boolean signWithDebugKeyStore)
      throws MojoExecutionException {
    getLog().debug("Building APK with internal APKBuilder");
    sourceFolders.add(new File(project.getBuild().getOutputDirectory()));

    for (Artifact artifact : getRelevantCompileArtifacts()) {
      if (extractDuplicates) {
        try {
          computeDuplicateFiles(artifact.getFile());
        } catch (Exception e) {
          getLog()
              .warn(
                  "Cannot compute duplicates files from " + artifact.getFile().getAbsolutePath(),
                  e);
        }
      }
      jarFiles.add(artifact.getFile());
    }

    // Check duplicates.
    if (extractDuplicates) {
      List<String> duplicates = new ArrayList<String>();
      List<File> jarToModify = new ArrayList<File>();
      for (String s : jars.keySet()) {
        List<File> l = jars.get(s);
        if (l.size() > 1) {
          getLog().warn("Duplicate file " + s + " : " + l);
          duplicates.add(s);
          for (int i = 1; i < l.size(); i++) {
            if (!jarToModify.contains(l.get(i))) {
              jarToModify.add(l.get(i));
            }
          }
        }
      }

      // Rebuild jars.
      for (File file : jarToModify) {
        File newJar;
        newJar = removeDuplicatesFromJar(file, duplicates);
        int index = jarFiles.indexOf(file);
        if (newJar != null) {
          jarFiles.set(index, newJar);
        }
      }
    }

    String debugKeyStore;
    ApkBuilder apkBuilder;
    try {
      debugKeyStore = ApkBuilder.getDebugKeystore();
      apkBuilder =
          new ApkBuilder(
              outputFile,
              zipArchive,
              dexFile,
              (signWithDebugKeyStore) ? debugKeyStore : null,
              null);
      if (apkDebug) {
        apkBuilder.setDebugMode(apkDebug);
      }

      for (File sourceFolder : sourceFolders) {
        apkBuilder.addSourceFolder(sourceFolder);
      }

      for (File jarFile : jarFiles) {
        boolean excluded = false;

        if (excludeJarResourcesPatterns != null) {
          final String name = jarFile.getName();
          getLog().debug("Checking " + name + " against patterns");
          for (Pattern pattern : excludeJarResourcesPatterns) {
            final Matcher matcher = pattern.matcher(name);
            if (matcher.matches()) {
              getLog().debug("Jar " + name + " excluded by pattern " + pattern);
              excluded = true;
              break;
            } else {
              getLog().debug("Jar " + name + " not excluded by pattern " + pattern);
            }
          }
        }

        if (excluded) {
          continue;
        }

        if (jarFile.isDirectory()) {
          String[] filenames =
              jarFile.list(
                  new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                      return PATTERN_JAR_EXT.matcher(name).matches();
                    }
                  });

          for (String filename : filenames) {
            apkBuilder.addResourcesFromJar(new File(jarFile, filename));
          }
        } else {
          apkBuilder.addResourcesFromJar(jarFile);
        }
      }

      for (File nativeFolder : nativeFolders) {
        apkBuilder.addNativeLibraries(nativeFolder);
      }
      apkBuilder.sealApk();
    } catch (ApkCreationException e) {
      throw new MojoExecutionException(e.getMessage());
    } catch (DuplicateFileException e) {
      final String msg =
          String.format(
              "Duplicated file: %s, found in archive %s and %s",
              e.getArchivePath(), e.getFile1(), e.getFile2());
      throw new MojoExecutionException(msg, e);
    } catch (SealedApkException e) {
      throw new MojoExecutionException(e.getMessage());
    }
  }