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

com.simpligility.maven.plugins.android.AndroidSdk Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show 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.sdklib.AndroidTargetHash;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkManager;
import com.android.sdklib.repository.FullRevision;
import com.android.utils.NullLogger;
import org.apache.maven.plugin.MojoExecutionException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import org.codehaus.plexus.interpolation.os.Os;

/**
 * Represents an Android SDK.
 * 
 * @author [email protected]
 * @author Manfred Moser 
 */
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 = "22";
    /**
     * 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 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 SdkManager sdkManager;
    private int sdkMajorVersion;
    private String buildToolsVersion;

    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;

        if ( sdkPath != null )
        {
            sdkManager = SdkManager.createManager( sdkPath.getPath(), new NullLogger() );
            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.getTargetFromHashString( hashString );

            if ( target != 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.getTargets() )
        {
            if ( t.isPlatform() && t.getVersionName().equals( apiLevel ) )
            {
                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 );
    }

    /**
     * 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( "lint" + ext( ".bat", "" ) );
    }

    /**
     * Get the android monkey runner path.
     * 
     * @return
     */
    public String getMonkeyRunnerPath()
    {
        return getPathForTool( "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()
    {
        return getPathForTool( SdkConstants.androidCmdName() );
    }

    /**
     * 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.getBuildTool( FullRevision.parseRevision( buildToolsVersion ) );
            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();
        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 );
    }

    /**
     * Returns the mainDexClasses script file, based on this SDK and OS.
     * Assumes that the script is in build-tools\VERSION\ directory.
     * 
     * NOTE: This file is found in version 21.1.1+ of build-tools.  
     * 
     * @return mainDexClasses file
     * @throws MojoExecutionException when the file is not found 
     */
    public File getMainDexClasses() throws MojoExecutionException 
    {
        final File location = getBuildToolInfo().getLocation();
        String mainDexClassesScript = "mainDexClasses";   
        if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) 
        {
            mainDexClassesScript += ".bat";   
        }               
        File mainDexClasses = new File( location, mainDexClassesScript );
        if ( !mainDexClasses.exists() ) 
        {
            throw new MojoExecutionException( "No " + mainDexClassesScript + " found in " + location );
        }
        return mainDexClasses;
    }

    /**
     * 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 );
        }
        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;
            for ( IAndroidTarget target:  sdkManager.getTargets() )
            {
                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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy