aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java448
1 files changed, 0 insertions, 448 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
deleted file mode 100644
index 56e0c0938..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
- *
- * 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.android.ide.eclipse.adt.internal.project;
-
-import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_SDK;
-
-import com.android.SdkConstants;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AndroidPrintStream;
-import com.android.ide.eclipse.adt.internal.build.BuildHelper;
-import com.android.ide.eclipse.adt.internal.build.DexException;
-import com.android.ide.eclipse.adt.internal.build.NativeLibInJarException;
-import com.android.ide.eclipse.adt.internal.build.ProguardExecException;
-import com.android.ide.eclipse.adt.internal.build.ProguardResultException;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.ide.eclipse.adt.io.IFileWrapper;
-import com.android.sdklib.BuildToolInfo;
-import com.android.sdklib.build.ApkCreationException;
-import com.android.sdklib.build.DuplicateFileException;
-import com.android.sdklib.internal.project.ProjectProperties;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.xml.AndroidManifest;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-
-/**
- * Export helper to export release version of APKs.
- */
-public final class ExportHelper {
- private static final String HOME_PROPERTY = "user.home"; //$NON-NLS-1$
- private static final String HOME_PROPERTY_REF = "${" + HOME_PROPERTY + '}'; //$NON-NLS-1$
- private static final String SDK_PROPERTY_REF = "${" + PROPERTY_SDK + '}'; //$NON-NLS-1$
- private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$
-
- /**
- * Exports a release version of the application created by the given project.
- * @param project the project to export
- * @param outputFile the file to write
- * @param key the key to used for signing. Can be null.
- * @param certificate the certificate used for signing. Can be null.
- * @param monitor progress monitor
- * @throws CoreException if an error occurs
- */
- public static void exportReleaseApk(IProject project, File outputFile, PrivateKey key,
- X509Certificate certificate, IProgressMonitor monitor) throws CoreException {
-
- // the export, takes the output of the precompiler & Java builders so it's
- // important to call build in case the auto-build option of the workspace is disabled.
- // Also enable dependency building to make sure everything is up to date.
- // However do not package the APK since we're going to do it manually here, using a
- // different output location.
- ProjectHelper.compileInReleaseMode(project, monitor);
-
- // if either key or certificate is null, ensure the other is null.
- if (key == null) {
- certificate = null;
- } else if (certificate == null) {
- key = null;
- }
-
- try {
- // check if the manifest declares debuggable as true. While this is a release build,
- // debuggable in the manifest will override this and generate a debug build
- IResource manifestResource = project.findMember(SdkConstants.FN_ANDROID_MANIFEST_XML);
- if (manifestResource.getType() != IResource.FILE) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- String.format("%1$s missing.", SdkConstants.FN_ANDROID_MANIFEST_XML)));
- }
-
- IFileWrapper manifestFile = new IFileWrapper((IFile) manifestResource);
- boolean debugMode = AndroidManifest.getDebuggable(manifestFile);
-
- AndroidPrintStream fakeStream = new AndroidPrintStream(null, null, new OutputStream() {
- @Override
- public void write(int b) throws IOException {
- // do nothing
- }
- });
-
- ProjectState projectState = Sdk.getProjectState(project);
-
- // get the jumbo mode option
- String forceJumboStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_FORCEJUMBO);
- Boolean jumbo = Boolean.valueOf(forceJumboStr);
-
- String dexMergerStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_DISABLE_MERGER);
- Boolean dexMerger = Boolean.valueOf(dexMergerStr);
-
- BuildToolInfo buildToolInfo = getBuildTools(projectState);
-
- BuildHelper helper = new BuildHelper(
- projectState,
- buildToolInfo,
- fakeStream, fakeStream,
- jumbo.booleanValue(),
- dexMerger.booleanValue(),
- debugMode, false /*verbose*/,
- null /*resourceMarker*/);
-
- // get the list of library projects
- List<IProject> libProjects = projectState.getFullLibraryProjects();
-
- // Step 1. Package the resources.
-
- // tmp file for the packaged resource file. To not disturb the incremental builders
- // output, all intermediary files are created in tmp files.
- File resourceFile = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_RES);
- resourceFile.deleteOnExit();
-
- // Make sure the PNG crunch cache is up to date
- helper.updateCrunchCache();
-
- // get the merged manifest
- IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project);
- IFile mergedManifestFile = androidOutputFolder.getFile(
- SdkConstants.FN_ANDROID_MANIFEST_XML);
-
-
- // package the resources.
- helper.packageResources(
- mergedManifestFile,
- libProjects,
- null, // res filter
- 0, // versionCode
- resourceFile.getParent(),
- resourceFile.getName());
-
- // Step 2. Convert the byte code to Dalvik bytecode
-
- // tmp file for the packaged resource file.
- File dexFile = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_DEX);
- dexFile.deleteOnExit();
-
- ProjectState state = Sdk.getProjectState(project);
- String proguardConfig = state.getProperties().getProperty(
- ProjectProperties.PROPERTY_PROGUARD_CONFIG);
-
- boolean runProguard = false;
- List<File> proguardConfigFiles = null;
- if (proguardConfig != null && proguardConfig.length() > 0) {
- // Be tolerant with respect to file and path separators just like
- // Ant is. Allow "/" in the property file to mean whatever the file
- // separator character is:
- if (File.separatorChar != '/' && proguardConfig.indexOf('/') != -1) {
- proguardConfig = proguardConfig.replace('/', File.separatorChar);
- }
-
- Iterable<String> paths = LintUtils.splitPath(proguardConfig);
- for (String path : paths) {
- if (path.startsWith(SDK_PROPERTY_REF)) {
- path = AdtPrefs.getPrefs().getOsSdkFolder() +
- path.substring(SDK_PROPERTY_REF.length());
- } else if (path.startsWith(HOME_PROPERTY_REF)) {
- path = System.getProperty(HOME_PROPERTY) +
- path.substring(HOME_PROPERTY_REF.length());
- }
- File proguardConfigFile = new File(path);
- if (proguardConfigFile.isAbsolute() == false) {
- proguardConfigFile = new File(project.getLocation().toFile(), path);
- }
- if (proguardConfigFile.isFile()) {
- if (proguardConfigFiles == null) {
- proguardConfigFiles = new ArrayList<File>();
- }
- proguardConfigFiles.add(proguardConfigFile);
- runProguard = true;
- } else {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- "Invalid proguard configuration file path " + proguardConfigFile
- + " does not exist or is not a regular file", null));
- }
- }
-
- // get the proguard file output by aapt
- if (proguardConfigFiles != null) {
- IFile proguardFile = androidOutputFolder.getFile(AdtConstants.FN_AAPT_PROGUARD);
- proguardConfigFiles.add(proguardFile.getLocation().toFile());
- }
- }
-
- Collection<String> dxInput;
-
- if (runProguard) {
- // get all the compiled code paths. This will contain both project output
- // folder and jar files.
- Collection<String> paths = helper.getCompiledCodePaths();
-
- // create a jar file containing all the project output (as proguard cannot
- // process folders of .class files).
- File inputJar = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_JAR);
- inputJar.deleteOnExit();
- JarOutputStream jos = new JarOutputStream(new FileOutputStream(inputJar));
-
- // a list of the other paths (jar files.)
- List<String> jars = new ArrayList<String>();
-
- for (String path : paths) {
- File root = new File(path);
- if (root.isDirectory()) {
- addFileToJar(jos, root, root);
- } else if (root.isFile()) {
- jars.add(path);
- }
- }
- jos.close();
-
- // destination file for proguard
- File obfuscatedJar = File.createTempFile(TEMP_PREFIX, SdkConstants.DOT_JAR);
- obfuscatedJar.deleteOnExit();
-
- // run proguard
- helper.runProguard(proguardConfigFiles, inputJar, jars, obfuscatedJar,
- new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD));
-
- helper.setProguardOutput(obfuscatedJar.getAbsolutePath());
-
- // dx input is proguard's output
- dxInput = Collections.singletonList(obfuscatedJar.getAbsolutePath());
- } else {
- // no proguard, simply get all the compiled code path: project output(s) +
- // jar file(s)
- dxInput = helper.getCompiledCodePaths();
- }
-
- IJavaProject javaProject = JavaCore.create(project);
-
- helper.executeDx(javaProject, dxInput, dexFile.getAbsolutePath());
-
- // Step 3. Final package
-
- helper.finalPackage(
- resourceFile.getAbsolutePath(),
- dexFile.getAbsolutePath(),
- outputFile.getAbsolutePath(),
- libProjects,
- key,
- certificate,
- null); //resourceMarker
-
- // success!
- } catch (CoreException e) {
- throw e;
- } catch (ProguardResultException e) {
- String msg = String.format("Proguard returned with error code %d. See console",
- e.getErrorCode());
- AdtPlugin.printErrorToConsole(project, msg);
- AdtPlugin.printErrorToConsole(project, (Object[]) e.getOutput());
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- msg, e));
- } catch (ProguardExecException e) {
- String msg = String.format("Failed to run proguard: %s", e.getMessage());
- AdtPlugin.printErrorToConsole(project, msg);
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- msg, e));
- } catch (DuplicateFileException e) {
- String msg = String.format(
- "Found duplicate file for APK: %1$s\nOrigin 1: %2$s\nOrigin 2: %3$s",
- e.getArchivePath(), e.getFile1(), e.getFile2());
- AdtPlugin.printErrorToConsole(project, msg);
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- e.getMessage(), e));
- } catch (NativeLibInJarException e) {
- String msg = e.getMessage();
-
- AdtPlugin.printErrorToConsole(project, msg);
- AdtPlugin.printErrorToConsole(project, (Object[]) e.getAdditionalInfo());
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- e.getMessage(), e));
- } catch (DexException e) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- e.getMessage(), e));
- } catch (ApkCreationException e) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- e.getMessage(), e));
- } catch (Exception e) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- "Failed to export application", e));
- } finally {
- // move back to a debug build.
- // By using a normal build, we'll simply rebuild the debug version, and let the
- // builder decide whether to build the full package or not.
- ProjectHelper.buildWithDeps(project, IncrementalProjectBuilder.FULL_BUILD, monitor);
- project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
- }
- }
-
- public static BuildToolInfo getBuildTools(ProjectState projectState)
- throws CoreException {
- BuildToolInfo buildToolInfo = projectState.getBuildToolInfo();
- if (buildToolInfo == null) {
- buildToolInfo = Sdk.getCurrent().getLatestBuildTool();
- }
-
- if (buildToolInfo == null) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- "No Build Tools installed in the SDK."));
- }
- return buildToolInfo;
- }
-
- /**
- * Exports an unsigned release APK after prompting the user for a location.
- *
- * <strong>Must be called from the UI thread.</strong>
- *
- * @param project the project to export
- */
- public static void exportUnsignedReleaseApk(final IProject project) {
- Shell shell = Display.getCurrent().getActiveShell();
-
- // create a default file name for the apk.
- String fileName = project.getName() + SdkConstants.DOT_ANDROID_PACKAGE;
-
- // Pop up the file save window to get the file location
- FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
-
- fileDialog.setText("Export Project");
- fileDialog.setFileName(fileName);
-
- final String saveLocation = fileDialog.open();
- if (saveLocation != null) {
- new Job("Android Release Export") {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- exportReleaseApk(project,
- new File(saveLocation),
- null, //key
- null, //certificate
- monitor);
-
- // this is unsigned export. Let's tell the developers to run zip align
- AdtPlugin.displayWarning("Android IDE Plug-in", String.format(
- "An unsigned package of the application was saved at\n%1$s\n\n" +
- "Before publishing the application you will need to:\n" +
- "- Sign the application with your release key,\n" +
- "- run zipalign on the signed package. ZipAlign is located in <SDK>/tools/\n\n" +
- "Aligning applications allows Android to use application resources\n" +
- "more efficiently.", saveLocation));
-
- return Status.OK_STATUS;
- } catch (CoreException e) {
- AdtPlugin.displayError("Android IDE Plug-in", String.format(
- "Error exporting application:\n\n%1$s", e.getMessage()));
- return e.getStatus();
- }
- }
- }.schedule();
- }
- }
-
- /**
- * Adds a file to a jar file.
- * The <var>rootDirectory</var> dictates the path of the file inside the jar file. It must be
- * a parent of <var>file</var>.
- * @param jar the jar to add the file to
- * @param file the file to add
- * @param rootDirectory the rootDirectory.
- * @throws IOException
- */
- private static void addFileToJar(JarOutputStream jar, File file, File rootDirectory)
- throws IOException {
- if (file.isDirectory()) {
- if (file.getName().equals("META-INF") == false) {
- for (File child: file.listFiles()) {
- addFileToJar(jar, child, rootDirectory);
- }
- }
- } else if (file.isFile()) {
- String rootPath = rootDirectory.getAbsolutePath();
- String path = file.getAbsolutePath();
- path = path.substring(rootPath.length()).replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
- if (path.charAt(0) == '/') {
- path = path.substring(1);
- }
-
- JarEntry entry = new JarEntry(path);
- entry.setTime(file.lastModified());
- jar.putNextEntry(entry);
-
- // put the content of the file.
- byte[] buffer = new byte[1024];
- int count;
- BufferedInputStream bis = null;
- try {
- bis = new BufferedInputStream(new FileInputStream(file));
- while ((count = bis.read(buffer)) != -1) {
- jar.write(buffer, 0, count);
- }
- } finally {
- if (bis != null) {
- try {
- bis.close();
- } catch (IOException ignore) {
- }
- }
- }
- jar.closeEntry();
- }
- }
-}