diff options
7 files changed, 128 insertions, 86 deletions
diff --git a/changelog.txt b/changelog.txt index e8d0b4a..ea7659f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,6 @@ 0.7.0 - Switch to ProGuard 4.10 + - Added ability to test proguarded (obfuscated) apps. - Jar files are now pre-dexed for faster dexing. - First pass at NDK integration diff --git a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy index b8a6c1d..de4a457 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy @@ -606,7 +606,7 @@ public abstract class BasePlugin { project.file( "$project.buildDir/libs/${project.archivesBaseName}-${variantData.baseName}.ap_") } - if (variantData.runProguard) { + if (variantConfiguration.buildType.runProguard) { processResources.conventionMapping.proguardOutputFile = { project.file("$project.buildDir/proguard/${variantData.dirName}/aapt_rules.txt") } @@ -1160,10 +1160,12 @@ public abstract class BasePlugin { */ protected void addPackageTasks(@NonNull ApkVariantData variantData, @Nullable Task assembleTask) { - VariantConfiguration variantConfig = variantData.variantConfiguration - boolean runProguard = !(variantData instanceof TestVariantData) && variantConfig.buildType.runProguard + boolean runProguard = variantConfig.buildType.runProguard && + (variantConfig.type != VariantConfiguration.Type.TEST || + (variantConfig.type == VariantConfiguration.Type.TEST && + variantConfig.testedConfig.type != VariantConfiguration.Type.LIBRARY)) // common dex task configuration String dexTaskName = "dex${variantData.name}" @@ -1182,7 +1184,8 @@ public abstract class BasePlugin { if (runProguard) { // first proguard task. - File outFile = createProguardTasks(variantData, variantConfig) + BaseVariantData testedVariantData = variantData instanceof TestVariantData ? variantData.testedVariantData : null as BaseVariantData + File outFile = createProguardTasks(variantData, testedVariantData) // then dexing task dexTask.dependsOn variantData.proguardTask @@ -1348,16 +1351,25 @@ public abstract class BasePlugin { /** * Creates the proguarding task for the given Variant. * @param variantData the variant data. - * @param variantConfig the variant configuration of variantData + * @param testedVariantData optional. variant data representing the tested variant, null if the + * variant is not a test variant * @return outFile file outputted by proguard */ @NonNull protected File createProguardTasks(@NonNull BaseVariantData variantData, - @NonNull VariantConfiguration variantConfig) { - def proguardTask = project.tasks.create("proguard${variantData.name}", ProGuardTask); + @Nullable BaseVariantData testedVariantData) { + VariantConfiguration variantConfig = variantData.variantConfiguration + + def proguardTask = project.tasks.create("proguard${variantData.name}", ProGuardTask) proguardTask.dependsOn variantData.javaCompileTask + if (testedVariantData != null) { + proguardTask.dependsOn testedVariantData.proguardTask + } + variantData.proguardTask = proguardTask + // --- Output File --- + File outFile; if (variantData instanceof LibraryVariantData) { outFile = project.file( @@ -1367,82 +1379,110 @@ public abstract class BasePlugin { "${project.buildDir}/classes-proguard/${variantData.dirName}/classes.jar") } - // because the Proguard task acts on all the config right away and not when the - // task actually runs, let's configure it in its doFirst - proguardTask.doFirst { - // all the config files coming from build type, product flavors. - List<Object> proguardFiles = variantConfig.getProguardFiles(true /*includeLibs*/); - for (Object proguardFile : proguardFiles) { - proguardTask.configuration(proguardFile) - } + // --- Proguard Config --- - // also the config file output by aapt - proguardTask.configuration(variantData.processResourcesTask.proguardOutputFile) + if (testedVariantData != null) { + // don't remove any code in tested app + proguardTask.dontshrink() + proguardTask.keepnames("class * extends junit.framework.TestCase") + proguardTask.keepclassmembers("class * extends junit.framework.TestCase {\n" + + " void test*(...);\n" + + "}") - List<File> packagedJars = getAndroidBuilder(variantData).getPackagedJars(variantConfig) + // input the mapping from the tested app so that we can deal with obfuscated code + proguardTask.applymapping("${project.buildDir}/proguard/${testedVariantData.dirName}/mapping.txt") - if (variantData instanceof LibraryVariantData) { - String packageName = variantConfig.getPackageFromManifest() - if (packageName == null) { - throw new BuildException("Failed to read manifest", null) - } - packageName = packageName.replace('.', '/'); - - // injar: the compilation output - // exclude R files and such from output - String exclude = '!' + packageName + "/R.class" - exclude += (', !' + packageName + "/R\$*.class") - exclude += (', !' + packageName + "/Manifest.class") - exclude += (', !' + packageName + "/Manifest\$*.class") - exclude += (', !' + packageName + "/BuildConfig.class") - proguardTask.injars(variantData.javaCompileTask.destinationDir, filter: exclude) - - // include R files and such for compilation - String include = exclude.replace('!', '') - proguardTask.libraryjars(variantData.javaCompileTask.destinationDir, filter: include) - - - // injar: the local dependencies, filter out local jars from packagedJars - Object[] jars = LibraryPlugin.getLocalJarFileList(variantData.variantDependency) - for (Object inJar : jars) { - if (packagedJars.contains(inJar)) { - packagedJars.remove(inJar); - } - proguardTask.injars((File) inJar, filter: '!META-INF/MANIFEST.MF') - } + // for tested app, we only care about their aapt config since the base + // configs are the same files anyway. + proguardTask.configuration(testedVariantData.processResourcesTask.proguardOutputFile) + } - // libjar: the library dependencies - for (File libJar : packagedJars) { - proguardTask.libraryjars(libJar, filter: '!META-INF/MANIFEST.MF') - } + // all the config files coming from build type, product flavors. + List<Object> proguardFiles = variantConfig.getProguardFiles(true /*includeLibs*/) + for (Object proguardFile : proguardFiles) { + proguardTask.configuration(proguardFile) + } - // ensure local jars keep their package names - proguardTask.keeppackagenames() - } else { - // injar: the compilation output - proguardTask.injars(variantData.javaCompileTask.destinationDir) + // also the config file output by aapt + proguardTask.configuration(variantData.processResourcesTask.proguardOutputFile) + + // --- InJars / LibraryJars --- - // injar: the dependencies - for (File inJar : packagedJars) { - proguardTask.injars(inJar, filter: '!META-INF/MANIFEST.MF') + List<File> packagedJars = getAndroidBuilder(variantData).getPackagedJars(variantConfig) + + if (variantData instanceof LibraryVariantData) { + String packageName = variantConfig.getPackageFromManifest() + if (packageName == null) { + throw new BuildException("Failed to read manifest", null) + } + packageName = packageName.replace('.', '/'); + + // injar: the compilation output + // exclude R files and such from output + String exclude = '!' + packageName + "/R.class" + exclude += (', !' + packageName + "/R\$*.class") + exclude += (', !' + packageName + "/Manifest.class") + exclude += (', !' + packageName + "/Manifest\$*.class") + exclude += (', !' + packageName + "/BuildConfig.class") + proguardTask.injars(variantData.javaCompileTask.destinationDir, filter: exclude) + + // include R files and such for compilation + String include = exclude.replace('!', '') + proguardTask.libraryjars(variantData.javaCompileTask.destinationDir, filter: include) + + // injar: the local dependencies, filter out local jars from packagedJars + Object[] jars = LibraryPlugin.getLocalJarFileList(variantData.variantDependency) + for (Object inJar : jars) { + if (packagedJars.contains(inJar)) { + packagedJars.remove(inJar); } + proguardTask.injars((File) inJar, filter: '!META-INF/MANIFEST.MF') } - // libraryJars: the runtime jars - for (String runtimeJar : getRuntimeJarList()) { - proguardTask.libraryjars(runtimeJar) + // libjar: the library dependencies + for (File libJar : packagedJars) { + proguardTask.libraryjars(libJar, filter: '!META-INF/MANIFEST.MF') + } + + // ensure local jars keep their package names + proguardTask.keeppackagenames() + } else { + // injar: the compilation output + proguardTask.injars(variantData.javaCompileTask.destinationDir) + + // injar: the dependencies + for (File inJar : packagedJars) { + proguardTask.injars(inJar, filter: '!META-INF/MANIFEST.MF') } + } - proguardTask.outjars(outFile) + // libraryJars: the runtime jars + for (String runtimeJar : getRuntimeJarList()) { + proguardTask.libraryjars(runtimeJar) + } - proguardTask.dump("${project.buildDir}/proguard/${variantData.dirName}/dump.txt") - proguardTask.printseeds( - "${project.buildDir}/proguard/${variantData.dirName}/seeds.txt") - proguardTask.printusage( - "${project.buildDir}/proguard/${variantData.dirName}/usage.txt") - proguardTask.printmapping( - "${project.buildDir}/proguard/${variantData.dirName}/mapping.txt") + if (testedVariantData != null) { + // input the tested app as library + proguardTask.libraryjars(testedVariantData.javaCompileTask.destinationDir) + // including its dependencies + List<File> testedPackagedJars = getAndroidBuilder(testedVariantData).getPackagedJars(testedVariantData.variantConfiguration) + for (File inJar : testedPackagedJars) { + proguardTask.libraryjars(inJar, filter: '!META-INF/MANIFEST.MF') + } } + + // --- Out files --- + + proguardTask.outjars(outFile) + + proguardTask.dump("${project.buildDir}/proguard/${variantData.dirName}/dump.txt") + proguardTask.printseeds( + "${project.buildDir}/proguard/${variantData.dirName}/seeds.txt") + proguardTask.printusage( + "${project.buildDir}/proguard/${variantData.dirName}/usage.txt") + proguardTask.printmapping( + "${project.buildDir}/proguard/${variantData.dirName}/mapping.txt") + return outFile } diff --git a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy index 69c7c2f..ba86d35 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy +++ b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy @@ -276,7 +276,7 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> { if (variantConfig.buildType.runProguard) { // run proguard on output of compile task - createProguardTasks(variantData, variantConfig) + createProguardTasks(variantData, null) // hack since bundle can't depend on variantData.proguardTask mergeProGuardFileTask.dependsOn variantData.proguardTask diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java index a85d8be..069143e 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java @@ -144,10 +144,6 @@ public abstract class BaseVariantData { return StringHelper.capitalize(variantConfiguration.getBuildType().getName()); } - public boolean getRunProguard() { - return getVariantConfiguration().getBuildType().isRunProguard(); - } - public void setOutputFile(Object file) { outputFile = file; } diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java index dca2d16..ebd336c 100644 --- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java +++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java @@ -87,9 +87,4 @@ public class TestVariantData extends ApkVariantData { public boolean getZipAlign() { return false; } - - @Override - public boolean getRunProguard() { - return false; - } } diff --git a/tests/proguard/src/instrumentTest/java/com/android/tests/basic/MainTest.java b/tests/proguard/src/instrumentTest/java/com/android/tests/basic/MainTest.java index cbbc52b..44bc9f4 100644 --- a/tests/proguard/src/instrumentTest/java/com/android/tests/basic/MainTest.java +++ b/tests/proguard/src/instrumentTest/java/com/android/tests/basic/MainTest.java @@ -38,5 +38,12 @@ public class MainTest extends ActivityInstrumentationTestCase2<Main> { public void testTextViewContent() { assertEquals("1234", mTextView.getText()); } + + /** Test using a obfuscated class */ + public void testObfuscatedCode() { + final Main a = getActivity(); + StringProvider sp = a.getStringProvider(); + assertEquals("42", sp.getString(42)); + } } diff --git a/tests/proguard/src/main/java/com/android/tests/basic/Main.java b/tests/proguard/src/main/java/com/android/tests/basic/Main.java index 6d3ae10..e32404a 100644 --- a/tests/proguard/src/main/java/com/android/tests/basic/Main.java +++ b/tests/proguard/src/main/java/com/android/tests/basic/Main.java @@ -4,20 +4,23 @@ import android.app.Activity; import android.os.Bundle; import android.widget.TextView; -public class Main extends Activity -{ +public class Main extends Activity { private int foo = 1234; + private final StringProvider mStringProvider = new StringProvider(); + /** Called when the activity is first created. */ @Override - public void onCreate(Bundle savedInstanceState) - { + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView tv = (TextView) findViewById(R.id.dateText); - StringProvider stringProvider = new StringProvider(); - tv.setText(stringProvider.getString(foo)); + tv.setText(getStringProvider().getString(foo)); + } + + public StringProvider getStringProvider() { + return mStringProvider; } } |