All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jayway.maven.plugins.android.standalonemojos.ManifestUpdateMojo Maven / Gradle / Ivy

There is a newer version: 4.0.0-rc.2
Show newest version
package com.jayway.maven.plugins.android.standalonemojos;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import com.jayway.maven.plugins.android.configuration.Manifest;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import com.jayway.maven.plugins.android.AbstractAndroidMojo;
import com.jayway.maven.plugins.android.common.AndroidExtension;

/**
 * Updates various version attributes present in the AndroidManifest.xml file.
 * 

* You can configure this mojo to update the following manifest attributes: *

*

* android:versionName on the manifest element. * android:versionCode on the manifest element. * android:sharedUserId on the manifest element. * android:debuggable on the application element. *

*

* Note: This process will reformat the AndroidManifest.xml per JAXP {@link Transformer} defaults if updates are made to the manifest. *

* You can configure attributes in the plugin configuration like so *

 *   <plugin>
 *     <groupId>com.jayway.maven.plugins.android.generation2</groupId>
 *     <artifactId>android-maven-plugin</artifactId>
 *     <executions>
 *       <execution>
 *         <id>update-manifest</id>
 *         <goals>
 *           <goal>manifest-update</goal>
 *         </goals>
 *         <configuration>
 *           <manifest>
 *             <versionName></versionName>
 *             <versionCode>123</versionCode>
 *             <versionCodeAutoIncrement>true|false</versionCodeAutoIncrement>
 *             <versionCodeUpdateFromVersion>true|false</versionCodeUpdateFromVersion>
 *             <sharedUserId>anId</sharedUserId>
 *             <debuggable>true|false</debuggable>
 *           </manifest>
 *         </configuration>
 *       </execution>
 *     </executions>
 *   </plugin>
 * 
* or use properties set in the pom or settings file or supplied as parameter. All parameters follow a android * .manifest.* naming convention. *

* * @author [email protected] * @author [email protected] * @author Manfred Moser * @goal manifest-update * @requiresProject true * @phase process-resources * */ public class ManifestUpdateMojo extends AbstractAndroidMojo { private static final String ATTR_VERSION_NAME = "android:versionName"; private static final String ATTR_VERSION_CODE = "android:versionCode"; private static final String ATTR_SHARED_USER_ID = "android:sharedUserId"; private static final String ATTR_DEBUGGABLE = "android:debuggable"; private static final String ELEM_APPLICATION = "application"; /** * The container for all the manifest update related configuration. * * @parameter */ private Manifest manifest; /** * Update the android:versionName with the specified parameter. If left empty it * will use the version number of the project. * * @parameter expression="${android.manifest.versionName}" default-value="${project.version}" */ protected String versionName; /** * Update the android:versionCode attribute with the specified parameter. * * @parameter expression="${android.manifest.versionCode}" */ protected Integer versionCode; /** * Auto increment the android:versionCode attribute with each build. * * @parameter expression="${android.manifest.versionCodeAutoincrement}" default-value="false" */ private boolean versionCodeAutoIncrement = false; /** * Update the android:versionCode attribute automatically from the project version * e.g 3.0.1 will become version code 301. As described in this blog post * http://www.simpligility.com/2010/11/release-version-management-for-your-android-application/ * but done without using resource filtering. * * @parameter expression="${android.manifest.versionCodeUpdateFromVersion} default-value="false" */ protected Boolean versionCodeUpdateFromVersion = false; /** * Update the android:sharedUserId attribute with the specified parameter. * * @parameter expression="${android.manifest.sharedUserId}" */ protected String sharedUserId; /** * Update the android:debuggable attribute with the specified parameter. * * @parameter expression="${android.manifest.debuggable}" */ protected Boolean debuggable; private String parsedVersionName; private Integer parsedVersionCode; private boolean parsedVersionCodeAutoIncrement; private Boolean parsedVersionCodeUpdateFromVersion; private String parsedSharedUserId; private Boolean parsedDebuggable; public void execute() throws MojoExecutionException, MojoFailureException { if (!AndroidExtension.isAndroidPackaging(project.getPackaging())) { return; // skip, not an android project. } if (androidManifestFile == null) { return; // skip, no androidmanifest.xml defined (rare case) } parseConfiguration(); getLog().info("Attempting to update manifest " + androidManifestFile); getLog().debug(" versionName=" + parsedVersionName); getLog().debug(" versionCode=" + parsedVersionCode); getLog().debug(" versionCodeAutoIncrement=" + parsedVersionCodeAutoIncrement); getLog().debug(" versionCodeUpdateFromVersion=" + parsedVersionCodeUpdateFromVersion); getLog().debug(" sharedUserId=" + parsedSharedUserId); getLog().debug(" debuggable=" + parsedDebuggable); if (!androidManifestFile.exists()) { return; // skip, no AndroidManifest.xml file found. } try { updateManifest(androidManifestFile); } catch (IOException e) { throw new MojoFailureException("XML I/O error: " + androidManifestFile, e); } catch (ParserConfigurationException e) { throw new MojoFailureException("Unable to prepare XML parser", e); } catch (SAXException e) { throw new MojoFailureException("Unable to parse XML: " + androidManifestFile, e); } catch (TransformerException e) { throw new MojoFailureException("Unable write XML: " + androidManifestFile, e); } } private void parseConfiguration() { // manifest element found in plugin config in pom if (manifest != null) { parsedVersionName = manifest.getVersionName(); parsedVersionCode = manifest.getVersionCode(); parsedVersionCodeAutoIncrement = manifest.isVersionCodeAutoIncrement(); parsedVersionCodeUpdateFromVersion = manifest.getVersionCodeUpdateFromVersion(); parsedSharedUserId = manifest.getSharedUserId(); parsedDebuggable = manifest.getDebuggable(); } else { parsedVersionName = versionName; parsedVersionCode = versionCode; parsedVersionCodeAutoIncrement = versionCodeAutoIncrement; parsedVersionCodeUpdateFromVersion = versionCodeUpdateFromVersion; parsedSharedUserId = sharedUserId; parsedDebuggable = debuggable; } } /** * Read manifest using JAXP */ private Document readManifest(File manifestFile) throws IOException, ParserConfigurationException, SAXException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(manifestFile); return doc; } /** * Write manifest using JAXP transformer */ private void writeManifest(File manifestFile, Document doc) throws IOException, TransformerException { TransformerFactory xfactory = TransformerFactory.newInstance(); Transformer xformer = xfactory.newTransformer(); xformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); Source source = new DOMSource(doc); FileWriter writer = null; try { writer = new FileWriter(manifestFile, false); String xmldecl = String.format("%n", doc.getXmlVersion(), doc.getXmlEncoding()); writer.write(xmldecl); Result result = new StreamResult(writer); xformer.transform(source, result); } finally { IOUtils.closeQuietly(writer); } } public void updateManifest(File manifestFile) throws IOException, ParserConfigurationException, SAXException, TransformerException, MojoFailureException { Document doc = readManifest(manifestFile); Element manifestElement = doc.getDocumentElement(); boolean dirty = false; if (StringUtils.isEmpty(parsedVersionName)) { // default to ${project.version} parsedVersionName = project.getVersion(); } Attr versionNameAttrib = manifestElement.getAttributeNode(ATTR_VERSION_NAME); if (versionNameAttrib == null || !StringUtils.equals(parsedVersionName, versionNameAttrib.getValue())) { getLog().info("Setting " + ATTR_VERSION_NAME +" to " + parsedVersionName); manifestElement.setAttribute(ATTR_VERSION_NAME, parsedVersionName); dirty = true; } if ((parsedVersionCodeAutoIncrement && parsedVersionCode != null) || (parsedVersionCodeUpdateFromVersion && parsedVersionCode != null) || (parsedVersionCodeAutoIncrement && parsedVersionCodeUpdateFromVersion)) { throw new MojoFailureException("versionCodeAutoIncrement, versionCodeUpdateFromVersion and versionCode " + "are mutual exclusive. They cannot be specified at the same time. " + "Please specify either versionCodeAutoIncrement, versionCodeUpdateFromVersion or versionCode!"); } if (parsedVersionCodeAutoIncrement) { Attr versionCode = manifestElement.getAttributeNode(ATTR_VERSION_CODE); int currentVersionCode = 0; if (versionCode != null) { currentVersionCode = NumberUtils.toInt(versionCode.getValue(), 0); } currentVersionCode++; manifestElement.setAttribute(ATTR_VERSION_CODE, String.valueOf(currentVersionCode)); dirty = true; } if (parsedVersionCodeUpdateFromVersion) { String verString = project.getVersion(); getLog().debug("Generating versionCode for " + verString); ArtifactVersion artifactVersion = new DefaultArtifactVersion(verString); String verCode = Integer.toString(artifactVersion.getMajorVersion()) + Integer.toString(artifactVersion.getMinorVersion()) + Integer.toString(artifactVersion.getIncrementalVersion()); getLog().info("Setting " + ATTR_VERSION_CODE + " to " + verCode); manifestElement.setAttribute(ATTR_VERSION_CODE, verCode); dirty = true; } if (parsedVersionCode != null) { Attr versionCodeAttr = manifestElement.getAttributeNode(ATTR_VERSION_CODE); int currentVersionCode = 0; if (versionCodeAttr != null) { currentVersionCode = NumberUtils.toInt(versionCodeAttr.getValue(), 0); } if (currentVersionCode != parsedVersionCode) { getLog().info("Setting " + ATTR_VERSION_CODE + " to " + parsedVersionCode); manifestElement.setAttribute(ATTR_VERSION_CODE, String.valueOf(parsedVersionCode)); dirty = true; } } if (!StringUtils.isEmpty(parsedSharedUserId)) { Attr sharedUserIdAttrib = manifestElement.getAttributeNode(ATTR_SHARED_USER_ID); if (sharedUserIdAttrib == null || !StringUtils.equals(parsedSharedUserId, sharedUserIdAttrib.getValue())) { getLog().info("Setting " + ATTR_SHARED_USER_ID +" to " + parsedSharedUserId); manifestElement.setAttribute(ATTR_SHARED_USER_ID, parsedSharedUserId); dirty = true; } } if (parsedDebuggable != null) { NodeList appElems = manifestElement.getElementsByTagName(ELEM_APPLICATION); // Update all application nodes. Not sure whether there will ever be more than one. for (int i = 0; i < appElems.getLength(); ++i) { Node node = appElems.item(i); getLog().info("Testing if node " + node.getNodeName() + " is application"); if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element)node; Attr debuggableAttrib = element.getAttributeNode(ATTR_DEBUGGABLE); if (debuggableAttrib == null || debuggable != BooleanUtils.toBoolean(debuggableAttrib.getValue())) { getLog().info("Setting " + ATTR_DEBUGGABLE + " to " + parsedDebuggable); element.setAttribute(ATTR_DEBUGGABLE, String.valueOf(parsedDebuggable)); dirty = true; } } } } if (dirty) { if (!manifestFile.delete()) { getLog().warn("Could not remove old " + manifestFile); } getLog().info("Made changes to manifest file, updating " + manifestFile); writeManifest(manifestFile, doc); } else { getLog().info("No changes found to write to manifest file"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy