/** * Creates the APK file using the command line. * * @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 doAPKWithCommand( File outputFile, File dexFile, File zipArchive, ArrayList<File> sourceFolders, ArrayList<File> jarFiles, ArrayList<File> nativeFolders, boolean signWithDebugKeyStore) throws MojoExecutionException { CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); List<String> commands = new ArrayList<String>(); commands.add(outputFile.getAbsolutePath()); if (!signWithDebugKeyStore) { commands.add("-u"); } commands.add("-z"); commands.add( new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".ap_") .getAbsolutePath()); commands.add("-f"); commands.add(new File(project.getBuild().getDirectory(), "classes.dex").getAbsolutePath()); commands.add("-rf"); commands.add(new File(project.getBuild().getDirectory(), "classes").getAbsolutePath()); if (nativeFolders != null && !nativeFolders.isEmpty()) { for (File lib : nativeFolders) { commands.add("-nf"); commands.add(lib.getAbsolutePath()); } } for (Artifact artifact : getRelevantCompileArtifacts()) { commands.add("-rj"); commands.add(artifact.getFile().getAbsolutePath()); } getLog().info(getAndroidSdk().getPathForTool("apkbuilder") + " " + commands.toString()); try { executor.executeCommand( getAndroidSdk().getPathForTool("apkbuilder"), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } }
private void invokeNDKStripper(File file) throws MojoExecutionException { try { getLog().debug("Detected shared library artifact, will now strip it"); // Execute the strip command final CommandExecutor stripCommandExecutor = CommandExecutor.Factory.createDefaultCommmandExecutor(); stripCommandExecutor.setErrorListener( new CommandExecutor.ErrorListener() { public boolean isError(String error) { getLog().error("Error while stripping binary: " + error); return true; } }); stripCommandExecutor.setLogger(getLog()); stripCommandExecutor.executeCommand( resolveNdkStripper(file).getAbsolutePath(), Arrays.asList(file.getAbsolutePath())); } catch (ExecutionException e) { getLog().error("Error while attempting to strip shared library", e); throw new MojoExecutionException("Error while attempting to strip shared library"); } }
/** * Given a map of source directories to list of AIDL (relative) filenames within each, runs the * AIDL compiler for each, such that all source directories are available to the AIDL compiler. * * @param files Map of source directory File instances to the relative paths to all AIDL files * within * @throws MojoExecutionException If the AIDL compiler fails */ private void generateAidlFiles( Map<File /*sourceDirectory*/, String[] /*relativeAidlFileNames*/> files) throws MojoExecutionException { List<String> protoCommands = new ArrayList<String>(); protoCommands.add("-p" + getAndroidSdk().getPathForFrameworkAidl()); genDirectoryAidl.mkdirs(); getLog().info("Adding AIDL gen folder to compile classpath: " + genDirectoryAidl); project.addCompileSourceRoot(genDirectoryAidl.getPath()); Set<File> sourceDirs = files.keySet(); for (File sourceDir : sourceDirs) { protoCommands.add("-I" + sourceDir); } for (File sourceDir : sourceDirs) { for (String relativeAidlFileName : files.get(sourceDir)) { File targetDirectory = new File(genDirectoryAidl, new File(relativeAidlFileName).getParent()); targetDirectory.mkdirs(); final String shortAidlFileName = new File(relativeAidlFileName).getName(); final String shortJavaFileName = shortAidlFileName.substring(0, shortAidlFileName.lastIndexOf(".")) + ".java"; final File aidlFileInSourceDirectory = new File(sourceDir, relativeAidlFileName); List<String> commands = new ArrayList<String>(protoCommands); commands.add(aidlFileInSourceDirectory.getAbsolutePath()); commands.add(new File(targetDirectory, shortJavaFileName).getAbsolutePath()); try { CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); executor.setCaptureStdOut(true); executor.executeCommand( getAndroidSdk().getAidlPath(), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } } } }
/** * @throws MojoExecutionException * @throws MojoFailureException */ public void execute() throws MojoExecutionException, MojoFailureException { try { // Validate the NDK final File ndkBuildFile = new File(getAndroidNdk().getNdkBuildPath()); NativeHelper.validateNDKVersion(ndkBuildFile.getParentFile()); // Validate the makefile - if our packaging type is so (for example) and there are // dependencies on .a files (or shared files for that matter) the makefile should include // the include of our Android Maven plugin generated makefile. validateMakefile(project, makefile); String[] ndkArchitectures = getAndroidNdk() .getNdkArchitectures( ndkClassifier, ndkArchitecture, applicationMakefile, project.getBasedir()); for (String ndkArchitecture : ndkArchitectures) { Preparation preparation = new Preparation().invoke(ndkArchitecture); boolean libsDirectoryExists = preparation.isLibsDirectoryExists(); File directoryToRemove = preparation.getDirectoryToRemove(); // Start setting up the command line to be executed final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); // Add an error listener to the build - this allows the build to conditionally fail // depending on a) the output of the build b) whether or not build errors (output on stderr) // should be // ignored and c) whether the pattern matches or not executor.setErrorListener(getNdkErrorListener()); final Set<Artifact> nativeLibraryArtifacts = findNativeLibraryDependencies(); // If there are any static libraries the code needs to link to, include those in the make // file final Set<Artifact> resolveNativeLibraryArtifacts = AetherHelper.resolveArtifacts( nativeLibraryArtifacts, repoSystem, repoSession, projectRepos); if (getLog().isDebugEnabled()) { getLog() .debug( "resolveArtifacts found " + resolveNativeLibraryArtifacts.size() + ": " + resolveNativeLibraryArtifacts.toString()); } final File makefileDir = new File(project.getBuild().getDirectory(), NDK_MAKFILE_DIRECTORY); makefileDir.mkdirs(); final File androidMavenMakefile = new File(makefileDir, "android_maven_plugin_makefile.mk"); // set the ndk build directory if (ndkBuildDirectory == null) { ndkBuildDirectory = project.getBasedir().getAbsolutePath(); } final MakefileHelper makefileHelper = new MakefileHelper( getLog(), repoSystem, repoSession, projectRepos, unpackedApkLibsDirectory); final MakefileHelper.MakefileHolder makefileHolder = makefileHelper.createMakefileFromArtifacts( new File(ndkBuildDirectory), resolveNativeLibraryArtifacts, ndkArchitecture, useHeaderArchives); IOUtil.copy(makefileHolder.getMakeFile(), new FileOutputStream(androidMavenMakefile)); // Add the path to the generated makefile - this is picked up by the build (by an include // from the user) executor.addEnvironment( "ANDROID_MAVEN_PLUGIN_MAKEFILE", androidMavenMakefile.getAbsolutePath()); setupNativeLibraryEnvironment( makefileHelper, executor, resolveNativeLibraryArtifacts, ndkArchitecture); // Adds the location of the Makefile capturer file - this file will after the build include // things like header files, flags etc. It is processed after the build to retrieve the // headers // and also capture flags etc ... final File makefileCaptureFile = File.createTempFile("android_maven_plugin_makefile_captures", ".tmp"); makefileCaptureFile.deleteOnExit(); executor.addEnvironment( MakefileHelper.MAKEFILE_CAPTURE_FILE, makefileCaptureFile.getAbsolutePath()); // Add any defined system properties if (systemProperties != null && !systemProperties.isEmpty()) { for (Map.Entry<String, String> entry : systemProperties.entrySet()) { executor.addEnvironment(entry.getKey(), entry.getValue()); } } executor.setLogger(this.getLog()); // Setup the command line for the make final List<String> commands = new ArrayList<String>(); // Setup the build directory (defaults to the current directory) but may be different // depending // on user configuration commands.add("-C"); commands.add(ndkBuildDirectory); // If the build should use a custom makefile or not - some validation is done to ensure // this exists and all if (makefile != null) { File makeFile = new File(project.getBasedir(), makefile); if (!makeFile.exists()) { getLog().error("Specified makefile " + makeFile + " does not exist"); throw new MojoExecutionException("Specified makefile " + makeFile + " does not exist"); } commands.add("-f"); commands.add(makefile); } configureApplicationMakefile(commands); configureMaxJobs(commands); configureNdkToolchain(commands); // Anything else on the command line the user wants to add - simply splice it up and // add it one by one to the command line if (ndkBuildAdditionalCommandline != null) { String[] additionalCommands = ndkBuildAdditionalCommandline.split(" "); for (final String command : additionalCommands) { commands.add(command); } } // If a build target is specified, tag that onto the command line as the // very last of the parameters if (target != null) { commands.add(target); } else /*if ( "a".equals( project.getPackaging() ) )*/ { commands.add(project.getArtifactId()); } final String ndkBuildPath = resolveNdkBuildExecutable(); getLog().info(ndkBuildPath + " " + commands.toString()); executor.executeCommand(ndkBuildPath, commands, project.getBasedir(), true); cleanUp( preparation.getNativeLibDirectory(), ndkArchitecture, libsDirectoryExists, directoryToRemove, makefileHolder, makefileCaptureFile); } } catch (MojoExecutionException e) { getLog().error("Error during build: " + e.getMessage(), e); throw e; } catch (Exception e) { getLog().error("Error while executing: " + e.getMessage()); throw new MojoExecutionException(e.getMessage(), e); } }
/** * Executes aapt to generate the R class for the given apklib. * * @param apklibArtifact apklib for which to generate the R class. * @throws MojoExecutionException if it fails. */ private void generateRForApkLibDependency(Artifact apklibArtifact) throws MojoExecutionException { final File unpackDir = getUnpackedLibFolder(apklibArtifact); getLog() .debug( "Generating incomplete R file for apklib: " + apklibArtifact.getGroupId() + ":" + apklibArtifact.getArtifactId()); final File apklibManifest = new File(unpackDir, "AndroidManifest.xml"); final File apklibResDir = new File(unpackDir, "res"); List<File> dependenciesResDirectories = new ArrayList<File>(); final Set<Artifact> apklibDeps = getDependencyResolver().getLibraryDependenciesFor(project, apklibArtifact); getLog().debug("apklib=" + apklibArtifact + " dependencies=" + apklibDeps); for (Artifact dependency : apklibDeps) { // Add in the resources that are dependencies of the apklib. final String extension = dependency.getType(); final File dependencyResDir = getUnpackedLibResourceFolder(dependency); if ((extension.equals(APKLIB) || extension.equals(AAR)) && dependencyResDir.exists()) { dependenciesResDirectories.add(dependencyResDir); } } // Create combinedAssets for this apklib dependency - can't have multiple -A args final File apklibCombAssets = new File(getUnpackedLibFolder(apklibArtifact), "combined-assets"); for (Artifact dependency : apklibDeps) { // Accumulate assets for dependencies of the apklib (if they exist). final String extension = dependency.getType(); final File dependencyAssetsDir = getUnpackedLibAssetsFolder(dependency); if ((extension.equals(APKLIB) || extension.equals(AAR))) { copyFolder(dependencyAssetsDir, apklibCombAssets); } } // Overlay the apklib dependency assets (if they exist) final File apkLibAssetsDir = getUnpackedLibAssetsFolder(apklibArtifact); copyFolder(apkLibAssetsDir, apklibCombAssets); final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(getLog()); AaptCommandBuilder commandBuilder = new AaptCommandBuilder() .packageResources() .makeResourcesNonConstant() .makePackageDirectories() .setWhereToOutputResourceConstants(genDirectory.getAbsolutePath()) .generateRIntoPackage(extractPackageNameFromAndroidManifest(apklibManifest)) .setPathToAndroidManifest(apklibManifest.getAbsolutePath()) .addResourceDirectoryIfExists(apklibResDir) .addResourceDirectoriesIfExists(dependenciesResDirectories) .autoAddOverlay() .addRawAssetsDirectoryIfExists(apklibCombAssets) .addExistingPackageToBaseIncludeSet(getAndroidSdk().getAndroidJar().getAbsolutePath()) .addConfigurations(configurations) .addExtraArguments(aaptExtraArgs) .setVerbose(aaptVerbose) // We need to generate R.txt for all projects as it needs to be consumed when generating // R class. // It also needs to be consumed when packaging aar. .generateRTextFile(unpackDir.getAbsolutePath()); getLog().debug(getAndroidSdk().getAaptPath() + " " + commandBuilder.toString()); try { executor.setCaptureStdOut(true); List<String> commands = commandBuilder.build(); executor.executeCommand(getAndroidSdk().getAaptPath(), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } }
private void generateR() throws MojoExecutionException { getLog().info("Generating R file for " + project.getArtifact()); genDirectory.mkdirs(); final File[] overlayDirectories = getResourceOverlayDirectories(); getLog().debug("Resource overlay folders : " + Arrays.asList(overlayDirectories)); final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); final List<String> commands = new ArrayList<String>(); commands.add("package"); commands.add("-f"); commands.add("--no-crunch"); // inputs commands.add("-I"); commands.add(getAndroidSdk().getAndroidJar().getAbsolutePath()); commands.add("-M"); commands.add(androidManifestFile.getAbsolutePath()); // NB AndroidBuilder only adds a single folder - presumably it contains a merge of all // resources. for (File resOverlayDir : overlayDirectories) { if (resOverlayDir != null && resOverlayDir.exists()) { getLog().debug("Adding resource overlay folder : " + resOverlayDir); commands.add("-S"); commands.add(resOverlayDir.getAbsolutePath()); } } if (resourceDirectory.exists()) { getLog().debug("Adding resource folder : " + resourceDirectory); commands.add("-S"); commands.add(resourceDirectory.getAbsolutePath()); } // Need to include any AAR or APKLIB dependencies when generating R because if any local // resources directly reference dependent resources then R generation will crash. addLibraryResourceFolders(commands); // NB aapt only accepts a single assets parameter - combinedAssets is a merge of all assets if (combinedAssets.exists()) { getLog().debug("Adding assets folder : " + combinedAssets); commands.add("-A"); commands.add(combinedAssets.getAbsolutePath()); } // outputs commands.add("-m"); commands.add("-J"); commands.add(genDirectory.getAbsolutePath()); // Write the output to an optional location // Used by AndroidBuilder but not by us. // final File optionalOutputLocation = some file; // getLog().debug( "Using default package : " + optionalOutputLocation ); // commands.add( "-F" ); // commands.add( optionalOutputLocation.getAbsolutePath() ); // If a proguard file is defined then output Proguard options to it. if (proguardFile != null) { final File parentFolder = proguardFile.getParentFile(); if (parentFolder != null) { parentFolder.mkdirs(); } getLog().debug("Adding proguard file : " + proguardFile); commands.add("-G"); commands.add(proguardFile.getAbsolutePath()); } if (StringUtils.isNotBlank(customPackage)) { getLog().debug("Adding custom-package : " + customPackage); commands.add("--custom-package"); commands.add(customPackage); } if (AAR.equals(project.getArtifact().getType())) { getLog().debug("Adding non-constant-id"); commands.add("--non-constant-id"); } for (String aaptExtraArg : aaptExtraArgs) { getLog().debug("Adding aapt arg : " + aaptExtraArg); commands.add(aaptExtraArg); } if (StringUtils.isNotBlank(configurations)) { // Should be comma separated list of locales etc. getLog().debug("Adding resource configurations : " + configurations); commands.add("-c"); commands.add(configurations); } if (aaptVerbose) { commands.add("-v"); } // We need to generate R.txt for all projects as it needs to be consumed when generating R // class. // It also needs to be consumed when packaging aar. commands.add("--output-text-symbols"); commands.add(targetDirectory.getAbsolutePath()); // Allows us to supply multiple -S arguments. commands.add("--auto-add-overlay"); getLog().debug(getAndroidSdk().getAaptPath() + " " + commands.toString()); try { targetDirectory.mkdirs(); executor.setCaptureStdOut(true); executor.executeCommand(getAndroidSdk().getAaptPath(), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } ResourceClassGenerator resourceGenerator = new ResourceClassGenerator(this, targetDirectory, genDirectory); generateCorrectRJavaForApklibDependencies(resourceGenerator); generateCorrectRJavaForAarDependencies(resourceGenerator); getLog().info("Adding R gen folder to compile classpath: " + genDirectory); project.addCompileSourceRoot(genDirectory.getAbsolutePath()); }
private void executeProguard() throws MojoExecutionException { // we should make this configurable, users may want to use a newer (or diff) version of proguard String proguardJar = getAndroidSdk().getPathForTool("proguard/lib/proguard.jar"); File proguardDir = new File(project.getBuild().getDirectory(), "proguard"); if (!proguardDir.exists() && !proguardDir.mkdir()) { throw new MojoExecutionException("Cannot create proguard output directory"); } else if (proguardDir.exists() && !proguardDir.isDirectory()) { throw new MojoExecutionException("Non-directory exists at " + proguardDir.getAbsolutePath()); } CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); List<String> commands = new ArrayList<String>(); if (jvmArguments != null) { for (String jvmArgument : jvmArguments) { // preserve backward compatibility allowing argument with or without dash (e.g. Xmx512m as // well as // -Xmx512m should work) (see // http://code.google.com/p/maven-android-plugin/issues/detail?id=153) if (!jvmArgument.startsWith("-")) { jvmArgument = "-" + jvmArgument; } commands.add(jvmArgument); } } commands.add("-jar"); commands.add(proguardJar); commands.add("@" + proguard.getConfig()); for (File file : getInputFiles()) { // don't add android packaging files, these are not input to proguard if (!AndroidExtension.isAndroidPackaging(FileUtils.extension(file.getAbsolutePath()))) { commands.add("-injars"); commands.add(file.getAbsolutePath()); } } commands.add("-outjars"); commands.add(project.getBuild().getDirectory() + File.separator + PROGUARD_OBFUSCATED_JAR); commands.add("-libraryjars"); commands.add(getAndroidSdk().getAndroidJar().getAbsolutePath()); commands.add("-dump"); commands.add(proguardDir + File.separator + "dump.txt"); commands.add("-printseeds"); commands.add(proguardDir + File.separator + "seeds.txt"); commands.add("-printusage"); commands.add(proguardDir + File.separator + "usage.txt"); commands.add("-printmapping"); commands.add(proguardDir + File.separator + "mapping.txt"); final String javaExecutable = getJavaExecutable().getAbsolutePath(); getLog().info(javaExecutable + " " + commands.toString()); try { executor.executeCommand(javaExecutable, commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } }
/** * Generates an intermediate apk file (actually .ap_) containing the resources and assets. * * @throws MojoExecutionException */ private void generateIntermediateApk() throws MojoExecutionException { CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); File[] overlayDirectories = getResourceOverlayDirectories(); File androidJar = getAndroidSdk().getAndroidJar(); File outputFile = new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".ap_"); List<String> commands = new ArrayList<String>(); commands.add("package"); commands.add("-f"); commands.add("-M"); commands.add(androidManifestFile.getAbsolutePath()); for (File resOverlayDir : overlayDirectories) { if (resOverlayDir != null && resOverlayDir.exists()) { commands.add("-S"); commands.add(resOverlayDir.getAbsolutePath()); } } if (resourceDirectory.exists()) { commands.add("-S"); commands.add(resourceDirectory.getAbsolutePath()); } for (Artifact libraryArtifact : getTransitiveDependencyArtifacts(APKLIB, AAR)) { final File libraryResDir = getUnpackedLibResourceFolder(libraryArtifact); if (libraryResDir.exists()) { commands.add("-S"); commands.add(libraryResDir.getAbsolutePath()); } } commands.add("--auto-add-overlay"); // NB aapt only accepts a single assets parameter - combinedAssets is a merge of all assets if (combinedAssets.exists()) { getLog().debug("Adding assets folder : " + combinedAssets); commands.add("-A"); commands.add(combinedAssets.getAbsolutePath()); } if (StringUtils.isNotBlank(renameManifestPackage)) { commands.add("--rename-manifest-package"); commands.add(renameManifestPackage); } if (StringUtils.isNotBlank(renameInstrumentationTargetPackage)) { commands.add("--rename-instrumentation-target-package"); commands.add(renameInstrumentationTargetPackage); } commands.add("-I"); commands.add(androidJar.getAbsolutePath()); commands.add("-F"); commands.add(outputFile.getAbsolutePath()); if (StringUtils.isNotBlank(configurations)) { commands.add("-c"); commands.add(configurations); } for (String aaptExtraArg : aaptExtraArgs) { commands.add(aaptExtraArg); } if (aaptVerbose) { commands.add("-v"); } if (!release) { getLog().info("Generating debug apk."); commands.add("--debug-mode"); } else { getLog().info("Generating release apk."); } getLog().debug(getAndroidSdk().getAaptPath() + " " + commands.toString()); try { executor.setCaptureStdOut(true); executor.executeCommand(getAndroidSdk().getAaptPath(), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } }
protected void instrument() throws MojoExecutionException, MojoFailureException { if (instrumentationPackage == null) { instrumentationPackage = extractPackageNameFromAndroidManifest(androidManifestFile); } if (instrumentationRunner == null) { instrumentationRunner = extractInstrumentationRunnerFromAndroidManifest(androidManifestFile); } final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); doWithDevices( new DeviceCallback() { public void doWithDevice(final IDevice device) throws MojoExecutionException, MojoFailureException { List<String> commands = new ArrayList<String>(); addDeviceParameter(commands, device); commands.add("shell"); commands.add("am"); commands.add("instrument"); commands.add("-w"); // only run Tests in specific package String testPackages = buildTestPackagesString(); // only run Tests in specific class String testClasses = buildTestClassesString(); boolean tcExists = StringUtils.isNotBlank(testClasses); boolean tpExists = StringUtils.isNotBlank(testPackages); if (tcExists && tpExists) { // if both testPackages and testClasses are specified --> ERROR throw new MojoFailureException( "testPackages and testClasses are mutual exclusive. They cannot be specified at the same time. " + "Please specify either testPackages or testClasses! For details, see http://developer.android.com/guide/developing/testing/testing_otheride.html"); } if (tpExists) { commands.add("-e"); commands.add("package"); commands.add(testPackages); getLog().info("Running tests for specified test packages: " + testPackages); } if (tcExists) { commands.add("-e"); commands.add("class"); commands.add(testClasses); getLog().info("Running tests for specified test classes/methods: " + testClasses); } // ---- stop mkessel extensions commands.add(instrumentationPackage + "/" + instrumentationRunner); getLog().info(getAndroidSdk().getAdbPath() + " " + commands.toString()); try { executor.executeCommand( getAndroidSdk().getAdbPath(), commands, project.getBasedir(), true); final String standardOut = executor.getStandardOut(); final String standardError = executor.getStandardError(); getLog().debug(standardOut); getLog().debug(standardError); // Fail when tests on device fail. adb does not exit with errorcode!=0 or even print // to stderr, so we have to parse stdout. if (standardOut == null || !standardOut.matches(".*?OK \\([0-9]+ tests?\\)\\s*")) { throw new MojoFailureException("Tests failed on device."); } } catch (ExecutionException e) { getLog().error(executor.getStandardOut()); getLog().error(executor.getStandardError()); throw new MojoFailureException("Tests failed on device."); } } }); }
/** * Generates an intermediate apk file (actually .ap_) containing the resources and assets. * * @throws MojoExecutionException */ private void generateIntermediateAp_() throws MojoExecutionException { CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); executor.setLogger(this.getLog()); File[] overlayDirectories; if (resourceOverlayDirectories == null || resourceOverlayDirectories.length == 0) { overlayDirectories = new File[] {resourceOverlayDirectory}; } else { overlayDirectories = resourceOverlayDirectories; } if (!combinedRes.exists()) { if (!combinedRes.mkdirs()) { throw new MojoExecutionException( "Could not create directory for combined resources at " + combinedRes.getAbsolutePath()); } } if (extractedDependenciesRes.exists()) { try { getLog().info("Copying dependency resource files to combined resource directory."); org.apache.commons.io.FileUtils.copyDirectory(extractedDependenciesRes, combinedRes); } catch (IOException e) { throw new MojoExecutionException("", e); } } if (resourceDirectory.exists()) { try { getLog().info("Copying local resource files to combined resource directory."); org.apache.commons.io.FileUtils.copyDirectory( resourceDirectory, combinedRes, new FileFilter() { /** * Excludes files matching one of the common file to exclude. The default excludes * pattern are the ones from * {org.codehaus.plexus.util.AbstractScanner#DEFAULTEXCLUDES} * * @see java.io.FileFilter#accept(java.io.File) */ public boolean accept(File file) { for (String pattern : AbstractScanner.DEFAULTEXCLUDES) { if (AbstractScanner.match(pattern, file.getAbsolutePath())) { getLog() .debug( "Excluding " + file.getName() + " from resource copy : matching " + pattern); return false; } } return true; } }); } catch (IOException e) { throw new MojoExecutionException("", e); } } // Must combine assets. // The aapt tools does not support several -A arguments. // We copy the assets from extracted dependencies first, and then the local assets. // This allows redefining the assets in the current project if (extractedDependenciesAssets.exists()) { try { getLog().info("Copying dependency assets files to combined assets directory."); org.apache.commons.io.FileUtils.copyDirectory( extractedDependenciesAssets, combinedAssets, new FileFilter() { /** * Excludes files matching one of the common file to exclude. The default excludes * pattern are the ones from * {org.codehaus.plexus.util.AbstractScanner#DEFAULTEXCLUDES} * * @see java.io.FileFilter#accept(java.io.File) */ public boolean accept(File file) { for (String pattern : AbstractScanner.DEFAULTEXCLUDES) { if (AbstractScanner.match(pattern, file.getAbsolutePath())) { getLog() .debug( "Excluding " + file.getName() + " from asset copy : matching " + pattern); return false; } } return true; } }); } catch (IOException e) { throw new MojoExecutionException("", e); } } if (assetsDirectory.exists()) { try { getLog().info("Copying local assets files to combined assets directory."); org.apache.commons.io.FileUtils.copyDirectory( assetsDirectory, combinedAssets, new FileFilter() { /** * Excludes files matching one of the common file to exclude. The default excludes * pattern are the ones from * {org.codehaus.plexus.util.AbstractScanner#DEFAULTEXCLUDES} * * @see java.io.FileFilter#accept(java.io.File) */ public boolean accept(File file) { for (String pattern : AbstractScanner.DEFAULTEXCLUDES) { if (AbstractScanner.match(pattern, file.getAbsolutePath())) { getLog() .debug( "Excluding " + file.getName() + " from asset copy : matching " + pattern); return false; } } return true; } }); } catch (IOException e) { throw new MojoExecutionException("", e); } } File androidJar = getAndroidSdk().getAndroidJar(); File outputFile = new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".ap_"); List<String> commands = new ArrayList<String>(); commands.add("package"); commands.add("-f"); commands.add("-M"); commands.add(androidManifestFile.getAbsolutePath()); for (File resOverlayDir : overlayDirectories) { if (resOverlayDir != null && resOverlayDir.exists()) { commands.add("-S"); commands.add(resOverlayDir.getAbsolutePath()); } } if (combinedRes.exists()) { commands.add("-S"); commands.add(combinedRes.getAbsolutePath()); } // Use the combined assets. // Indeed, aapt does not support several -A arguments. if (combinedAssets.exists()) { commands.add("-A"); commands.add(combinedAssets.getAbsolutePath()); } commands.add("-I"); commands.add(androidJar.getAbsolutePath()); commands.add("-F"); commands.add(outputFile.getAbsolutePath()); if (StringUtils.isNotBlank(configurations)) { commands.add("-c"); commands.add(configurations); } getLog().info(getAndroidSdk().getPathForTool("aapt") + " " + commands.toString()); try { executor.executeCommand( getAndroidSdk().getPathForTool("aapt"), commands, project.getBasedir(), false); } catch (ExecutionException e) { throw new MojoExecutionException("", e); } }