com.simpligility.maven.plugins.android.AndroidSdk Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of android-maven-plugin Show documentation
Show all versions of android-maven-plugin Show documentation
Maven Plugin for Android Development
The newest version!
/*
* Copyright (C) 2009, 2010 Jayway AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.simpligility.maven.plugins.android;
import com.android.SdkConstants;
import com.android.annotations.Nullable;
import com.android.repository.Revision;
import com.android.sdklib.AndroidTargetHash;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.repository.AndroidSdkHandler;
import com.android.sdklib.repository.targets.AndroidTargetManager;
import org.apache.maven.plugin.MojoExecutionException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* Represents an Android SDK.
*
* @author [email protected]
* @author Manfred Moser - [email protected]
*/
public class AndroidSdk
{
/**
* the default API level for the SDK used as a fall back if none is supplied,
* should ideally point to the latest available version
*/
private static final String DEFAULT_ANDROID_API_LEVEL = "23";
/**
* property file in each platform folder with details about platform.
*/
private static final String SOURCE_PROPERTIES_FILENAME = "source.properties";
/**
* property name for the sdk tools revision in sdk/tools/lib source.properties
*/
private static final String SDK_TOOLS_REVISION_PROPERTY = "Pkg.Revision";
/**
* folder name for the sdk sub folder that contains the different platform versions.
*/
private static final String PLATFORMS_FOLDER_NAME = "platforms";
private static final String BIN_FOLDER_NAME_IN_TOOLS = "bin";
private static final String PARAMETER_MESSAGE = "Please provide a proper Android SDK directory path as "
+ "configuration parameter ... in the plugin . As an alternative,"
+ " you may add the parameter to commandline: -Dandroid.sdk.path=... or set environment variable "
+ AbstractAndroidMojo.ENV_ANDROID_HOME + ".";
private final File sdkPath;
private File platformToolsPath;
private File toolsPath;
private final IAndroidTarget androidTarget;
private AndroidSdkHandler sdkManager;
private int sdkMajorVersion;
private String buildToolsVersion;
private ProgressIndicatorImpl progressIndicator;
public AndroidSdk( File sdkPath, String apiLevel )
{
this( sdkPath, apiLevel, null );
}
public AndroidSdk( File sdkPath, String apiLevel, @Nullable String buildToolsVersion )
{
this.sdkPath = sdkPath;
this.buildToolsVersion = buildToolsVersion;
this.progressIndicator = new ProgressIndicatorImpl();
if ( sdkPath != null )
{
sdkManager = AndroidSdkHandler.getInstance( sdkPath );
platformToolsPath = new File( sdkPath, SdkConstants.FD_PLATFORM_TOOLS );
toolsPath = new File( sdkPath, SdkConstants.FD_TOOLS );
if ( sdkManager == null )
{
throw invalidSdkException( sdkPath, apiLevel );
}
}
loadSDKToolsMajorVersion();
if ( apiLevel == null )
{
apiLevel = DEFAULT_ANDROID_API_LEVEL;
}
androidTarget = findPlatformByApiLevel( apiLevel );
if ( androidTarget == null )
{
throw invalidSdkException( sdkPath, apiLevel );
}
}
private InvalidSdkException invalidSdkException( File sdkPath, String platformOrApiLevel )
{
throw new InvalidSdkException( "Invalid SDK: Platform/API level " + platformOrApiLevel
+ " not available. This command should give you all you need:\n" + sdkPath.getAbsolutePath()
+ File.separator + "tools" + File.separator + "android update sdk --no-ui --obsolete --force" );
}
private IAndroidTarget findPlatformByApiLevel( String apiLevel )
{
// try find by api level first
AndroidVersion version = null;
try
{
version = new AndroidVersion( apiLevel );
String hashString = AndroidTargetHash.getPlatformHashString( version );
IAndroidTarget target = sdkManager.getAndroidTargetManager( progressIndicator )
.getTargetFromHashString( hashString, progressIndicator );
// SdkManager may return a non-null IAndroidTarget that references nothing.
// I suspect it points to an SDK that has been removed.
if ( target != null && target.getLocation() != null )
{
return target;
}
}
catch ( AndroidVersion.AndroidVersionException ignore )
{
throw new InvalidSdkException( "Error AndroidVersion: " + ignore.getMessage() );
}
// fallback to searching for platform on standard Android platforms (isPlatform() is true)
for ( IAndroidTarget t: sdkManager.getAndroidTargetManager( null ).getTargets( null ) )
{
if ( t.isPlatform() && apiLevel.equals( t.getVersionName() ) )
{
return t;
}
}
return null;
}
private void assertPathIsDirectory( final File path )
{
if ( path == null )
{
throw new InvalidSdkException( PARAMETER_MESSAGE );
}
if ( !path.isDirectory() )
{
throw new InvalidSdkException( "Path \"" + path + "\" is not a directory. " + PARAMETER_MESSAGE );
}
}
/**
* Get the aapt tool path.
*
* @return
*/
public String getAaptPath()
{
return getPathForBuildTool( BuildToolInfo.PathId.AAPT );
}
/**
* Get the aild tool path
* @return
*/
public String getAidlPath()
{
return getPathForBuildTool( BuildToolInfo.PathId.AIDL );
}
/**
* Get the path for dx.jar
* @return
*/
public String getDxJarPath()
{
return getPathForBuildTool( BuildToolInfo.PathId.DX_JAR );
}
/**
* @return the path to the dx.jar
*/
public String getD8JarPath()
{
final File pathToDexJar = new File( getPathForBuildTool( BuildToolInfo.PathId.DX_JAR ) );
final File pathToD8Jar = new File( pathToDexJar.getParent(), "d8.jar" );
return pathToD8Jar.getAbsolutePath();
}
/**
* Get the path for proguard.jar
* @return
*/
public String getProguardJarPath()
{
File directory = new File( getToolsPath(), "proguard" + File.separator + "lib" + File.separator );
File proguardJar = new File( directory, "proguard.jar" );
if ( proguardJar.exists() )
{
return proguardJar.getAbsolutePath();
}
throw new InvalidSdkException( "Cannot find " + proguardJar );
}
/**
* Get the path for shrinkedAndroid.jar
* @return
*/
public String getShrinkedAndroidJarPath()
{
File shrinkedAndroidJar = new File( getBuildToolsLibDirectoryPath(), "shrinkedAndroid.jar" );
if ( shrinkedAndroidJar.exists() )
{
return shrinkedAndroidJar.getAbsolutePath();
}
throw new InvalidSdkException( "Cannot find " + shrinkedAndroidJar );
}
/**
* Get the path for build-tools lib directory
* @return
*/
public String getBuildToolsLibDirectoryPath()
{
File buildToolsLib = new File( getBuildToolInfo().getLocation(), "lib" );
if ( buildToolsLib.exists() )
{
return buildToolsLib.getAbsolutePath();
}
throw new InvalidSdkException( "Cannot find " + buildToolsLib );
}
/**
* Get the path for mainDexClasses.rules
* @return
*/
public String getMainDexClassesRulesPath()
{
File mainDexClassesRules = new File( getBuildToolInfo().getLocation(),
"mainDexClasses.rules" );
if ( mainDexClassesRules.exists() )
{
return mainDexClassesRules.getAbsolutePath();
}
throw new InvalidSdkException( "Cannot find " + mainDexClassesRules );
}
public void assertThatBuildToolsVersionIsAtLeast( String version, String feature )
throws InvalidSdkException, NumberFormatException
{
if ( getBuildToolInfo().getRevision().
compareTo( Revision.parseRevision( version ) ) < 0 )
{
throw new InvalidSdkException( "Version of build tools must be at least "
+ version + " for " + feature + " to work" );
}
}
/**
* Get the android debug tool path (adb).
*
* @return
*/
public String getAdbPath()
{
return getPathForPlatformTool( SdkConstants.FN_ADB );
}
/**
* Get the android zipalign path.
*
* @return
*/
public String getZipalignPath()
{
return getPathForBuildTool( BuildToolInfo.PathId.ZIP_ALIGN );
}
/**
* Get the android lint path.
*
* @return
*/
public String getLintPath()
{
return getPathForTool( BIN_FOLDER_NAME_IN_TOOLS + "/" + "lint" + ext( ".bat", "" ) );
}
/**
* Get the android monkey runner path.
*
* @return
*/
public String getMonkeyRunnerPath()
{
return getPathForTool( BIN_FOLDER_NAME_IN_TOOLS + "/" + "monkeyrunner" + ext( ".bat", "" ) );
}
/**
* Get the apkbuilder path.
*
* @return
*/
public String getApkBuilderPath()
{
return getPathForTool( "apkbuilder" + ext( ".bat", "" ) );
}
/**
* Get the android tool path.
*
* @return
*/
public String getAndroidPath()
{
String cmd = "android";
String ext = SdkConstants.currentPlatform() == 2 ? ".bat" : "";
return getPathForTool( cmd + ext );
}
/**
* Get the path to the tools directory.
* @return
*/
public File getToolsPath()
{
return toolsPath;
}
private String getPathForBuildTool( BuildToolInfo.PathId pathId )
{
return getBuildToolInfo().getPath( pathId );
}
private BuildToolInfo getBuildToolInfo()
{
//First we use the build tools specified in the pom file
if ( buildToolsVersion != null && !buildToolsVersion.equals( "" ) )
{
BuildToolInfo buildToolInfo = sdkManager.getBuildToolInfo( Revision.parseRevision( buildToolsVersion ),
progressIndicator );
if ( buildToolInfo != null )
{
return buildToolInfo;
}
//Since we cannot find the build tool specified by the user we make it fail
// instead of using the latest build tool version
throw new InvalidSdkException( "Invalid SDK: Build-tools " + buildToolsVersion + " not found."
+ " Check your Android SDK to install the build tools " + buildToolsVersion );
}
if ( androidTarget != null )
{
BuildToolInfo buildToolInfo = androidTarget.getBuildToolInfo();
if ( buildToolInfo != null )
{
return buildToolInfo;
}
}
// if no valid target is defined, or it has no build tools installed, try to use the latest
BuildToolInfo latestBuildToolInfo = sdkManager.getLatestBuildTool( progressIndicator, true );
if ( latestBuildToolInfo == null )
{
throw new InvalidSdkException( "Invalid SDK: Build-tools not found. Check the content of '"
+ sdkPath.getAbsolutePath() + File.separator + "build-tools', or run '"
+ sdkPath.getAbsolutePath() + File.separator + "tools" + File.separator
+ "android sdk' to install them" );
}
return latestBuildToolInfo;
}
private String getPathForPlatformTool( String tool )
{
return new File( platformToolsPath, tool ).getAbsolutePath();
}
private String getPathForTool( String tool )
{
return new File( toolsPath, tool ).getAbsolutePath();
}
private static String ext( String windowsExtension, String nonWindowsExtension )
{
if ( SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS )
{
return windowsExtension;
}
else
{
return nonWindowsExtension;
}
}
/**
* Returns the complete path for framework.aidl
, based on this SDK.
*
* @return the complete path as a String
, including the filename.
*/
public String getPathForFrameworkAidl()
{
return androidTarget.getPath( IAndroidTarget.ANDROID_AIDL );
}
/**
* Resolves the android.jar from this SDK.
*
* @return a File
pointing to the android.jar file.
* @throws org.apache.maven.plugin.MojoExecutionException
* if the file can not be resolved.
*/
public File getAndroidJar() throws MojoExecutionException
{
final String androidJarPath = androidTarget.getPath( IAndroidTarget.ANDROID_JAR );
if ( androidJarPath == null )
{
throw new MojoExecutionException( "No AndroidJar found for " + androidTarget.getLocation() );
}
return new File ( androidJarPath );
}
/**
* Resolves the path for this SDK.
*
* @return a File
pointing to the SDk Directory.
* @throws org.apache.maven.plugin.MojoExecutionException
* if the file can not be resolved.
*/
public File getSdkPath() throws MojoExecutionException
{
if ( sdkPath.exists() )
{
return sdkPath;
}
throw new MojoExecutionException( "Can't find the SDK directory : " + sdkPath.getAbsolutePath() );
}
/**
* This method returns the previously specified version. However, if none have been specified it returns the
* "latest" version.
*/
public File getPlatform()
{
assertPathIsDirectory( sdkPath );
final File platformsDirectory = new File( sdkPath, PLATFORMS_FOLDER_NAME );
assertPathIsDirectory( platformsDirectory );
final File platformDirectory;
if ( androidTarget == null )
{
IAndroidTarget latestTarget = null;
AndroidTargetManager targetManager = sdkManager.getAndroidTargetManager( progressIndicator );
for ( IAndroidTarget target: targetManager.getTargets( progressIndicator ) )
{
if ( target.isPlatform() )
{
if ( latestTarget == null
|| target.getVersion().getApiLevel() > latestTarget.getVersion().getApiLevel() )
{
latestTarget = target;
}
}
}
platformDirectory = new File ( latestTarget.getLocation() );
}
else
{
platformDirectory = new File( androidTarget.getLocation() );
}
assertPathIsDirectory( platformDirectory );
return platformDirectory;
}
/**
* Loads the SDK Tools version
*/
private void loadSDKToolsMajorVersion()
{
File propFile = new File( sdkPath, "tools/" + SOURCE_PROPERTIES_FILENAME );
Properties properties = new Properties();
try
{
properties.load( new FileInputStream( propFile ) );
}
catch ( IOException e )
{
throw new InvalidSdkException( "Error reading " + propFile.getAbsoluteFile() );
}
if ( properties.containsKey( SDK_TOOLS_REVISION_PROPERTY ) )
{
try
{
String versionString = properties.getProperty( SDK_TOOLS_REVISION_PROPERTY );
String majorVersion;
if ( versionString.matches( ".*[\\.| ].*" ) )
{
String[] versions = versionString.split( "[\\.| ]" );
majorVersion = versions[ 0 ];
}
else
{
majorVersion = versionString;
}
sdkMajorVersion = Integer.parseInt( majorVersion );
}
catch ( NumberFormatException e )
{
throw new InvalidSdkException( "Error - The property '" + SDK_TOOLS_REVISION_PROPERTY
+ "' in the SDK source.properties file number is not an Integer: "
+ properties.getProperty( SDK_TOOLS_REVISION_PROPERTY ) );
}
}
}
/**
* Returns the version of the SDK Tools.
*
* @return
*/
public int getSdkMajorVersion()
{
return sdkMajorVersion;
}
}