diff --git a/README.md b/README.md
index 27049d39..ab36f366 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,20 @@ embed('com.facebook.fresco:fresco:1.11.0') {
**More usage see [example](./example).**
+### Resource prefixing (experimental)
+You can enable prefixing of library resources. This can be useful if your fat-aar has a lot of resources that cannot be renamed at the source level. The plugin will add the specified prefix to all internal library resources during build time.
+
+```groovy
+fataar {
+
+ /**
+ * Add prefix for all library resources. To prevent conflicts with a library clients.
+ * @since 1.3.7
+ */
+ resourcePrefix = "lib_main_"
+}
+```
+
## About AAR File
AAR is a file format for android library.
diff --git a/example/app/libs/fat-aar-final.aar b/example/app/libs/fat-aar-final.aar
index b23a3154..b40bde33 100644
Binary files a/example/app/libs/fat-aar-final.aar and b/example/app/libs/fat-aar-final.aar differ
diff --git a/example/app/src/main/java/com/fataar/demo/MainActivity.java b/example/app/src/main/java/com/fataar/demo/MainActivity.java
index a1591236..66876e09 100644
--- a/example/app/src/main/java/com/fataar/demo/MainActivity.java
+++ b/example/app/src/main/java/com/fataar/demo/MainActivity.java
@@ -7,6 +7,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
+import android.util.Log;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
@@ -30,13 +31,16 @@
import com.kezong.demo.libaar.AarFlavor;
import com.kezong.demo.libaar.AarLibClass;
import com.kezong.demo.libaar.KotlinTest2;
+import com.kezong.demo.libaar.LibCountries;
import com.kezong.demo.libaar.TestActivity;
import com.kezong.demo.libaar2.Aar2LibClass;
import com.kezong.demo.libaarlocal.AarLocalLibClass;
import com.kezong.demo.libaarlocal2.AarLocal2LibClass;
+import com.kezong.demo.lib.R.*;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Field;
/**
* @author kezong on 2020/12/11.
@@ -65,6 +69,11 @@ protected void onCreate(Bundle savedInstanceState) {
testAssetsMerge();
testRemoteAar();
testFlavor();
+ testEnum();
+ }
+
+ private void testEnum() {
+ addTestView("enums", "lib flag ee", LibCountries.ESTONIA.getFlagRes() == R.drawable.lib_main_flag_ee);
}
private void testFlavor() {
@@ -162,12 +171,17 @@ public void testKotlinTopLevel2() {
}
public void testResourceMerge() {
+
+ for (Field field : R.string.class.getFields()) {
+ Log.d("R class name:", field.getName());
+ }
+
String text = new AarLibClass().getLibName(this);
- addTestView("resource", text, TextUtils.equals(text, "lib-aar"));
+ addTestView("resource", text, TextUtils.equals(text, "lib-aar eng"));
}
public void testResourceMerge2() {
- String text = this.getResources().getString(R.string.app_name_aar2);
+ String text = this.getResources().getString(R.string.lib_main_app_name_aar2);
addTestView("resource2", text, TextUtils.equals(text, "lib-aar2"));
}
diff --git a/example/build.gradle b/example/build.gradle
index 338a6144..2540820e 100644
--- a/example/build.gradle
+++ b/example/build.gradle
@@ -7,8 +7,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
- classpath 'com.github.kezong:fat-aar:1.3.6'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
+ classpath 'com.github.kezong:fat-aar:1.3.7'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30"
}
}
diff --git a/example/gradle.properties b/example/gradle.properties
index d015431a..e4ed8faf 100644
--- a/example/gradle.properties
+++ b/example/gradle.properties
@@ -1,2 +1,4 @@
android.useAndroidX=true
-android.enableJetifier=true
\ No newline at end of file
+android.enableJetifier=true
+org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
+
diff --git a/example/lib-aar/src/main/AndroidManifest.xml b/example/lib-aar/src/main/AndroidManifest.xml
index 52c10332..80e7c2f2 100644
--- a/example/lib-aar/src/main/AndroidManifest.xml
+++ b/example/lib-aar/src/main/AndroidManifest.xml
@@ -7,6 +7,6 @@
+ android:theme="@style/LibAarTheme" />
diff --git a/example/lib-aar/src/main/java/com/kezong/demo/libaar/AarLibClass.java b/example/lib-aar/src/main/java/com/kezong/demo/libaar/AarLibClass.java
index bdf29fd9..6e8c569e 100644
--- a/example/lib-aar/src/main/java/com/kezong/demo/libaar/AarLibClass.java
+++ b/example/lib-aar/src/main/java/com/kezong/demo/libaar/AarLibClass.java
@@ -12,4 +12,8 @@ public class AarLibClass {
public String getLibName(Context ctx) {
return ctx.getResources().getString(R.string.app_name_aar);
}
+
+ public String getTestString(Context ctx) {
+ return ctx.getResources().getString(R.string.lib_aar_test_string1);
+ }
}
diff --git a/example/lib-aar/src/main/java/com/kezong/demo/libaar/LibCountries.kt b/example/lib-aar/src/main/java/com/kezong/demo/libaar/LibCountries.kt
new file mode 100644
index 00000000..90634c09
--- /dev/null
+++ b/example/lib-aar/src/main/java/com/kezong/demo/libaar/LibCountries.kt
@@ -0,0 +1,25 @@
+package com.kezong.demo.libaar
+
+import android.content.Context
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import java.io.Serializable
+
+enum class LibCountries(
+ val code: String,
+ @StringRes val nameRes: Int,
+ @DrawableRes val flagRes: Int,
+ vararg phonePrefix: String,
+) : Serializable {
+
+ ESTONIA("ee", R.string.country_ee, R.drawable.flag_ee, "+397"),
+ USA("us", R.string.country_us, R.drawable.flag_us, "+1");
+
+ fun getName(context: Context): String = context.getString(nameRes)
+
+ companion object {
+
+ @JvmStatic
+ fun findByCode(countryCode: String?) = values().find { it.code.equals(countryCode, true) }
+ }
+}
\ No newline at end of file
diff --git a/example/lib-aar/src/main/java/com/kezong/demo/libaar/TestActivity.java b/example/lib-aar/src/main/java/com/kezong/demo/libaar/TestActivity.java
index 0618496e..330e1bab 100644
--- a/example/lib-aar/src/main/java/com/kezong/demo/libaar/TestActivity.java
+++ b/example/lib-aar/src/main/java/com/kezong/demo/libaar/TestActivity.java
@@ -4,6 +4,10 @@
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import com.kezong.demo.libaar.databinding.DatabindingBinding;
@@ -13,11 +17,30 @@ public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
+ setTheme(R.style.LibAarTheme_Main);
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.databinding);
User user = new User();
user.setName("Hello World");
user.setSex("[success][dataBinding] male");
binding.setUser(user);
+
+ for (LibCountries country : LibCountries.values()) {
+ binding.container.addView(getCountryView(country));
+ }
+ }
+
+ private View getCountryView(LibCountries country) {
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+ TextView textView = new TextView(this);
+ textView.setText(country.getName(this));
+ ImageView imageView = new ImageView(this);
+ imageView.setImageResource(country.getFlagRes());
+
+ layout.addView(textView);
+ layout.addView(imageView);
+
+ return layout;
}
}
diff --git a/example/lib-aar/src/main/res/drawable-hdpi/flag_ee.png b/example/lib-aar/src/main/res/drawable-hdpi/flag_ee.png
new file mode 100644
index 00000000..facef6c7
Binary files /dev/null and b/example/lib-aar/src/main/res/drawable-hdpi/flag_ee.png differ
diff --git a/example/lib-aar/src/main/res/drawable-hdpi/flag_us.png b/example/lib-aar/src/main/res/drawable-hdpi/flag_us.png
new file mode 100644
index 00000000..310d216c
Binary files /dev/null and b/example/lib-aar/src/main/res/drawable-hdpi/flag_us.png differ
diff --git a/example/lib-aar/src/main/res/drawable/lib_background.xml b/example/lib-aar/src/main/res/drawable/lib_background.xml
new file mode 100644
index 00000000..8659eb59
--- /dev/null
+++ b/example/lib-aar/src/main/res/drawable/lib_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/lib-aar/src/main/res/layout/databinding.xml b/example/lib-aar/src/main/res/layout/databinding.xml
index f4c534c9..3beb1c92 100644
--- a/example/lib-aar/src/main/res/layout/databinding.xml
+++ b/example/lib-aar/src/main/res/layout/databinding.xml
@@ -1,19 +1,29 @@
-
+
+
diff --git a/example/lib-aar/src/main/res/layout/test_layout.xml b/example/lib-aar/src/main/res/layout/test_layout.xml
index 8c1f1488..61a0028a 100644
--- a/example/lib-aar/src/main/res/layout/test_layout.xml
+++ b/example/lib-aar/src/main/res/layout/test_layout.xml
@@ -1,10 +1,14 @@
-
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
\ No newline at end of file
diff --git a/example/lib-aar/src/main/res/values-en/strings.xml b/example/lib-aar/src/main/res/values-en/strings.xml
new file mode 100644
index 00000000..53c557ff
--- /dev/null
+++ b/example/lib-aar/src/main/res/values-en/strings.xml
@@ -0,0 +1,6 @@
+
+
+ lib-aar eng
+ lib aar test string value eng
+ @string/lib_aar_test_string1
+
\ No newline at end of file
diff --git a/example/lib-aar/src/main/res/values/colors.xml b/example/lib-aar/src/main/res/values/colors.xml
new file mode 100644
index 00000000..78f6bae4
--- /dev/null
+++ b/example/lib-aar/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ @android:color/white
+ #ff0000
+
\ No newline at end of file
diff --git a/example/lib-aar/src/main/res/values/dimens.xml b/example/lib-aar/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..8119e451
--- /dev/null
+++ b/example/lib-aar/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 10dp
+ @dimen/corner_radius
+
\ No newline at end of file
diff --git a/example/lib-aar/src/main/res/values/strings.xml b/example/lib-aar/src/main/res/values/strings.xml
index 87f8203e..b17082de 100644
--- a/example/lib-aar/src/main/res/values/strings.xml
+++ b/example/lib-aar/src/main/res/values/strings.xml
@@ -1,3 +1,7 @@
lib-aar
+ lib aar test string value
+ @string/lib_aar_test_string1
+ Estonia
+ USA
diff --git a/example/lib-aar/src/main/res/values/style.xml b/example/lib-aar/src/main/res/values/style.xml
new file mode 100644
index 00000000..69ff03c7
--- /dev/null
+++ b/example/lib-aar/src/main/res/values/style.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/lib-aar2/src/main/res/drawable/im_cat.jpg b/example/lib-aar2/src/main/res/drawable/im_cat.jpg
new file mode 100644
index 00000000..ce05f88d
Binary files /dev/null and b/example/lib-aar2/src/main/res/drawable/im_cat.jpg differ
diff --git a/example/lib-aar2/src/main/res/drawable/simple_drawable.xml b/example/lib-aar2/src/main/res/drawable/simple_drawable.xml
new file mode 100644
index 00000000..a8b409b1
--- /dev/null
+++ b/example/lib-aar2/src/main/res/drawable/simple_drawable.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/example/lib-aar2/src/main/res/layout/simple_layout.xml b/example/lib-aar2/src/main/res/layout/simple_layout.xml
new file mode 100644
index 00000000..0b2ce591
--- /dev/null
+++ b/example/lib-aar2/src/main/res/layout/simple_layout.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/example/lib-aar2/src/main/res/values/colors.xml b/example/lib-aar2/src/main/res/values/colors.xml
new file mode 100644
index 00000000..eb68020b
--- /dev/null
+++ b/example/lib-aar2/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ @android:color/black
+ @color/my_test_color
+
\ No newline at end of file
diff --git a/example/lib-aar2/src/main/res/values/strings.xml b/example/lib-aar2/src/main/res/values/strings.xml
index 605cddd8..f39fa94a 100644
--- a/example/lib-aar2/src/main/res/values/strings.xml
+++ b/example/lib-aar2/src/main/res/values/strings.xml
@@ -1,3 +1,4 @@
lib-aar2
+ lib string 1
diff --git a/example/lib-aar2/src/main/res/values/styles.xml b/example/lib-aar2/src/main/res/values/styles.xml
new file mode 100644
index 00000000..f8ebf05d
--- /dev/null
+++ b/example/lib-aar2/src/main/res/values/styles.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/lib-main/build.gradle b/example/lib-main/build.gradle
index 28ba820b..7f2c9f50 100644
--- a/example/lib-main/build.gradle
+++ b/example/lib-main/build.gradle
@@ -10,11 +10,11 @@ repositories {
}
android {
- compileSdkVersion 29
+ compileSdkVersion 31
defaultConfig {
minSdkVersion 16
- targetSdkVersion 27
+ targetSdkVersion 31
versionCode 1
versionName "1.0.0"
}
@@ -44,6 +44,15 @@ android {
exclude 'lib/armeabi/*.so'
exclude 'lib/arm64-v8a/*.so'
}
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_11
+ }
}
afterEvaluate {
@@ -71,6 +80,12 @@ fataar {
* @since 1.3.0
*/
transitive = true
+
+ /**
+ * Add prefix for all library resources. To prevent conflicts with a library clients.
+ * @since 1.3.7
+ */
+ resourcePrefix = "lib_main_"
}
dependencies {
diff --git a/source/gradle.properties b/source/gradle.properties
index 0e311803..12dccc6c 100644
--- a/source/gradle.properties
+++ b/source/gradle.properties
@@ -1,3 +1,3 @@
PUBLISH_GROUP_ID=com.github.kezong
PUBLISH_ARTIFACT_ID=fat-aar
-PUBLISH_VERSION=1.3.6
+PUBLISH_VERSION=1.3.7
diff --git a/source/src/main/groovy/com/kezong/fataar/FatAarExtension.groovy b/source/src/main/groovy/com/kezong/fataar/FatAarExtension.groovy
index 00e25716..432c9069 100644
--- a/source/src/main/groovy/com/kezong/fataar/FatAarExtension.groovy
+++ b/source/src/main/groovy/com/kezong/fataar/FatAarExtension.groovy
@@ -25,4 +25,10 @@ class FatAarExtension {
* @since 1.3.0
*/
boolean transitive = false
+
+ /**
+ * Add prefix for all library resources. To prevent conflicts with a library clients.
+ * @since 1.3.7
+ */
+ String resourcePrefix = ""
}
diff --git a/source/src/main/groovy/com/kezong/fataar/VariantProcessor.groovy b/source/src/main/groovy/com/kezong/fataar/VariantProcessor.groovy
index 63d71eda..8609e4b3 100755
--- a/source/src/main/groovy/com/kezong/fataar/VariantProcessor.groovy
+++ b/source/src/main/groovy/com/kezong/fataar/VariantProcessor.groovy
@@ -3,6 +3,8 @@ package com.kezong.fataar
import com.android.build.gradle.api.LibraryVariant
import com.android.build.gradle.internal.api.DefaultAndroidSourceSet
import com.android.build.gradle.tasks.ManifestProcessorTask
+import groovy.xml.XmlParser
+import groovy.xml.XmlUtil
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ResolvedArtifact
@@ -35,6 +37,8 @@ class VariantProcessor {
private Collection mExplodeTasks = new ArrayList<>()
+ private HashSet renamedResources = new HashSet()
+
private VersionAdapter mVersionAdapter
private TaskProvider mMergeClassTask
@@ -70,6 +74,7 @@ class VariantProcessor {
}
processManifest()
processResources()
+ processResourcePrefixing()
processAssets()
processJniLibs()
processConsumerProguard()
@@ -79,7 +84,7 @@ class VariantProcessor {
}
private static void printEmbedArtifacts(Collection artifacts,
- Collection dependencies) {
+ Collection dependencies) {
Collection moduleNames = artifacts.stream().map { it.moduleVersion.id.name }.collect()
dependencies.each { dependency ->
if (!moduleNames.contains(dependency.moduleName)) {
@@ -192,17 +197,19 @@ class VariantProcessor {
private void transformRClasses(RClassesTransform transform, TaskProvider transformTask, TaskProvider bundleTask, TaskProvider reBundleTask) {
transform.putTargetPackage(mVariant.name, mVariant.getApplicationId())
+ transform.putResourcesPrefix(mProject.fataar.resourcePrefix)
transformTask.configure {
- doFirst {
- // library package name parsed by aar's AndroidManifest.xml
- // so must put after explode tasks perform.
- Collection libraryPackages = mAndroidArchiveLibraries
- .stream()
- .map { it.packageName }
- .collect()
- transform.putLibraryPackages(mVariant.name, libraryPackages);
- }
- }
+ doFirst {
+ // library package name parsed by aar's AndroidManifest.xml
+ // so must put after explode tasks perform.
+ Collection libraryPackages = mAndroidArchiveLibraries
+ .stream()
+ .map { it.packageName }
+ .collect()
+ transform.putLibraryPackages(mVariant.name, libraryPackages);
+ transform.putRenamedResources(renamedResources)
+ }
+ }
bundleTask.configure {
finalizedBy(reBundleTask)
}
@@ -251,7 +258,7 @@ class VariantProcessor {
static def getTaskDependency(ResolvedArtifact artifact) {
try {
return artifact.buildDependencies
- } catch(MissingPropertyException ignore) {
+ } catch (MissingPropertyException ignore) {
// since gradle 6.8.0, property is changed;
return artifact.builtBy
}
@@ -313,13 +320,8 @@ class VariantProcessor {
}
}
- /**
- * merge manifest
- */
- private void processManifest() {
- ManifestProcessorTask processManifestTask = mVersionAdapter.getProcessManifest()
-
- File manifestOutput
+ private File getManifestOutputDir() {
+ def manifestOutput
if (FatUtils.compareVersion(VersionAdapter.AGPVersion, "4.2.0-alpha07") >= 0) {
manifestOutput = mProject.file("${mProject.buildDir.path}/intermediates/merged_manifest/${mVariant.name}/AndroidManifest.xml")
} else if (FatUtils.compareVersion(VersionAdapter.AGPVersion, "3.3.0") >= 0) {
@@ -328,6 +330,17 @@ class VariantProcessor {
manifestOutput = mProject.file(processManifestTask.getManifestOutputDirectory().absolutePath + "/AndroidManifest.xml")
}
+ return manifestOutput
+ }
+
+ /**
+ * merge manifest
+ */
+ private void processManifest() {
+ ManifestProcessorTask processManifestTask = mVersionAdapter.getProcessManifest()
+
+ File manifestOutput = getManifestOutputDir()
+
final List inputManifests = new ArrayList<>()
for (archiveLibrary in mAndroidArchiveLibraries) {
inputManifests.add(archiveLibrary.getManifest())
@@ -346,6 +359,12 @@ class VariantProcessor {
processManifestTask.doLast {
// Merge manifests
manifestsMergeTask.get().doTaskAction()
+
+ String prefix = mProject.fataar.resourcePrefix
+
+ if (prefix != null && !prefix.isEmpty()) {
+ modifyResourceUsage(getManifestOutputDir(), prefix)
+ }
}
}
@@ -359,7 +378,7 @@ class VariantProcessor {
if (kotlinCompile != null) {
dependsOn(kotlinCompile)
}
- } catch(Exception ignore) {
+ } catch (Exception ignore) {
}
@@ -476,6 +495,7 @@ class VariantProcessor {
if (sourceSet.name == mVariant.name) {
for (archiveLibrary in mAndroidArchiveLibraries) {
FatUtils.logInfo("Merge resource,Library res:${archiveLibrary.resFolder}")
+
sourceSet.res.srcDir(archiveLibrary.resFolder)
}
}
@@ -483,6 +503,171 @@ class VariantProcessor {
}
}
+ private void processResourcePrefixing() {
+
+ String prefix = mProject.fataar.resourcePrefix
+
+ if (prefix.isEmpty()) {
+ println("[fat-aar] Resource prefix is empty. Skip resource modifying.")
+ return
+ }
+
+ String preBuildPath = "package" + mVariant.name.capitalize() + "Resources"
+ TaskProvider packageResourcesTask = mProject.tasks.named(preBuildPath)
+ if (packageResourcesTask == null) {
+ throw new RuntimeException("Can not find task ${taskPath}!")
+ }
+
+ packageResourcesTask.configure {
+
+ doFirst {
+ def renamedResCount = 0
+
+ mProject.android.sourceSets.each { DefaultAndroidSourceSet sourceSet ->
+ if (sourceSet.name == mVariant.name) {
+ sourceSet.res.sourceFiles.files.each { resFile ->
+ renamedResCount += addPrefixByFile(resFile, prefix)
+ }
+ }
+ }
+
+ mProject.android.sourceSets.each { DefaultAndroidSourceSet sourceSet ->
+ if (sourceSet.name == mVariant.name) {
+ sourceSet.res.sourceFiles.files.each { resFile ->
+ modifyResourceUsage(resFile, prefix)
+ }
+ }
+ }
+
+ println("[fat-aar] Prefix was added to $renamedResCount resources")
+ }
+ }
+ }
+
+ private int addPrefixByFile(File file, String prefix) {
+ def renamedResCount = 0
+ renamedResources.add(file.name.split("\\.").first())
+
+ File newFile
+ if (!file.name.startsWith(prefix)) {
+
+ String newPath = file.path.replace(file.name, prefix + file.name)
+ newFile = new File(newPath)
+ file.renameTo(newFile)
+
+ renamedResCount++
+ } else {
+ newFile = file
+ }
+
+ if (newFile.name.endsWith(".xml")) {
+ renamedResCount += addPrefixForResources(newFile, prefix)
+ }
+
+ return renamedResCount
+ }
+
+ private int addPrefixForResources(File file, String prefix) {
+
+ def renamedResCount = 0
+
+ if (prefix.isEmpty()) return renamedResCount
+
+ def parser = new XmlParser()
+ def root = parser.parse(file)
+ def wasModified = false
+
+ if (root.name() == "resources") {
+ root.each { resourceElement ->
+ String name = resourceElement.attribute("name")
+
+ if (resourceTypes.contains(resourceElement.name())
+ && name != null
+ && !name.isEmpty()
+ && !name.startsWith(prefix)) {
+
+ renamedResources.add(name)
+ renamedResources.add(name.replace(".", "_"))
+ resourceElement.@name = prefix + name
+ renamedResCount++
+ wasModified = true
+ }
+ }
+ }
+
+ if (wasModified) {
+ file.withWriter { outWriter ->
+ XmlUtil.serialize(root, outWriter)
+ }
+ }
+
+ return renamedResCount
+ }
+
+ private void modifyResourceUsage(File file, String prefix) {
+ if (!file.name.endsWith(".xml")) return
+
+ def parser = new XmlParser()
+ def root = parser.parse(file)
+ def wasModified = false
+
+ wasModified = addPrefixForAllNodeResUsage(root, prefix)
+ if (wasModified) {
+ file.withWriter { outWriter ->
+ XmlUtil.serialize(root, outWriter)
+ }
+ }
+ }
+
+ private boolean addPrefixForAllNodeResUsage(Node rootNode, String prefix) {
+ def wasModified = false
+ def nodeValue = rootNode.text()
+
+ rootNode.attributes().each { attr ->
+ def isParentStyle = attr.key == "parent" && renamedResources.contains(attr.value)
+
+ if (isParentStyle || usesInternalResource(attr.value)) {
+ attr.value = addPrefixForResourceUsage(attr.value, prefix)
+ wasModified = true
+ }
+ }
+
+ if (usesInternalResource(nodeValue)) {
+ rootNode.setValue(addPrefixForResourceUsage(nodeValue, prefix))
+ wasModified = true
+ } else {
+ rootNode.each { subNode ->
+ if (subNode instanceof Node)
+ wasModified = addPrefixForAllNodeResUsage(subNode, prefix) || wasModified
+ }
+ }
+ return wasModified
+ }
+
+ private boolean usesInternalResource(String tagValue) {
+ def splitedName = tagValue.split("/")
+ def resType = splitedName[0]
+ if (resType != null && !resType.isEmpty() && resType.startsWith("@")) {
+
+ def key = resType.replace("@", "")
+ .replace("+", "")
+ .toLowerCase()
+
+ return renamedResources.contains(splitedName.last()) && resourceTypes.contains(key)
+ }
+ return false
+ }
+
+ private static String addPrefixForResourceUsage(String resRef, String prefix) {
+ def resPath = resRef.split("/")
+ def resName = resPath.last()
+ return resRef.replace(resName, prefix + resName)
+ }
+
+ private static Set resourceTypes = new HashSet(Arrays.asList("anim", "style", "animator", "array", "bool", "color", "dimen",
+ "drawable", "font", "fraction", "id", "integer", "interpolator", "layout", "menu", "mipmap", "navigation",
+ "plurals", "raw", "string", "styleable", "transition", "xml")) // except attr
+
/**
* merge assets
*
@@ -578,7 +763,7 @@ class VariantProcessor {
try {
String mergeName = 'merge' + mVariant.name.capitalize() + 'GeneratedProguardFiles'
mergeGenerateProguardTask = mProject.tasks.named(mergeName)
- } catch(Exception ignore) {
+ } catch (Exception ignore) {
return
}
diff --git a/source/src/main/java/com/kezong/fataar/RClassesTransform.java b/source/src/main/java/com/kezong/fataar/RClassesTransform.java
index c21a72d0..a2f33820 100644
--- a/source/src/main/java/com/kezong/fataar/RClassesTransform.java
+++ b/source/src/main/java/com/kezong/fataar/RClassesTransform.java
@@ -15,12 +15,16 @@
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -59,6 +63,10 @@ public class RClassesTransform extends Transform {
private final Map> libraryPackageMap = new HashMap<>();
+ private String resourcePrefix = null;
+
+ private HashSet renamedResources = null;
+
public RClassesTransform(final Project project) {
this.project = project;
}
@@ -66,16 +74,26 @@ public RClassesTransform(final Project project) {
/**
* Different variants have different package names.
* So targetPackageName must set after evaluate
- * @param variantName variant name
+ *
+ * @param variantName variant name
* @param targetPackage main module's package name
*/
public void putTargetPackage(String variantName, String targetPackage) {
targetPackageMap.put(variantName, targetPackage);
}
+ public void putResourcesPrefix(String prefix) {
+ this.resourcePrefix = prefix;
+ }
+
+ public void putRenamedResources(HashSet renamedResources) {
+ this.renamedResources = renamedResources;
+ }
+
/**
* library packages name must set after exploded task perform
- * @param variantName variant name
+ *
+ * @param variantName variant name
* @param libraryPackages sub module's package name, read from AndroidManifest.xml
*/
public void putLibraryPackages(String variantName, Collection libraryPackages) {
@@ -136,7 +154,9 @@ public void transform(TransformInvocation transformInvocation) throws Interrupte
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
constPool.renameClass(transformTable);
+ addPrefixForResourceReads(constPool, resourcePrefix, transformTable.values());
}
+
ctClass.writeFile(outputDir.getAbsolutePath());
} catch (CannotCompileException | NotFoundException | IOException e) {
e.printStackTrace();
@@ -168,6 +188,55 @@ public void transform(TransformInvocation transformInvocation) throws Interrupte
+ "ms");
}
+ private void addPrefixForResourceReads(ConstPool constPool, String resourcePrefix, Collection libRClasses) {
+
+ if (resourcePrefix == null || resourcePrefix.isEmpty()) return;
+
+ final List resourceTypes = Arrays.asList("anim", "animator", "array", "bool", "color", "dimen",
+ "drawable", "font", "fraction", "id", "integer", "interpolator", "layout", "menu", "mipmap", "navigation",
+ "plurals", "raw", "string", "styleable", "transition", "xml", "style"); // except, attr
+
+ for (int i = 1; i < constPool.getSize(); i++) {
+ try {
+ String constClassName = constPool.getFieldrefClassName(i).replace(".", "/");
+
+ if (libRClasses.contains(constClassName)
+ && resourceTypes.contains(constClassName.split("\\$")[1])) {
+
+ String name = constPool.getFieldrefName(i);
+ String newName = resourcePrefix + name;
+ constPool.renameClass(name, newName);
+ int nameId = constPool.getNameAndTypeName(constPool.getFieldrefNameAndType(i));
+
+ try {
+ Method getItemMethod = constPool.getClass()
+ .getDeclaredMethod("getItem", int.class);
+ getItemMethod.setAccessible(true);
+
+ Object utf8Info = getItemMethod.invoke(constPool, nameId);
+
+ Field classPoolUtf8NameField = utf8Info.getClass()
+ .getDeclaredField("string");
+
+ classPoolUtf8NameField.setAccessible(true);
+ String classPoolResourceName = (String) classPoolUtf8NameField.get(utf8Info);
+
+ if (renamedResources.contains(classPoolResourceName)) {
+ classPoolUtf8NameField.set(utf8Info, newName);
+ }
+ } catch (IllegalAccessException
+ | InvocationTargetException
+ | NoSuchMethodException
+ | NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (ClassCastException e) {
+ // ignore this
+ }
+ }
+ }
+
private Map buildTransformTable(String variantName) {
String targetPackage = targetPackageMap.get(variantName);
Collection libraryPackages = libraryPackageMap.get(variantName);
diff --git a/source/upload.gradle b/source/upload.gradle
index 03cbfd67..af831ab0 100644
--- a/source/upload.gradle
+++ b/source/upload.gradle
@@ -105,6 +105,7 @@ publishing {
}
}
}
+
signing {
sign publishing.publications
}
\ No newline at end of file