src/main/java/com/simpligility/maven/plugins/android/phase09package/ApkMojo.java
private void doAPKWithAPKBuilder( File outputFile, File dexFile, File zipArchive, Collection<File> sourceFolders,
                                      List<File> jarFiles, Collection<File> nativeFolders,
                                      boolean signWithDebugKeyStore ) throws MojoExecutionException
    {
        getLog().debug( "Building APK with internal APKBuilder" );
        
        //A when jack is running the classes directory will not get filled (usually)
        // so let's skip it if it wasn't created by something else
        if ( projectOutputDirectory.exists() || !getJack().isEnabled() ) 
        {
            sourceFolders.add( projectOutputDirectory );
        }

        for ( Artifact artifact : filterArtifacts( getRelevantCompileArtifacts(), skipDependencies,
                artifactTypeSet.getIncludes(), artifactTypeSet.getExcludes(), artifactSet.getIncludes(),
                artifactSet.getExcludes() ) )
        {
            getLog().debug( "Found artifact for APK :" + artifact );
            if ( extractDuplicates )
            {
                try
                {
                    computeDuplicateFiles( artifact.getFile() );
                }
                catch ( Exception e )
                {
                    getLog().warn( "Cannot compute duplicates files from " + artifact.getFile().getAbsolutePath(), e );
                }
            }
            jarFiles.add( artifact.getFile() );
        }

        for ( File src : sourceFolders )
        {
            computeDuplicateFilesInSource( src );
        }

        // Check duplicates.
        if ( extractDuplicates )
        {
            try
            {
                extractDuplicateFiles( jarFiles, sourceFolders );
            }
            catch ( IOException e )
            {
                getLog().error( "Could not extract duplicates to duplicate-resources.jar", e );
            }
        }

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

            for ( File sourceFolder : sourceFolders )
            {
                getLog().debug( "Adding source folder : " + sourceFolder );
                // Use ApkBuilder#addFile() to explicitly add resource files so that we can add META-INF/services.
                addResourcesFromFolder( apkBuilder, 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() )
                {
                    getLog().debug( "Adding resources from jar folder : " + jarFile );
                    final String[] filenames = jarFile.list( new FilenameFilter()
                    {
                        public boolean accept( File dir, String name )
                        {
                            return PATTERN_JAR_EXT.matcher( name ).matches();
                        }
                    } );

                    for ( String filename : filenames )
                    {
                        final File innerJar = new File( jarFile, filename );
                        getLog().debug( "Adding resources from innerJar : " + innerJar );
                        apkBuilder.addResourcesFromJar( innerJar );
                    }
                }
                else
                {
                    getLog().debug( "Adding resources from : " + jarFile );
                    apkBuilder.addResourcesFromJar( jarFile );
                }
            }

            addSecondaryDexes( dexFile, apkBuilder );

            for ( File nativeFolder : nativeFolders )
            {
                getLog().debug( "Adding native library : " + nativeFolder );
                apkBuilder.addNativeLibraries( nativeFolder );
            }
            apkBuilder.sealApk();
        }
        catch ( ApkCreationException | SealedApkException | IOException e )
        {
            throw new MojoExecutionException( e.getMessage(), e );
        }
        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 );
        }
    }
private void doAPKWithAPKBuilder( File outputFile, File dexFile, File zipArchive, Collection<File> sourceFolders,
                                      List<File> jarFiles, Collection<File> nativeFolders,
                                      boolean signWithDebugKeyStore ) throws MojoExecutionException
    {
        getLog().debug( "Building APK with internal APKBuilder" );
        
        //A when jack is running the classes directory will not get filled (usually)
        // so let's skip it if it wasn't created by something else
        if ( projectOutputDirectory.exists() || !getJack().isEnabled() ) 
        {
            sourceFolders.add( projectOutputDirectory );
        }

        for ( Artifact artifact : filterArtifacts( getRelevantCompileArtifacts(), skipDependencies,
                artifactTypeSet.getIncludes(), artifactTypeSet.getExcludes(), artifactSet.getIncludes(),
                artifactSet.getExcludes() ) )
        {
            getLog().debug( "Found artifact for APK :" + artifact );
            if ( extractDuplicates )
            {
                try
                {
                    computeDuplicateFiles( artifact.getFile() );
                }
                catch ( Exception e )
                {
                    getLog().warn( "Cannot compute duplicates files from " + artifact.getFile().getAbsolutePath(), e );
                }
            }
            jarFiles.add( artifact.getFile() );
        }

        for ( File src : sourceFolders )
        {
            computeDuplicateFilesInSource( src );
        }

        // Check duplicates.
        if ( extractDuplicates )
        {
            try
            {
                extractDuplicateFiles( jarFiles, sourceFolders );
            }
            catch ( IOException e )
            {
                getLog().error( "Could not extract duplicates to duplicate-resources.jar", e );
            }
        }

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

            for ( File sourceFolder : sourceFolders )
            {
                getLog().debug( "Adding source folder : " + sourceFolder );
                // Use ApkBuilder#addFile() to explicitly add resource files so that we can add META-INF/services.
                addResourcesFromFolder( apkBuilder, 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() )
                {
                    getLog().debug( "Adding resources from jar folder : " + jarFile );
                    final String[] filenames = jarFile.list( new FilenameFilter()
                    {
                        public boolean accept( File dir, String name )
                        {
                            return PATTERN_JAR_EXT.matcher( name ).matches();
                        }
                    } );

                    for ( String filename : filenames )
                    {
                        final File innerJar = new File( jarFile, filename );
                        getLog().debug( "Adding resources from innerJar : " + innerJar );
                        apkBuilder.addResourcesFromJar( innerJar );
                    }
                }
                else
                {
                    getLog().debug( "Adding resources from : " + jarFile );
                    apkBuilder.addResourcesFromJar( jarFile );
                }
            }

            addSecondaryDexes( dexFile, apkBuilder );

            for ( File nativeFolder : nativeFolders )
            {
                getLog().debug( "Adding native library : " + nativeFolder );
                apkBuilder.addNativeLibraries( nativeFolder );
            }
            apkBuilder.sealApk();
        }
        catch ( ApkCreationException | SealedApkException | IOException e )
        {
            throw new MojoExecutionException( e.getMessage(), e );
        }
        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 );
        }
    }
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.