/******************************************************************************* * Copyright (c) 2008, 2011 Sonatype Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sonatype Inc. - initial API and implementation *******************************************************************************/ package com.simpligility.maven.plugins.android.common; import com.android.SdkConstants; import com.google.common.io.PatternFilenameFilter; import com.simpligility.maven.plugins.android.phase09package.AarMojo; import com.simpligility.maven.plugins.android.phase09package.ApklibMojo; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.UnArchiver; import org.codehaus.plexus.archiver.zip.ZipUnArchiver; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.console.ConsoleLogger; import java.io.File; import java.io.IOException; import static com.simpligility.maven.plugins.android.common.AndroidExtension.AAR; import static com.simpligility.maven.plugins.android.common.AndroidExtension.APK; /** * Provides convenience methods for unpacking Android libraries so that their contents can be used in the build. */ public final class UnpackedLibHelper { private final ArtifactResolverHelper artifactResolverHelper; private final Logger log; // ${project.build.directory}/unpacked-libs private final File unpackedLibsDirectory; public UnpackedLibHelper( ArtifactResolverHelper artifactResolverHelper, MavenProject project, Logger log, File unpackedLibsFolder ) { this.artifactResolverHelper = artifactResolverHelper; if ( unpackedLibsFolder != null ) { // if absolute then use it. // if relative then make it relative to the basedir of the project. this.unpackedLibsDirectory = unpackedLibsFolder.isAbsolute() ? unpackedLibsFolder : new File( project.getBasedir(), unpackedLibsFolder.getPath() ); } else { // If not specified then default to target/unpacked-libs final File targetFolder = new File( project.getBuild().getDirectory() ); this.unpackedLibsDirectory = new File( targetFolder, "unpacked-libs" ); } this.log = log; } public void extractApklib( Artifact apklibArtifact ) throws MojoExecutionException { final File apkLibFile = artifactResolverHelper.resolveArtifactToFile( apklibArtifact ); if ( apkLibFile.isDirectory() ) { log.warn( "The apklib artifact points to '" + apkLibFile + "' which is a directory; skipping unpacking it." ); return; } final UnArchiver unArchiver = new ZipUnArchiver( apkLibFile ) { @Override protected Logger getLogger() { return new ConsoleLogger( log.getThreshold(), "dependencies-unarchiver" ); } }; final File apklibDirectory = getUnpackedLibFolder( apklibArtifact ); apklibDirectory.mkdirs(); unArchiver.setDestDirectory( apklibDirectory ); log.debug( "Extracting APKLIB to " + apklibDirectory ); try { unArchiver.extract(); } catch ( ArchiverException e ) { throw new MojoExecutionException( "ArchiverException while extracting " + apklibDirectory + ". Message: " + e.getLocalizedMessage(), e ); } } public void extractAarLib( Artifact aarArtifact ) throws MojoExecutionException { final File aarFile = artifactResolverHelper.resolveArtifactToFile( aarArtifact ); if ( aarFile.isDirectory() ) { log.warn( "The aar artifact points to '" + aarFile + "' which is a directory; skipping unpacking it." ); return; } final UnArchiver unArchiver = new ZipUnArchiver( aarFile ) { @Override protected Logger getLogger() { return new ConsoleLogger( log.getThreshold(), "dependencies-unarchiver" ); } }; final File aarDirectory = getUnpackedLibFolder( aarArtifact ); aarDirectory.mkdirs(); unArchiver.setDestDirectory( aarDirectory ); log.debug( "Extracting AAR to " + aarDirectory ); try { unArchiver.extract(); } catch ( ArchiverException e ) { throw new MojoExecutionException( "ArchiverException while extracting " + aarDirectory.getAbsolutePath() + ". Message: " + e.getLocalizedMessage(), e ); } // Move native libraries from libs to jni folder for legacy AARs. // This ensures backward compatibility with older AARs where libs are in "libs" folder. final File jniFolder = new File( aarDirectory, AarMojo.NATIVE_LIBRARIES_FOLDER ); final File libsFolder = new File( aarDirectory, ApklibMojo.NATIVE_LIBRARIES_FOLDER ); if ( !jniFolder.exists() && libsFolder.isDirectory() && libsFolder.exists() ) { String[] natives = libsFolder.list( new PatternFilenameFilter( "^.*(?<!(?i)\\.jar)$" ) ); if ( natives.length > 0 ) { log.debug( "Moving AAR native libraries from libs to jni folder" ); for ( String nativeLibPath : natives ) { try { FileUtils.moveToDirectory( new File( libsFolder, nativeLibPath ), jniFolder, true ); } catch ( IOException e ) { throw new MojoExecutionException( "Could not move native libraries from " + libsFolder, e ); } } } } } public File getArtifactToFile( Artifact artifact ) throws MojoExecutionException { final File artifactFile = artifactResolverHelper.resolveArtifactToFile( artifact ); return artifactFile; } public File getUnpackedLibsFolder() { return unpackedLibsDirectory; } public File getUnpackedLibFolder( Artifact artifact ) { return new File( unpackedLibsDirectory.getAbsolutePath(), getShortenedGroupId( artifact.getGroupId() ) + "_" + artifact.getArtifactId() + "_" + artifact.getBaseVersion() ); } public File getUnpackedClassesJar( Artifact artifact ) { return new File( getUnpackedLibFolder( artifact ), SdkConstants.FN_CLASSES_JAR ); } public File getUnpackedApkLibSourceFolder( Artifact artifact ) { return new File( getUnpackedLibFolder( artifact ), "src" ); } public File getUnpackedLibResourceFolder( Artifact artifact ) { return new File( getUnpackedLibFolder( artifact ), "res" ); } public File getUnpackedLibAssetsFolder( Artifact artifact ) { return new File( getUnpackedLibFolder( artifact ), "assets" ); } /** * @param artifact Android dependency that is being referenced. * @return Folder where the unpacked native libraries are located. * @see http://tools.android.com/tech-docs/new-build-system/aar-format */ public File getUnpackedLibNativesFolder( Artifact artifact ) { if ( AAR.equals( artifact.getType() ) ) { return new File( getUnpackedLibFolder( artifact ), AarMojo.NATIVE_LIBRARIES_FOLDER ); } else { return new File( getUnpackedLibFolder( artifact ), ApklibMojo.NATIVE_LIBRARIES_FOLDER ); } } public File getJarFileForApk( Artifact artifact ) { final String fileName = artifact.getFile().getName(); final String modifiedFileName = fileName.substring( 0, fileName.lastIndexOf( "." ) ) + ".jar"; return new File( artifact.getFile().getParentFile(), modifiedFileName ); } /** * @param groupId An a dot separated groupId (eg org.apache.maven) * @return A shortened (and potentially non-unique) version of the groupId, that consists of the first letter * of each part of the groupId. Eg oam for org.apache.maven */ private String getShortenedGroupId( String groupId ) { final String[] parts = groupId.split( "\\." ); final StringBuilder sb = new StringBuilder(); for ( final String part : parts ) { sb.append( part.charAt( 0 ) ); } return sb.toString(); } /** * @return True if this project constructs an APK as opposed to an AAR or APKLIB. */ public boolean isAPKBuild( MavenProject project ) { return APK.equals( project.getPackaging() ); } }