android artifacts: align apk

This commit is contained in:
Eugene Kudelevsky
2012-06-05 18:49:40 +04:00
parent e6cef9f0cb
commit 5705687f1e
4 changed files with 90 additions and 41 deletions
@@ -405,4 +405,5 @@ android.launch.draw.9.patch.action=Draw 9 Patch
android.facet.settings.include.system.proguard=Include system proguard file
file.already.exists.error=File {0} already exists
deployment.target.settings.min.sdk.info.message=Only compatible AVDs are shown. See 'uses-sdk' tag in AndroidManifest.xml
android.compilation.warning.circular.app.dependency=Generated fields in {0}.R class in module ''{1}'' won''t be final, because of circular dependency on module ''{2}''
android.compilation.warning.circular.app.dependency=Generated fields in {0}.R class in module ''{1}'' won''t be final, because of circular dependency on module ''{2}''
cannot.find.zip.align=The zipalign tool was not found in the SDK.\n\nPlease update to the latest SDK and re-export your application\nor run zipalign manually.\n\nAligning applications allows Android to use application resources\nmore efficiently.
@@ -1,8 +1,10 @@
package org.jetbrains.android.compiler.artifact;
import com.android.sdklib.SdkConstants;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -14,6 +16,8 @@ import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.util.xmlb.annotations.Transient;
import org.apache.commons.codec.binary.Base64;
import org.jetbrains.android.compiler.AndroidCompileUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.annotations.NotNull;
@@ -44,8 +48,21 @@ public class AndroidApplicationArtifactProperties extends ArtifactProperties<And
mySigningMode != AndroidArtifactSigningMode.RELEASE_SIGNED) {
return;
}
final String errorPrefix = "[Artifact '" + artifact.getName() + "'] ";
final Pair<PrivateKey, X509Certificate> pair = getPrivateKeyAndCertificate(context, errorPrefix);
final AndroidFacet facet = AndroidArtifactUtil.getPackagedFacet(context.getProject(), artifact);
if (facet == null) {
return;
}
final String messagePrefix = "[Artifact '" + artifact.getName() + "'] ";
final Module module = facet.getModule();
final AndroidPlatform platform = AndroidPlatform.getInstance(module);
if (platform == null) {
context.addMessage(CompilerMessageCategory.ERROR, messagePrefix +
AndroidBundle.message("android.compilation.error.specify.platform", module.getName()), null, -1, -1);
return;
}
final Pair<PrivateKey, X509Certificate> pair = getPrivateKeyAndCertificate(context, messagePrefix);
if (pair == null) {
return;
}
@@ -64,11 +81,26 @@ public class AndroidApplicationArtifactProperties extends ArtifactProperties<And
return;
}
final String zipAlignPath =
FileUtil.toSystemDependentName(platform.getSdkData().getLocation() + '/' + AndroidCommonUtils.toolPath(SdkConstants.FN_ZIPALIGN));
final boolean runZipAlign = new File(zipAlignPath).isFile();
File tmpDir = null;
try {
tmpDir = FileUtil.createTempDirectory("android_artifact", "tmp");
final File tmpArtifact = new File(tmpDir, "tmpArtifact.apk");
FileUtil.copy(artifactFile, tmpArtifact);
if (runZipAlign) {
final String errorMessage = AndroidArtifactUtil.executeZipAlign(zipAlignPath, artifactFile, tmpArtifact);
if (errorMessage != null) {
context.addMessage(CompilerMessageCategory.ERROR, messagePrefix + "zip-align: " + errorMessage, null, -1, -1);
return;
}
}
else {
context.addMessage(CompilerMessageCategory.WARNING, messagePrefix + AndroidBundle.message("cannot.find.zip.align"), null, -1, -1);
FileUtil.copy(artifactFile, tmpArtifact);
}
if (!FileUtil.delete(artifactFile)) {
context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete file " + artifactFile.getPath(), null, -1, -1);
@@ -1,11 +1,20 @@
package org.jetbrains.android.compiler.artifact;
import com.intellij.CommonBundle;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactManager;
import com.intellij.packaging.elements.PackagingElementResolvingContext;
import com.intellij.packaging.impl.artifacts.ArtifactUtil;
import com.intellij.packaging.ui.ArtifactEditorContext;
import com.intellij.util.Processor;
@@ -13,6 +22,7 @@ import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.List;
/**
@@ -31,6 +41,21 @@ public class AndroidArtifactUtil {
}, editorContext, true);
}
@Nullable
public static AndroidFacet getPackagedFacet(Project project, Artifact artifact) {
final Ref<AndroidFinalPackageElement> elementRef = Ref.create(null);
final PackagingElementResolvingContext resolvingContext = ArtifactManager.getInstance(project).getResolvingContext();
ArtifactUtil
.processPackagingElements(artifact, AndroidFinalPackageElementType.getInstance(), new Processor<AndroidFinalPackageElement>() {
public boolean process(AndroidFinalPackageElement e) {
elementRef.set(e);
return false;
}
}, resolvingContext, true);
final AndroidFinalPackageElement element = elementRef.get();
return element != null ? element.getFacet() : null;
}
@Nullable
public static AndroidFacet chooseAndroidApplicationModule(@NotNull Project project, @NotNull List<Module> modules) {
final ChooseModulesDialog dialog = new ChooseModulesDialog(project, modules, "Select Module",
@@ -53,4 +78,29 @@ public class AndroidArtifactUtil {
}
return facet;
}
@Nullable
public static String executeZipAlign(String zipAlignPath, File source, File destination) {
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath(zipAlignPath);
commandLine.addParameters("-f", "4", source.getAbsolutePath(), destination.getAbsolutePath());
OSProcessHandler handler;
try {
handler = new OSProcessHandler(commandLine.createProcess(), "");
}
catch (ExecutionException e) {
return e.getMessage();
}
final StringBuilder builder = new StringBuilder();
handler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
builder.append(event.getText());
}
});
handler.startNotify();
handler.waitFor();
int exitCode = handler.getProcess().exitValue();
return exitCode != 0 ? builder.toString() : null;
}
}
@@ -18,11 +18,6 @@ package org.jetbrains.android.exportSignedPackage;
import com.android.sdklib.SdkConstants;
import com.intellij.CommonBundle;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.wizard.CommitStepException;
import com.intellij.openapi.application.ApplicationManager;
@@ -42,7 +37,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -50,6 +44,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.JBLabel;
import org.jetbrains.android.compiler.AndroidCompileUtil;
import org.jetbrains.android.compiler.AndroidProguardCompiler;
import org.jetbrains.android.compiler.artifact.AndroidArtifactUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidRootUtil;
@@ -244,7 +239,7 @@ class ApkStep extends ExportSignedPackageWizardStep {
if (runZipAlign) {
File realDestFile = new File(apkPath);
final String message = executeZipAlign(zipAlignPath, destFile, realDestFile);
final String message = AndroidArtifactUtil.executeZipAlign(zipAlignPath, destFile, realDestFile);
if (message != null) {
showErrorInDispatchThread(message);
return;
@@ -254,11 +249,7 @@ class ApkStep extends ExportSignedPackageWizardStep {
public void run() {
String title = AndroidBundle.message("android.export.package.wizard.title");
if (!runZipAlign) {
Messages.showWarningDialog(myWizard.getProject(), "The zipalign tool was not found in the SDK.\n\n" +
"Please update to the latest SDK and re-export your application\n" +
"or run zipalign manually.\n\n" +
"Aligning applications allows Android to use application resources\n" +
"more efficiently.", title);
Messages.showWarningDialog(myWizard.getProject(), AndroidBundle.message("cannot.find.zip.align"), title);
}
Messages.showInfoMessage(myWizard.getProject(), AndroidBundle.message("android.export.package.success.message", apkPath), title);
}
@@ -286,31 +277,6 @@ class ApkStep extends ExportSignedPackageWizardStep {
}, ModalityState.NON_MODAL);
}
@Nullable
private static String executeZipAlign(String zipAlignPath, File source, File destination) {
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath(zipAlignPath);
commandLine.addParameters("-f", "4", source.getAbsolutePath(), destination.getAbsolutePath());
OSProcessHandler handler;
try {
handler = new OSProcessHandler(commandLine.createProcess(), "");
}
catch (ExecutionException e) {
return e.getMessage();
}
final StringBuilder builder = new StringBuilder();
handler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
builder.append(event.getText());
}
});
handler.startNotify();
handler.waitFor();
int exitCode = handler.getProcess().exitValue();
return exitCode != 0 ? builder.toString() : null;
}
@Override
protected boolean canFinish() {
return true;