ApkBuilderpublic class ApkBuilder extends BaseBuilder
Fields Summary |
---|
public static final String | ID | private static final String | PROPERTY_CONVERT_TO_DEX | private static final String | PROPERTY_PACKAGE_RESOURCES | private static final String | PROPERTY_BUILD_APK | private static final String | DX_PREFIX | private boolean | mConvertToDexDex conversion flag. This is set to true if one of the changed/added/removed
file is a .class file. Upon visiting all the delta resource, if this
flag is true, then we know we'll have to make the "classes.dex" file. | private boolean | mPackageResourcesPackage resources flag. This is set to true if one of the changed/added/removed
file is a resource file. Upon visiting all the delta resource, if
this flag is true, then we know we'll have to repackage the resources. | private boolean | mBuildFinalPackageFinal package build flag. | private PrintStream | mOutStream | private PrintStream | mErrStream | private final com.android.jarutils.SignedJarBuilder.IZipEntryFilter | mJavaResourcesFilter{@link IZipEntryFilter} to filter out everything that is not a standard java resources.
Used in {@link SignedJarBuilder#writeZip(java.io.InputStream, IZipEntryFilter)} when
we only want the java resources from external jars. |
Constructors Summary |
---|
public ApkBuilder()
super();
|
Methods Summary |
---|
protected org.eclipse.core.resources.IProject[] | build(int kind, java.util.Map args, org.eclipse.core.runtime.IProgressMonitor monitor)
// get a project object
IProject project = getProject();
// Top level check to make sure the build can move forward.
abortOnBadSetup(project);
// get the list of referenced projects.
IProject[] referencedProjects = ProjectHelper.getReferencedProjects(project);
IJavaProject[] referencedJavaProjects = getJavaProjects(referencedProjects);
// get the output folder, this method returns the path with a trailing
// separator
IJavaProject javaProject = JavaCore.create(project);
IFolder outputFolder = BaseProjectHelper.getOutputFolder(project);
// now we need to get the classpath list
ArrayList<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject);
// First thing we do is go through the resource delta to not
// lose it if we have to abort the build for any reason.
ApkDeltaVisitor dv = null;
if (kind == FULL_BUILD) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Start_Full_Apk_Build);
mPackageResources = true;
mConvertToDex = true;
mBuildFinalPackage = true;
} else {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Start_Inc_Apk_Build);
// go through the resources and see if something changed.
IResourceDelta delta = getDelta(project);
if (delta == null) {
mPackageResources = true;
mConvertToDex = true;
mBuildFinalPackage = true;
} else {
dv = new ApkDeltaVisitor(this, sourceList, outputFolder);
delta.accept(dv);
// save the state
mPackageResources |= dv.getPackageResources();
mConvertToDex |= dv.getConvertToDex();
mBuildFinalPackage |= dv.getMakeFinalPackage();
}
// also go through the delta for all the referenced projects, until we are forced to
// compile anyway
for (int i = 0 ; i < referencedJavaProjects.length &&
(mBuildFinalPackage == false || mConvertToDex == false); i++) {
IJavaProject referencedJavaProject = referencedJavaProjects[i];
delta = getDelta(referencedJavaProject.getProject());
if (delta != null) {
ReferencedProjectDeltaVisitor refProjectDv = new ReferencedProjectDeltaVisitor(
referencedJavaProject);
delta.accept(refProjectDv);
// save the state
mConvertToDex |= refProjectDv.needDexConvertion();
mBuildFinalPackage |= refProjectDv.needMakeFinalPackage();
}
}
}
// store the build status in the persistent storage
saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , mConvertToDex);
saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources);
saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
if (dv != null && dv.mXmlError) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Xml_Error);
// if there was some XML errors, we just return w/o doing
// anything since we've put some markers in the files anyway
return referencedProjects;
}
if (outputFolder == null) {
// mark project and exit
markProject(AdtConstants.MARKER_ADT, Messages.Failed_To_Get_Output,
IMarker.SEVERITY_ERROR);
return referencedProjects;
}
// first thing we do is check that the SDK directory has been setup.
String osSdkFolder = AdtPlugin.getOsSdkFolder();
if (osSdkFolder.length() == 0) {
// this has already been checked in the precompiler. Therefore,
// while we do have to cancel the build, we don't have to return
// any error or throw anything.
return referencedProjects;
}
// get the extra configs for the project.
// The map contains (name, filter) where 'name' is a name to be used in the apk filename,
// and filter is the resource filter to be used in the aapt -c parameters to restrict
// which resource configurations to package in the apk.
Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
// do some extra check, in case the output files are not present. This
// will force to recreate them.
IResource tmp = null;
if (mPackageResources == false) {
// check the full resource package
tmp = outputFolder.findMember(AndroidConstants.FN_RESOURCES_AP_);
if (tmp == null || tmp.exists() == false) {
mPackageResources = true;
mBuildFinalPackage = true;
} else {
// if the full package is present, we check the filtered resource packages as well
if (configs != null) {
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String filename = String.format(AndroidConstants.FN_RESOURCES_S_AP_,
entry.getKey());
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, filename);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mPackageResources = true;
mBuildFinalPackage = true;
break;
}
}
}
}
}
// check classes.dex is present. If not we force to recreate it.
if (mConvertToDex == false) {
tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX);
if (tmp == null || tmp.exists() == false) {
mConvertToDex = true;
mBuildFinalPackage = true;
}
}
// also check the final file(s)!
String finalPackageName = ProjectHelper.getApkFilename(project, null /*config*/);
if (mBuildFinalPackage == false) {
tmp = outputFolder.findMember(finalPackageName);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
} else if (configs != null) {
// if the full apk is present, we check the filtered apk as well
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String filename = ProjectHelper.getApkFilename(project, entry.getKey());
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, filename);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
break;
}
}
}
}
// at this point we know if we need to recreate the temporary apk
// or the dex file, but we don't know if we simply need to recreate them
// because they are missing
// refresh the output directory first
IContainer ic = outputFolder.getParent();
if (ic != null) {
ic.refreshLocal(IResource.DEPTH_ONE, monitor);
}
// we need to test all three, as we may need to make the final package
// but not the intermediary ones.
if (mPackageResources || mConvertToDex || mBuildFinalPackage) {
IPath binLocation = outputFolder.getLocation();
if (binLocation == null) {
markProject(AdtConstants.MARKER_ADT, Messages.Output_Missing,
IMarker.SEVERITY_ERROR);
return referencedProjects;
}
String osBinPath = binLocation.toOSString();
// Remove the old .apk.
// This make sure that if the apk is corrupted, then dx (which would attempt
// to open it), will not fail.
String osFinalPackagePath = osBinPath + File.separator + finalPackageName;
File finalPackage = new File(osFinalPackagePath);
// if delete failed, this is not really a problem, as the final package generation
// handle already present .apk, and if that one failed as well, the user will be
// notified.
finalPackage.delete();
if (configs != null) {
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String packageFilepath = osBinPath + File.separator +
ProjectHelper.getApkFilename(project, entry.getKey());
finalPackage = new File(packageFilepath);
finalPackage.delete();
}
}
// first we check if we need to package the resources.
if (mPackageResources) {
// remove some aapt_package only markers.
removeMarkersFromContainer(project, AndroidConstants.MARKER_AAPT_PACKAGE);
// need to figure out some path before we can execute aapt;
// resource to the AndroidManifest.xml file
IResource manifestResource = project .findMember(
AndroidConstants.WS_SEP + AndroidConstants.FN_ANDROID_MANIFEST);
if (manifestResource == null
|| manifestResource.exists() == false) {
// mark project and exit
String msg = String.format(Messages.s_File_Missing,
AndroidConstants.FN_ANDROID_MANIFEST);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return referencedProjects;
}
// get the resource folder
IFolder resFolder = project.getFolder(
AndroidConstants.WS_RESOURCES);
// and the assets folder
IFolder assetsFolder = project.getFolder(
AndroidConstants.WS_ASSETS);
// we need to make sure this one exists.
if (assetsFolder.exists() == false) {
assetsFolder = null;
}
IPath resLocation = resFolder.getLocation();
IPath manifestLocation = manifestResource.getLocation();
if (resLocation != null && manifestLocation != null) {
String osResPath = resLocation.toOSString();
String osManifestPath = manifestLocation.toOSString();
String osAssetsPath = null;
if (assetsFolder != null) {
osAssetsPath = assetsFolder.getLocation().toOSString();
}
// build the default resource package
if (executeAapt(project, osManifestPath, osResPath,
osAssetsPath, osBinPath + File.separator +
AndroidConstants.FN_RESOURCES_AP_, null /*configFilter*/) == false) {
// aapt failed. Whatever files that needed to be marked
// have already been marked. We just return.
return referencedProjects;
}
// now do the same thing for all the configured resource packages.
if (configs != null) {
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
String outPathFormat = osBinPath + File.separator +
AndroidConstants.FN_RESOURCES_S_AP_;
String outPath = String.format(outPathFormat, entry.getKey());
if (executeAapt(project, osManifestPath, osResPath,
osAssetsPath, outPath, entry.getValue()) == false) {
// aapt failed. Whatever files that needed to be marked
// have already been marked. We just return.
return referencedProjects;
}
}
}
// build has been done. reset the state of the builder
mPackageResources = false;
// and store it
saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources);
}
}
// then we check if we need to package the .class into classes.dex
if (mConvertToDex) {
if (executeDx(javaProject, osBinPath, osBinPath + File.separator +
AndroidConstants.FN_CLASSES_DEX, referencedJavaProjects) == false) {
// dx failed, we return
return referencedProjects;
}
// build has been done. reset the state of the builder
mConvertToDex = false;
// and store it
saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex);
}
// now we need to make the final package from the intermediary apk
// and classes.dex.
// This is the default package with all the resources.
String classesDexPath = osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX;
if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
classesDexPath,osFinalPackagePath, javaProject,
referencedJavaProjects) == false) {
return referencedProjects;
}
// now do the same thing for all the configured resource packages.
if (configs != null) {
String resPathFormat = osBinPath + File.separator +
AndroidConstants.FN_RESOURCES_S_AP_;
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
// make the filename for the resource package.
String resPath = String.format(resPathFormat, entry.getKey());
// make the filename for the apk to generate
String apkOsFilePath = osBinPath + File.separator +
ProjectHelper.getApkFilename(project, entry.getKey());
if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject,
referencedJavaProjects) == false) {
return referencedProjects;
}
}
}
// we are done.
// get the resource to bin
outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
// build has been done. reset the state of the builder
mBuildFinalPackage = false;
// and store it
saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
// reset the installation manager to force new installs of this project
ApkInstallManager.getInstance().resetInstallationFor(project);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
"Build Success!");
}
return referencedProjects;
| static boolean | checkFileForPackaging(org.eclipse.core.resources.IFile file)Checks a {@link IFile} to make sure it should be packaged as standard resources.
String name = file.getName();
String ext = file.getFileExtension();
return JavaResourceFilter.checkFileForPackaging(name, ext);
| static boolean | checkFolderForPackaging(org.eclipse.core.resources.IFolder folder)Checks whether an {@link IFolder} and its content is valid for packaging into the .apk as
standard Java resource.
String name = folder.getName();
return JavaResourceFilter.checkFolderForPackaging(name);
| private boolean | executeAapt(org.eclipse.core.resources.IProject project, java.lang.String osManifestPath, java.lang.String osResPath, java.lang.String osAssetsPath, java.lang.String osOutFilePath, java.lang.String configFilter)Executes aapt. If any error happen, files or the project will be marked.
IAndroidTarget target = Sdk.getCurrent().getTarget(project);
// Create the command line.
ArrayList<String> commandArray = new ArrayList<String>();
commandArray.add(target.getPath(IAndroidTarget.AAPT));
commandArray.add("package"); //$NON-NLS-1$
commandArray.add("-f");//$NON-NLS-1$
if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
commandArray.add("-v"); //$NON-NLS-1$
}
if (configFilter != null) {
commandArray.add("-c"); //$NON-NLS-1$
commandArray.add(configFilter);
}
commandArray.add("-M"); //$NON-NLS-1$
commandArray.add(osManifestPath);
commandArray.add("-S"); //$NON-NLS-1$
commandArray.add(osResPath);
if (osAssetsPath != null) {
commandArray.add("-A"); //$NON-NLS-1$
commandArray.add(osAssetsPath);
}
commandArray.add("-I"); //$NON-NLS-1$
commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR));
commandArray.add("-F"); //$NON-NLS-1$
commandArray.add(osOutFilePath);
String command[] = commandArray.toArray(
new String[commandArray.size()]);
if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
StringBuilder sb = new StringBuilder();
for (String c : command) {
sb.append(c);
sb.append(' ");
}
AdtPlugin.printToConsole(project, sb.toString());
}
// launch
int execError = 1;
try {
// launch the command line process
Process process = Runtime.getRuntime().exec(command);
// list to store each line of stderr
ArrayList<String> results = new ArrayList<String>();
// get the output and return code from the process
execError = grabProcessOutput(process, results);
// attempt to parse the error output
boolean parsingError = parseAaptOutput(results, project);
// if we couldn't parse the output we display it in the console.
if (parsingError) {
if (execError != 0) {
AdtPlugin.printErrorToConsole(project, results.toArray());
} else {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, project,
results.toArray());
}
}
// We need to abort if the exec failed.
if (execError != 0) {
// if the exec failed, and we couldn't parse the error output (and therefore
// not all files that should have been marked, were marked), we put a generic
// marker on the project and abort.
if (parsingError) {
markProject(AdtConstants.MARKER_ADT, Messages.Unparsed_AAPT_Errors,
IMarker.SEVERITY_ERROR);
}
// abort if exec failed.
return false;
}
} catch (IOException e1) {
String msg = String.format(Messages.AAPT_Exec_Error, command[0]);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
} catch (InterruptedException e) {
String msg = String.format(Messages.AAPT_Exec_Error, command[0]);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
}
return true;
| private boolean | executeDx(org.eclipse.jdt.core.IJavaProject javaProject, java.lang.String osBinPath, java.lang.String osOutFilePath, org.eclipse.jdt.core.IJavaProject[] referencedJavaProjects)Execute the Dx tool for dalvik code conversion.
IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject());
AndroidTargetData targetData = Sdk.getCurrent().getTargetData(target);
if (targetData == null) {
throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
}
// get the dex wrapper
DexWrapper wrapper = targetData.getDexWrapper();
if (wrapper == null) {
throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
}
// make sure dx use the proper output streams.
// first make sure we actually have the streams available.
if (mOutStream == null) {
IProject project = getProject();
mOutStream = AdtPlugin.getOutPrintStream(project, DX_PREFIX);
mErrStream = AdtPlugin.getErrPrintStream(project, DX_PREFIX);
}
try {
// get the list of libraries to include with the source code
String[] libraries = getExternalJars();
// get the list of referenced projects output to add
String[] projectOutputs = getProjectOutputs(referencedJavaProjects);
String[] fileNames = new String[1 + projectOutputs.length + libraries.length];
// first this project output
fileNames[0] = osBinPath;
// then other project output
System.arraycopy(projectOutputs, 0, fileNames, 1, projectOutputs.length);
// then external jars.
System.arraycopy(libraries, 0, fileNames, 1 + projectOutputs.length, libraries.length);
int res = wrapper.run(osOutFilePath, fileNames,
AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE,
mOutStream, mErrStream);
if (res != 0) {
// output error message and marker the project.
String message = String.format(Messages.Dalvik_Error_d,
res);
AdtPlugin.printErrorToConsole(getProject(), message);
markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR);
return false;
}
} catch (Throwable ex) {
String message = ex.getMessage();
if (message == null) {
message = ex.getClass().getCanonicalName();
}
message = String.format(Messages.Dalvik_Error_s, message);
AdtPlugin.printErrorToConsole(getProject(), message);
markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR);
if ((ex instanceof NoClassDefFoundError)
|| (ex instanceof NoSuchMethodError)) {
AdtPlugin.printErrorToConsole(getProject(), Messages.Incompatible_VM_Warning,
Messages.Requires_1_5_Error);
}
return false;
}
return true;
| private boolean | finalPackage(java.lang.String intermediateApk, java.lang.String dex, java.lang.String output, org.eclipse.jdt.core.IJavaProject javaProject, org.eclipse.jdt.core.IJavaProject[] referencedJavaProjects)Makes the final package. Package the dex files, the temporary resource file into the final
package file.
FileOutputStream fos = null;
try {
IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
String osKeyPath = store.getString(AdtPlugin.PREFS_CUSTOM_DEBUG_KEYSTORE);
if (osKeyPath == null || new File(osKeyPath).exists() == false) {
osKeyPath = DebugKeyProvider.getDefaultKeyStoreOsPath();
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
Messages.ApkBuilder_Using_Default_Key);
} else {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
String.format(Messages.ApkBuilder_Using_s_To_Sign, osKeyPath));
}
// TODO: get the store type from somewhere else.
DebugKeyProvider provider = new DebugKeyProvider(osKeyPath, null /* storeType */,
new IKeyGenOutput() {
public void err(String message) {
AdtPlugin.printErrorToConsole(javaProject.getProject(),
Messages.ApkBuilder_Signing_Key_Creation_s + message);
}
public void out(String message) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE,
javaProject.getProject(),
Messages.ApkBuilder_Signing_Key_Creation_s + message);
}
});
PrivateKey key = provider.getDebugKey();
X509Certificate certificate = (X509Certificate)provider.getCertificate();
if (key == null) {
String msg = String.format(Messages.Final_Archive_Error_s,
Messages.ApkBuilder_Unable_To_Gey_Key);
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
}
// compare the certificate expiration date
if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) {
// TODO, regenerate a new one.
String msg = String.format(Messages.Final_Archive_Error_s,
String.format(Messages.ApkBuilder_Certificate_Expired_on_s,
DateFormat.getInstance().format(certificate.getNotAfter())));
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
}
// create the jar builder.
fos = new FileOutputStream(output);
SignedJarBuilder builder = new SignedJarBuilder(fos, key, certificate);
// add the intermediate file containing the compiled resources.
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
String.format(Messages.ApkBuilder_Packaging_s, intermediateApk));
FileInputStream fis = new FileInputStream(intermediateApk);
try {
builder.writeZip(fis, null /* filter */);
} finally {
fis.close();
}
// Now we add the new file to the zip archive for the classes.dex file.
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
String.format(Messages.ApkBuilder_Packaging_s, AndroidConstants.FN_CLASSES_DEX));
File entryFile = new File(dex);
builder.writeFile(entryFile, AndroidConstants.FN_CLASSES_DEX);
// Now we write the standard resources from the project and the referenced projects.
writeStandardResources(builder, javaProject, referencedJavaProjects);
// Now we write the standard resources from the external libraries
for (String libraryOsPath : getExternalJars()) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
String.format(Messages.ApkBuilder_Packaging_s, libraryOsPath));
try {
fis = new FileInputStream(libraryOsPath);
builder.writeZip(fis, mJavaResourcesFilter);
} finally {
fis.close();
}
}
// now write the native libraries.
// First look if the lib folder is there.
IResource libFolder = javaProject.getProject().findMember(SdkConstants.FD_NATIVE_LIBS);
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
// look inside and put .so in lib/* by keeping the relative folder path.
writeNativeLibraries(libFolder.getFullPath().segmentCount(), builder, libFolder);
}
// close the jar file and write the manifest and sign it.
builder.close();
} catch (GeneralSecurityException e1) {
// mark project and return
String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage());
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
} catch (IOException e1) {
// mark project and return
String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage());
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
} catch (KeytoolException e) {
String eMessage = e.getMessage();
// mark the project with the standard message
String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
// output more info in the console
AdtPlugin.printErrorToConsole(javaProject.getProject(),
msg,
String.format(Messages.ApkBuilder_JAVA_HOME_is_s, e.getJavaHome()),
Messages.ApkBuilder_Update_or_Execute_manually_s,
e.getCommandLine());
} catch (AndroidLocationException e) {
String eMessage = e.getMessage();
// mark the project with the standard message
String msg = String.format(Messages.Final_Archive_Error_s, eMessage);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
// and also output it in the console
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
} catch (CoreException e) {
// mark project and return
String msg = String.format(Messages.Final_Archive_Error_s, e.getMessage());
AdtPlugin.printErrorToConsole(javaProject.getProject(), msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// pass.
}
}
}
return true;
| private org.eclipse.jdt.core.IJavaProject[] | getJavaProjects(org.eclipse.core.resources.IProject[] projects)Returns an array of {@link IJavaProject} matching the provided {@link IProject} objects.
ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
for (IProject p : projects) {
if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
list.add(JavaCore.create(p));
}
}
return list.toArray(new IJavaProject[list.size()]);
| private java.lang.String[] | getProjectOutputs(org.eclipse.jdt.core.IJavaProject[] referencedJavaProjects)Returns the list of the output folders for the specified {@link IJavaProject} objects, if
they are Android projects.
ArrayList<String> list = new ArrayList<String>();
IWorkspace ws = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = ws.getRoot();
for (IJavaProject javaProject : referencedJavaProjects) {
// only include output from non android referenced project
// (This is to handle the case of reference Android projects in the context of
// instrumentation projects that need to reference the projects to be tested).
if (javaProject.getProject().hasNature(AndroidConstants.NATURE) == false) {
// get the output folder
IPath path = null;
try {
path = javaProject.getOutputLocation();
} catch (JavaModelException e) {
continue;
}
IResource outputResource = wsRoot.findMember(path);
if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
String outputOsPath = outputResource.getLocation().toOSString();
list.add(outputOsPath);
}
}
}
return list.toArray(new String[list.size()]);
| protected void | startupOnInitialize()
super.startupOnInitialize();
// load the build status. We pass true as the default value to
// force a recompile in case the property was not found
mConvertToDex = loadProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , true);
mPackageResources = loadProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, true);
mBuildFinalPackage = loadProjectBooleanProperty(PROPERTY_BUILD_APK, true);
| private void | writeNativeLibraries(int rootSegmentCount, com.android.jarutils.SignedJarBuilder jarBuilder, org.eclipse.core.resources.IResource resource)Writes native libraries into a {@link SignedJarBuilder}.
This recursively go through folder and writes .so files.
The path in the archive is based on the root folder containing the libraries in the project.
Its segment count is passed to the method to compute the resources path relative to the root
folder.
Native libraries in the archive must be in a "lib" folder. Everything in the project native
lib folder directly goes in this "lib" folder in the archive.
if (resource.getType() == IResource.FILE) {
IPath path = resource.getFullPath();
// check the extension.
if (path.getFileExtension().equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) {
// remove the first segment to build the path inside the archive.
path = path.removeFirstSegments(rootSegmentCount);
// add it to the archive.
IPath apkPath = new Path(SdkConstants.FD_APK_NATIVE_LIBS);
apkPath = apkPath.append(path);
// writes the file in the apk.
jarBuilder.writeFile(resource.getLocation().toFile(), apkPath.toString());
}
} else if (resource.getType() == IResource.FOLDER) {
IResource[] members = ((IFolder)resource).members();
for (IResource member : members) {
writeNativeLibraries(rootSegmentCount, jarBuilder, member);
}
}
| private void | writeStandardProjectResources(com.android.jarutils.SignedJarBuilder jarBuilder, org.eclipse.jdt.core.IJavaProject javaProject, org.eclipse.core.resources.IWorkspaceRoot wsRoot, java.util.ArrayList list)Writes the standard resources of a {@link IJavaProject} into a {@link SignedJarBuilder}.
Standard resources are non java/aidl files placed in the java package folders.
// get the source pathes
ArrayList<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject);
// loop on them and then recursively go through the content looking for matching files.
for (IPath sourcePath : sourceFolders) {
IResource sourceResource = wsRoot.findMember(sourcePath);
if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) {
writeStandardSourceFolderResources(jarBuilder, sourcePath, (IFolder)sourceResource,
list);
}
}
| private void | writeStandardResources(com.android.jarutils.SignedJarBuilder jarBuilder, org.eclipse.jdt.core.IJavaProject javaProject, org.eclipse.jdt.core.IJavaProject[] referencedJavaProjects)Writes the standard resources of a project and its referenced projects
into a {@link SignedJarBuilder}.
Standard resources are non java/aidl files placed in the java package folders.
IWorkspace ws = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = ws.getRoot();
// create a list of path already put into the archive, in order to detect conflict
ArrayList<String> list = new ArrayList<String>();
writeStandardProjectResources(jarBuilder, javaProject, wsRoot, list);
for (IJavaProject referencedJavaProject : referencedJavaProjects) {
// only include output from non android referenced project
// (This is to handle the case of reference Android projects in the context of
// instrumentation projects that need to reference the projects to be tested).
if (referencedJavaProject.getProject().hasNature(AndroidConstants.NATURE) == false) {
writeStandardProjectResources(jarBuilder, referencedJavaProject, wsRoot, list);
}
}
| private void | writeStandardSourceFolderResources(com.android.jarutils.SignedJarBuilder jarBuilder, org.eclipse.core.runtime.IPath sourceFolder, org.eclipse.core.resources.IFolder currentFolder, java.util.ArrayList list)Recursively writes the standard resources of a source folder into a {@link SignedJarBuilder}.
Standard resources are non java/aidl files placed in the java package folders.
try {
IResource[] members = currentFolder.members();
for (IResource member : members) {
int type = member.getType();
if (type == IResource.FILE && member.exists()) {
if (checkFileForPackaging((IFile)member)) {
// this files must be added to the archive.
IPath fullPath = member.getFullPath();
// We need to create its path inside the archive.
// This path is relative to the source folder.
IPath relativePath = fullPath.removeFirstSegments(
sourceFolder.segmentCount());
String zipPath = relativePath.toString();
// lets check it's not already in the list of path added to the archive
if (list.indexOf(zipPath) != -1) {
AdtPlugin.printErrorToConsole(getProject(),
String.format(
Messages.ApkBuilder_s_Conflict_with_file_s,
fullPath, zipPath));
} else {
// get the File object
File entryFile = member.getLocation().toFile();
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
String.format(Messages.ApkBuilder_Packaging_s_into_s, fullPath, zipPath));
// write it in the zip archive
jarBuilder.writeFile(entryFile, zipPath);
// and add it to the list of entries
list.add(zipPath);
}
}
} else if (type == IResource.FOLDER) {
if (checkFolderForPackaging((IFolder)member)) {
writeStandardSourceFolderResources(jarBuilder, sourceFolder,
(IFolder)member, list);
}
}
}
} catch (CoreException e) {
// if we can't get the members of the folder, we just don't do anything.
}
|
|