Skip to content

Commit a476aa0

Browse files
committed
feature: support minify enabled
1 parent 07bbc0d commit a476aa0

File tree

11 files changed

+159
-69
lines changed

11 files changed

+159
-69
lines changed

.run/publishExspToMaven.run.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="publishExspToMaven" type="GradleRunConfiguration" factoryName="Gradle">
3+
<ExternalSystemSettings>
4+
<option name="executionName" />
5+
<option name="externalProjectPath" value="$PROJECT_DIR$" />
6+
<option name="externalSystemIdString" value="GRADLE" />
7+
<option name="scriptParameters" value="" />
8+
<option name="taskDescriptions">
9+
<list />
10+
</option>
11+
<option name="taskNames">
12+
<list>
13+
<option value="publishExspToMaven" />
14+
</list>
15+
</option>
16+
<option name="vmOptions" />
17+
</ExternalSystemSettings>
18+
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
19+
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
20+
<DebugAllEnabled>false</DebugAllEnabled>
21+
<method v="2" />
22+
</configuration>
23+
</component>

README.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ This is a wrapper library for `SharedPreferences` for Android, based on Lombok (
2929
id 'io.freefair.lombok' version '5.3.0'
3030
id 'kotlin-kapt'
3131
}
32-
32+
3333
kapt {
3434
keepJavacAnnotationProcessors = true
3535
}
36-
36+
3737
dependencies {
3838
implementation "io.github.sgpublic:exsp-runtime:$latest"
3939
kapt "io.github.sgpublic:exsp-compiler:$latest"
40-
40+
4141
def lombok_ver = "1.18.24"
4242
compileOnly "org.projectlombok:lombok:$lombok_ver"
4343
annotationProcessor "org.projectlombok:lombok:$lombok_ver"
@@ -63,18 +63,25 @@ This is a wrapper library for `SharedPreferences` for Android, based on Lombok (
6363
public class TestPreference {
6464
@ExValue(defVal = "test")
6565
private String testString;
66-
66+
6767
@ExValue(defVal = "0")
6868
private float testFloat;
69-
69+
7070
@ExValue(defVal = "0")
7171
private int testInt;
72-
72+
7373
@ExValue(defVal = "0")
7474
private long testLong;
75-
75+
7676
@ExValue(defVal = "false")
7777
private boolean testBool;
78+
79+
@ExValue(defVal = "TYPE_A")
80+
private Type testEnum;
81+
82+
public enum Type {
83+
TYPE_A, TYPE_B;
84+
}
7885
}
7986
```
8087

@@ -84,7 +91,7 @@ This is a wrapper library for `SharedPreferences` for Android, based on Lombok (
8491
class App: Application() {
8592
override fun onCreate() {
8693
super.onCreate()
87-
94+
8895
ExPreference.init(this)
8996
}
9097
}
@@ -108,13 +115,23 @@ This is a wrapper library for `SharedPreferences` for Android, based on Lombok (
108115
Log.d("TestPreference#testString", test.getTestString());
109116
```
110117

118+
7. If you set `isMinifyEnabled = true` in your project, you should add to `proguard-rules.pro`:
119+
120+
```
121+
-keepclassmembers class io.github.sgpublic.exsp.ExPrefs { public static *** get(***); }
122+
```
123+
124+
125+
111126
## Custom Type
112127
113128
`ExSharedPreference` allows you to save custom types into SharedPreferences, but since SharedPreferences only supports a limited number of types, we use the conversion mechanism to complete this function.
114129
130+
**PS: We've added special support for enum types, so you needn't to add converters for enum types.**
131+
115132
1. Add the required custom types to the class directly.
116133
117-
**PS: The `defVal` needs to fill in the string of the original type value, not your custom type!**
134+
**Note: The `defVal` needs to fill in the string of the original type value, not your custom type!**
118135
119136
```java
120137
@Data
@@ -211,4 +228,3 @@ sharedPreference.editor()
211228
### @ExConverter
212229

213230
This annotation is used to mark a custom type converter for `ExSharedPreference` processing.
214-

build.gradle.kts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
plugins {
2-
id("com.android.library") version "7.3.0" apply false
3-
id("org.jetbrains.kotlin.android") version "1.7.10" apply false
4-
id("com.android.application") version "7.3.0" apply false
2+
val androidVer = "7.3.1"
3+
id("com.android.library") version androidVer apply false
4+
id("com.android.application") version androidVer apply false
5+
6+
val ktVer = "1.7.21"
7+
id("org.jetbrains.kotlin.android") version ktVer apply false
58
}

compiler/src/main/kotlin/io/github/sgpublic/exsp/core/ConverterCompiler.kt

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ object ConverterCompiler {
2020
.addModifiers(Modifier.PUBLIC)
2121

2222
val any = TypeVariableName.get("?")
23-
val Origin = TypeVariableName.get("Origin")
24-
val Target = TypeVariableName.get("Target")
23+
val OriginT = TypeVariableName.get("OriginT")
24+
val TargetT = TypeVariableName.get("TargetT")
2525
val anyClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), any)
2626
val anyConverter = ParameterizedTypeName.get(ClassName.get(Converter::class.java), any, any)
2727
val extendsConverterClass = ParameterizedTypeName.get(ClassName.get(Class::class.java),
2828
WildcardTypeName.subtypeOf(ParameterizedTypeName.get(ClassName.get(Converter::class.java), any, any)))
29-
val originClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), Origin)
30-
val knownConverter = ParameterizedTypeName.get(ClassName.get(Converter::class.java), Origin, Target)
29+
val originClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), OriginT)
30+
val knownConverter = ParameterizedTypeName.get(ClassName.get(Converter::class.java), OriginT, TargetT)
3131

3232
FieldSpec.builder(
3333
ParameterizedTypeName.get(ClassName.get(Map::class.java), anyClass, anyConverter),
@@ -43,54 +43,55 @@ object ConverterCompiler {
4343
impl.addField(it.build())
4444
}
4545

46+
val originClazzParam = ParameterSpec.builder(originClass, "clazz").build()
4647
MethodSpec.methodBuilder("getConverter")
4748
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
48-
.addTypeVariables(listOf(Origin, Target))
49-
.addParameter(ParameterSpec.builder(originClass, "clazz").build())
50-
.beginControlFlow("if (!\$T.registry.containsKey(clazz))", ExPreferenceProcessor.ExConverters)
51-
.addStatement("throw new \$T(\"Cannot find converter for \" + clazz + \", " +
52-
"have you created its converter and added @ExConverter?\")", IllegalStateException::class.java)
49+
.addTypeVariables(listOf(OriginT, TargetT))
50+
.addParameter(originClazzParam)
51+
.beginControlFlow("if (!\$T.registry.containsKey(\$N))", ExPreferenceProcessor.ExConverters, originClazzParam)
52+
.addStatement("throw new \$T(\"Cannot find converter for \" + \$N + \", " +
53+
"have you created its converter and added @ExConverter?\")", IllegalStateException::class.java, originClazzParam)
5354
.endControlFlow()
54-
.beginControlFlow("if (!\$T.converters.containsKey(clazz))", ExPreferenceProcessor.ExConverters)
55+
.beginControlFlow("if (!\$T.converters.containsKey(\$N))", ExPreferenceProcessor.ExConverters, originClazzParam)
5556
.beginControlFlow("try")
56-
.addStatement("\$T.converters.put(clazz, \$T.registry.get(clazz).newInstance())",
57-
ExPreferenceProcessor.ExConverters, ExPreferenceProcessor.ExConverters)
57+
.addStatement("\$T.converters.put(clazz, \$T.registry.get(\$N).newInstance())",
58+
ExPreferenceProcessor.ExConverters, ExPreferenceProcessor.ExConverters, originClazzParam)
5859
.nextControlFlow("catch (IllegalAccessException | InstantiationException e)")
59-
.addStatement("throw new \$T(\"Failed to create instance for \" + \$T.registry.get(clazz) + \"!\")",
60-
RuntimeException::class.java, ExPreferenceProcessor.ExConverters)
60+
.addStatement("throw new \$T(\"Failed to create instance for \" + \$T.registry.get(\$N) + \"!\")",
61+
RuntimeException::class.java, ExPreferenceProcessor.ExConverters, originClazzParam)
6162
.endControlFlow()
6263
.endControlFlow()
63-
.addStatement("return (\$T<\$T, \$T>) \$T.converters.get(clazz)",
64-
Converter::class.java, Origin, Target, ExPreferenceProcessor.ExConverters)
64+
.addStatement("return (\$T<\$T, \$T>) \$T.converters.get(\$N)",
65+
Converter::class.java, OriginT, TargetT, ExPreferenceProcessor.ExConverters, originClazzParam)
6566
.returns(knownConverter)
6667
.let {
6768
impl.addMethod(it.build())
6869
}
6970

7071
MethodSpec.methodBuilder("toPreference")
7172
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
72-
.addTypeVariables(listOf(Origin, Target))
73-
.addParameter(ParameterSpec.builder(originClass, "clazz").build())
74-
.addParameter(ParameterSpec.builder(Origin, "value").build())
75-
.returns(Target)
76-
.addStatement("\$T<\$T, \$T> converter = \$T.getConverter(clazz)",
77-
Converter::class.java, Origin, Target, ExPreferenceProcessor.ExConverters)
73+
.addTypeVariables(listOf(OriginT, TargetT))
74+
.addParameter(originClazzParam)
75+
.addParameter(ParameterSpec.builder(OriginT, "value").build())
76+
.returns(TargetT)
77+
.addStatement("\$T<\$T, \$T> converter = \$T.getConverter(\$N)",
78+
Converter::class.java, OriginT, TargetT, ExPreferenceProcessor.ExConverters, originClazzParam)
7879
.addStatement("return converter.toPreference(value)",
79-
Converter::class.java, Origin, Target, ExPreferenceProcessor.ExConverters)
80+
Converter::class.java, OriginT, TargetT, ExPreferenceProcessor.ExConverters)
8081
.let {
8182
impl.addMethod(it.build())
8283
}
8384

8485
MethodSpec.methodBuilder("fromPreference")
8586
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
86-
.addTypeVariables(listOf(Origin, Target))
87-
.addParameter(ParameterSpec.builder(originClass, "clazz").build())
88-
.addParameter(ParameterSpec.builder(Target, "value").build())
89-
.returns(Origin)
90-
.addStatement("\$T<\$T, \$T> converter = \$T.getConverter(clazz)",
91-
Converter::class.java, Origin, Target, ExPreferenceProcessor.ExConverters)
87+
.addTypeVariables(listOf(OriginT, TargetT))
88+
.addParameter(originClazzParam)
89+
.addParameter(ParameterSpec.builder(TargetT, "value").build())
90+
.returns(OriginT)
91+
.addStatement("\$T<\$T, \$T> converter = \$T.getConverter(\$N)",
92+
Converter::class.java, OriginT, TargetT, ExPreferenceProcessor.ExConverters, originClazzParam)
9293
.addStatement("return converter.fromPreference(value)",
93-
Converter::class.java, Origin, Target, ExPreferenceProcessor.ExConverters)
94+
Converter::class.java, OriginT, TargetT, ExPreferenceProcessor.ExConverters)
9495
.let {
9596
impl.addMethod(it.build())
9697
}

compiler/src/main/kotlin/io/github/sgpublic/exsp/core/PreferenceCompiler.kt

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,61 @@ import javax.lang.model.element.Element
1111
import javax.lang.model.element.Modifier
1212
import javax.lang.model.element.TypeElement
1313
import javax.lang.model.element.VariableElement
14-
import javax.tools.Diagnostic
1514

1615
object PreferenceCompiler {
1716
fun apply(env: RoundEnvironment) {
17+
val any = TypeVariableName.get("?")
18+
val anyClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), any)
19+
val anyLazy = ParameterizedTypeName.get(ClassName.get(Lazy::class.java), any)
20+
21+
val prefsName = ClassName.get("io.github.sgpublic.exsp", "ExPrefs")
22+
val prefsClazz = TypeSpec.classBuilder(prefsName)
23+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
24+
25+
val prefs = FieldSpec.builder(
26+
ParameterizedTypeName.get(ClassName.get(Map::class.java), anyClass, anyLazy),
27+
"prefs", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL
28+
).initializer("new \$T<>()", HashMap::class.java).build()
29+
prefsClazz.addField(prefs)
30+
31+
val PrefT = TypeVariableName.get("PrefT")
32+
val prefClass = ParameterizedTypeName.get(ClassName.get(Class::class.java), PrefT)
33+
val lazyPref = ParameterizedTypeName.get(ClassName.get(Lazy::class.java), PrefT)
34+
val clazz = ParameterSpec.builder(prefClass, "clazz").build()
35+
MethodSpec.methodBuilder("get")
36+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
37+
.addTypeVariable(PrefT)
38+
.addParameter(clazz)
39+
.beginControlFlow("if (\$T.\$N.containsKey(\$N))", prefsName, prefs, clazz)
40+
.addStatement("return (\$T) \$T.\$N.get(\$N)", lazyPref, prefsName, prefs, clazz)
41+
.endControlFlow()
42+
.addStatement("throw new \$T(\"Unknown ExPreference type, did you add @ExPreference?\")", IllegalStateException::class.java)
43+
.returns(lazyPref)
44+
.let {
45+
prefsClazz.addMethod(it.build())
46+
}
47+
48+
val static = CodeBlock.builder()
49+
1850
for (element: Element in env.getElementsAnnotatedWith(ExSharedPreference::class.java)) {
1951
if (element !is TypeElement) {
2052
continue
2153
}
22-
applySingle(element)
54+
static.addStatement("\$T.\$N.put(\$L)", prefsName, prefs, applySingle(element))
2355
}
56+
57+
prefsClazz.addStaticBlock(static.build())
58+
59+
JavaFile.builder("io.github.sgpublic.exsp", prefsClazz.build())
60+
.build().writeTo(ExPreferenceProcessor.mFiler)
2461
}
2562

26-
private fun applySingle(element: TypeElement) {
63+
private fun applySingle(element: TypeElement): CodeBlock {
2764
val anno = element.getAnnotation(ExSharedPreference::class.java)
2865

2966
val originType = ClassName.get(element)
3067
val origin = element.simpleName.toString()
31-
val spName = "\"" + anno.name + "\""
68+
val spName = "\"${anno.name.takeIf { it.isNotBlank() } ?: element.qualifiedName}\""
3269

3370
val pkg = element.qualifiedName.let {
3471
val tmp = it.substring(0, it.length - origin.length)
@@ -39,9 +76,11 @@ object PreferenceCompiler {
3976
}
4077
}
4178

42-
val impl = TypeSpec.classBuilder(origin + "_Impl")
79+
val implName = "${origin}_Impl"
80+
val impl = TypeSpec.classBuilder(implName)
4381
.superclass(originType)
4482
.addModifiers(Modifier.PUBLIC)
83+
val implType = ClassName.get(pkg, implName)
4584

4685
MethodSpec.methodBuilder("getSharedPreference")
4786
.addModifiers(Modifier.PRIVATE)
@@ -72,11 +111,6 @@ object PreferenceCompiler {
72111
impl.addMethod(it.build())
73112
}
74113

75-
val save = MethodSpec.methodBuilder("save")
76-
.addModifiers(Modifier.PUBLIC)
77-
.addParameter(originType, "data")
78-
.returns(TypeName.VOID)
79-
80114
for (field: Element in element.enclosedElements) {
81115
val defVal = field.getAnnotation(ExValue::class.java)?.defVal
82116
if (field !is VariableElement) {
@@ -107,7 +141,6 @@ object PreferenceCompiler {
107141

108142

109143
var convertedType = type
110-
ExPreferenceProcessor.mMessager.printMessage(Diagnostic.Kind.WARNING, "field: ${field.asType()}")
111144
if (type.supported()) {
112145
setter.addStatement("\$T converted = value", type)
113146
getter.addStatement("\$T origin", type)
@@ -170,15 +203,26 @@ object PreferenceCompiler {
170203
}
171204
setter.addStatement("editor.apply()")
172205

173-
save.addStatement("${field.setterName()}(data.${field.getterName()}())")
174-
175206
impl.addMethod(getter.build())
176207
impl.addMethod(setter.build())
177208
}
178209

179-
impl.addMethod(save.build())
180-
181210
JavaFile.builder(pkg, impl.build())
182211
.build().writeTo(ExPreferenceProcessor.mFiler)
212+
213+
val invoke = MethodSpec.methodBuilder("invoke")
214+
.addAnnotation(Override::class.java)
215+
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
216+
.addStatement("return new \$T()", implType)
217+
.returns(originType)
218+
.build()
219+
val originFunction0 = ParameterizedTypeName.get(ClassName.get(Function0::class.java), originType)
220+
return CodeBlock.of("\$T.class, \$T.lazy(\$L)",
221+
originType, ClassName.get("kotlin", "LazyKt"),
222+
TypeSpec.anonymousClassBuilder("")
223+
.addSuperinterface(originFunction0)
224+
.addMethod(invoke)
225+
.build()
226+
)
183227
}
184228
}

compiler/src/main/kotlin/io/github/sgpublic/exsp/util/_Types.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ private val enu = ExPreferenceProcessor.getElement("java.lang.Enum")
8282
fun VariableElement.isEnum(): Boolean {
8383
var asElement = ExPreferenceProcessor.asElement(asType()) ?: return false
8484
while (asElement.superclass != null) {
85-
ExPreferenceProcessor.mMessager.printMessage(Diagnostic.Kind.WARNING, "asElement: $asElement")
8685
if (asElement == enu) {
8786
return true
8887
}

demo/build.gradle.kts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ android {
2222
}
2323

2424
buildTypes {
25-
release {
26-
isMinifyEnabled = false
25+
all {
26+
isMinifyEnabled = true
27+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
2728
}
2829
}
2930
compileOptions {
@@ -42,11 +43,11 @@ kapt {
4243
dependencies {
4344
implementation("androidx.core:core-ktx:1.9.0")
4445
implementation("androidx.appcompat:appcompat:1.5.1")
45-
implementation("com.google.android.material:material:1.6.1")
46+
implementation("com.google.android.material:material:1.7.0")
4647
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
4748
testImplementation("junit:junit:4.13.2")
48-
androidTestImplementation("androidx.test.ext:junit:1.1.3")
49-
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
49+
androidTestImplementation("androidx.test.ext:junit:1.1.4")
50+
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
5051

5152
implementation(project(":runtime"))
5253
kapt(project(":compiler"))

0 commit comments

Comments
 (0)