import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.internal.project.ApkSettings;
+import com.android.sdklib.xml.AndroidManifest;
+import com.android.sdklib.xml.AndroidXPathFactory;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.xml.sax.InputSource;
import java.io.File;
import java.io.FileInputStream;
import java.util.Set;
import java.util.Map.Entry;
+import javax.xml.xpath.XPath;
+
public class ApkBuilder extends BaseBuilder {
public static final String ID = "com.android.ide.eclipse.adt.ApkBuilder"; //$NON-NLS-1$
// we need to test all three, as we may need to make the final package
// but not the intermediary ones.
if (mPackageResources || mConvertToDex || mBuildFinalPackage) {
+ // resource to the AndroidManifest.xml file
+ IFile manifestFile = project.getFile(AndroidConstants.FN_ANDROID_MANIFEST);
+
+ if (manifestFile == null || manifestFile.exists() == false) {
+ // mark project and exit
+ String msg = String.format(Messages.s_File_Missing,
+ AndroidConstants.FN_ANDROID_MANIFEST);
+ markProject(AndroidConstants.MARKER_PACKAGING, msg, IMarker.SEVERITY_ERROR);
+ return referencedProjects;
+ }
+
IPath binLocation = outputFolder.getLocation();
if (binLocation == null) {
markProject(AndroidConstants.MARKER_PACKAGING, Messages.Output_Missing,
// 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(AndroidConstants.MARKER_PACKAGING, msg, IMarker.SEVERITY_ERROR);
- return referencedProjects;
- }
-
// get the resource folder
- IFolder resFolder = project.getFolder(
- AndroidConstants.WS_RESOURCES);
+ IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES);
// and the assets folder
- IFolder assetsFolder = project.getFolder(
- AndroidConstants.WS_ASSETS);
+ IFolder assetsFolder = project.getFolder(AndroidConstants.WS_ASSETS);
// we need to make sure this one exists.
if (assetsFolder.exists() == false) {
}
IPath resLocation = resFolder.getLocation();
- IPath manifestLocation = manifestResource.getLocation();
+ IPath manifestLocation = manifestFile.getLocation();
if (resLocation != null && manifestLocation != null) {
String osResPath = resLocation.toOSString();
saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex);
}
+ // figure out whether the application is debuggable.
+ // It is considered debuggable if the attribute debuggable is set to true
+ // in the manifest
+ boolean debuggable = false;
+ XPath xpath = AndroidXPathFactory.newXPath();
+ String result = xpath.evaluate(
+ "/" + AndroidManifest.NODE_MANIFEST + //$NON-NLS-1$
+ "/" + AndroidManifest.NODE_APPLICATION + //$NON-NLS-1$
+ "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + //$NON-NLS-1$
+ ":" + AndroidManifest.ATTRIBUTE_DEBUGGABLE, //$NON-NLS-1$
+ new InputSource(manifestFile.getContents()));
+ if (result.length() > 0) {
+ debuggable = Boolean.valueOf(result);
+ }
+
// now we need to make the final package from the intermediary apk
// and classes.dex.
// This is the default package with all the resources.
AndroidConstants.FN_CLASSES_DEX;
if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
classesDexPath,osFinalPackagePath, javaProject,
- referencedJavaProjects) == false) {
+ referencedJavaProjects, debuggable) == false) {
return referencedProjects;
}
String apkOsFilePath = osBinPath + File.separator +
ProjectHelper.getApkFilename(project, entry.getKey());
if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject,
- referencedJavaProjects) == false) {
+ referencedJavaProjects, debuggable) == false) {
return referencedProjects;
}
}
* @param output The path to the final package file to create.
* @param javaProject
* @param referencedJavaProjects
+ * @param debuggable
* @return true if success, false otherwise.
*/
private boolean finalPackage(String intermediateApk, String dex, String output,
- final IJavaProject javaProject, IJavaProject[] referencedJavaProjects) {
+ final IJavaProject javaProject, IJavaProject[] referencedJavaProjects,
+ boolean debuggable) {
FileOutputStream fos = null;
try {
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
// look inside and put .so in lib/* by keeping the relative folder path.
- writeNativeLibraries((IFolder) libFolder, builder);
+ writeNativeLibraries((IFolder) libFolder, builder, debuggable);
}
// close the jar file and write the manifest and sign it.
* The path in the archive is based on the ABI folder name, and located under a main
* folder called "lib".
*
- * This method also packages any "gdbserver" executable it finds in the ABI folders.
+ * This method also packages any "gdbserver" executable it finds in the ABI folders, if
+ * <var>debuggable</var> is set to true.
*
* @param rootFolder The folder containing the native libraries.
* @param jarBuilder the {@link SignedJarBuilder} used to create the archive.
+ * @param debuggable whether the application is debuggable. If <code>true</code> then gdbserver
+ * executables will be packaged as well.
* @throws CoreException
* @throws IOException
*/
- private void writeNativeLibraries(IFolder rootFolder, SignedJarBuilder jarBuilder)
+ private void writeNativeLibraries(IFolder rootFolder, SignedJarBuilder jarBuilder,
+ boolean debuggable)
throws CoreException, IOException {
// the native files must be under a single sub-folder under the main root folder.
// the sub-folder represents the abi for the native libs
// check the extension.
String ext = path.getFileExtension();
if (AndroidConstants.EXT_NATIVE_LIB.equalsIgnoreCase(ext) ||
- GDBSERVER_NAME.equals(lib.getName())) {
+ (debuggable && GDBSERVER_NAME.equals(lib.getName()))) {
// compute the path inside the archive.
IPath apkPath = new Path(SdkConstants.FD_APK_NATIVE_LIBS);
apkPath = apkPath.append(abi.getName()).append(lib.getName());
<!-- Name of the application package extracted from manifest file -->
<xpath input="AndroidManifest.xml" expression="/manifest/@package"
output="manifest.package" />
+ <!-- Value of the debuggable attribute (Application node) extracted from manifest file -->
+ <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:debuggable"
+ output="manifest.debuggable" default="false"/>
<!-- Input directories -->
<property name="source.dir" value="src" />
<!-- This is macro that enable passing variable list of external jar files to ApkBuilder
Example of use:
- <package-helper sign.package="true" debug.mode="true">
+ <package-helper sign.package="true">
<extra-jars>
<jarfolder path="my_jars" />
<jarfile path="foo/bar.jar" />
</package-helper> -->
<macrodef name="package-helper">
<attribute name="sign.package" />
- <attribute name="debug.mode" />
<element name="extra-jars" optional="yes" />
<sequential>
<apkbuilder
outfolder="${out.absolute.dir}"
basename="${ant.project.name}"
signed="@{sign.package}"
- debug="@{debug.mode}"
+ debug="${manifest.debuggable}"
verbose="${verbose}">
<file path="${intermediate.dex.file}" />
<sourcefolder path="${source.absolute.dir}" />
<!-- Packages the application and sign it with a debug key. -->
<target name="-package-debug-sign" depends="-dex, -package-resources">
- <package-helper sign.package="true" debug.mode="true" />
+ <package-helper sign.package="true" />
</target>
<!-- Packages the application without signing it. -->
<target name="-package-release" depends="-dex, -package-resources">
- <package-helper sign.package="false" debug.mode="false" />
+ <package-helper sign.package="false" />
</target>
<target name="-compile-tested-if-test" if="tested.project.dir" unless="do.not.compile.again">
<!-- Invoked from external files for code coverage purposes -->
<target name="-package-with-emma" depends="-dex-instrumented, -package-resources">
- <package-helper sign.package="true" debug.mode="true">
+ <package-helper sign.package="true">
<extra-jars>
<!-- Injected from external file -->
<jarfile path="${emma.dir}/emma_device.jar" />