Android uses the "default" method in the interface to generate apk - android

Now there is a third-party dependency package: page
It has an interface that contains the default method :
public interface TempInterface {
default String getStr() {
return "test";
}
}
And i create a module : app
There is a class in "app" that uses the above interface
public class AA implements TempInterface {
}
"build.gradle" file in "app" :
dependencies {
compileOnly project(':page')
}
In the generated APK, the following classes appear:
what about *$-CC ?????
And when I decompiled the DEX file, I found that there was no such class at all:
So I'm confused about what this "* $- CC" is ??
Who can help me
the build.gradle :

$-CC file is generated by d8 when the class file compile to dex file.
More details on https://mouaad.aallam.com/java-8-interface-methods-for-android/

why you apply proguard from your app/build.gradle, it obfuscates your class and methods name so that reverse engineering is tough. that is what happens here

Related

Serializer for data class Kotlin not found at build release

I want convert my json string response from API to object:
val obj = Json.decodeFromString<MyModel>(jsonResponseString)
My data class:
#Serializable
data class MyModel(
#SerializedName("field") val field: String
)
It look like very simple and it works on debug mode!
But when a compiled the AppBundle, builded in release mode and download app from Play Store internal testing, I got the following error :
Serializer for class '...' is not found. Mark the class as #serializable or provide the
serializer explicitly.
kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered
You should add this to your proguard.pro if you're using minifyEnabled true
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
-keepclassmembers class kotlinx.serialization.json.** {
*** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
kotlinx.serialization.KSerializer serializer(...);
}
# Change here com.yourcompany.yourpackage
-keep,includedescriptorclasses class com.yourcompany.yourpackage.**$$serializer { *; } # <-- change package name to your app's
-keepclassmembers class com.yourcompany.yourpackage.** { # <-- change package name to your app's
*** Companion;
}
-keepclasseswithmembers class com.yourcompany.yourpackage.** { # <-- change package name to your app's
kotlinx.serialization.KSerializer serializer(...);
}
Make sure you replace the placeholder package name with your app package name
Source
I found the next solution:
First step, I added #Keep anotation. Keep anotation denotes that the annotated element should not be removed when the code is minified at build time:
#Keep
#Serializable
data class MyModel(
#SerializedName("field") val field: String
)
Second step, I converted my json to object making a static reference to the serializer:
val objError = Json {ignoreUnknownKeys = true}.decodeFromString(MyModel.serializer(), jsonResponseString)
Dont forget import and implement last version of:
'org.jetbrains.kotlin.plugin.serialization'
And it worked and it save my day!!
I have fixed that with these changes in the Gradle files, in the build project gradle add this line to dependencies:
classpath "org.jetbrains.kotlin:kotlin-serialization:1.5.21"
Add also these to the build app gradle:
plugins {
...
id 'kotlinx-serialization'
}
dependencies {
...
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2'
}
Please note version numbers might be different.
Starting from 1.5.0-RC proguard rules are shipped with library.
Bundled Proguard rules
The kotlinx-serialization-core-jvm JAR file now includes consumer Proguard >rules,
so manual Proguard configuration is no longer necessary for most of the setups.

Android aar file Inside a Library module - NoClassDefFoundError

I am having an external library (constants.aar) file. I have kept this .aar file in to my Android library module project's (sdk-module)/lib folder. This sdk-module has classes which uses methods from constants.aar.
Compiling the sdk-module generates sdk-module.aar file.
In my application i am including this sdk-module.aar file. When i am trying to use certain class files of sdk-module, i am getting NoClassDefFoundError.
java.lang.NoClassDefFoundError: Failed resolution of: "class file from constant.aar";
Caused by: java.lang.ClassNotFoundException: Didn't find class "xyz" on path:
I have unzipped the sdk-module.aar file and i can see that constants.aar file is available in its /lib folder.
How to resolve this issue?
android {
defaultConfig {
....
multiDexEnabled true // Add this line in your build.gradle file
}
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
Extend : MultiDexApplication Class In in your ApplicationClass.java
public class BusinessCardApplication extends MultiDexApplication { ... }
OR
MultiDex.install(this); //add this line
Either, See this library's Issues File. If It Is from library's issue there is also define this error detail

AAR Android Library - disable compression on assets

I have to distribute some files under assets in my AAR that should not be compressed.
So for example, in an Android app you would do the following in build.gradle:
android {
...
aaptOptions {
noCompress 'dll'
}
}
Is there a way to apply this from an AAR file? I would rather not have to include instructions for developers consuming my AAR to modify their build.gradle file.
I don't think there is a way to set gradle build settings from inside an AAR.
However, I am making a gradle plugin anyway, so I plan to ship a gradle plugin along with the AAR.
So in my plugin I'm doing this:
class AaptOptionsTask extends DefaultTask {
#TaskAction
def run() {
project.configure(project) {
project.android.aaptOptions.setProperty('noCompress', 'dll')
}
}
AaptOptionsTask() {
group = 'myGroup'
description = 'aaptOptions settings'
}
}
Which is setup as a task like this:
class MyGradlePlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.task('aaptOptionsTask', type: AaptOptionsTask)
project.tasks.getByName('preBuild').dependsOn('aaptOptionsTask')
}
}
If there is another way, I'm all ears.

Dagger 2 inject error in AppCompatActivity

I'm newbie for Dagger.
Current I create sample project some snip code:
MyComponent.java
#PerActivity
#Component(modules = MyModule.class)
public interface MyComponent {
void inject(TutorialActivity activity);
}
MyModule.java
#Module
public class MyModule {
#Provides
Position providePosition() {
return new Position();
}
}
PerActivity.java
#Scope
#Retention(RUNTIME)
public #interface PerActivity {}
TutorialActivity.java
public class TutorialActivity extends AppCompatActivity{}
When compile project I get error:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.IllegalArgumentException: expected one element but was: <android.support.v4.app.FragmentActivity, android.support.v4.app.TaskStackBuilder.SupportParentable>
So if I change TutorialActivity as:
public class TutorialActivity extends Activity{}
or even
public class TutorialActivity{} // Without extends
Then it will working normally.(I can see class generated by Dagger2).
Please help !
Thanks.
UPDATE
My project structure:
common module.
app module. (app module will use common module as depended in gradle).
In both build.gradle (common and app module) I added:
apt "com.google.dagger:dagger-compiler:${daggerVersion}"
compile "com.google.dagger:dagger:${daggerVersion}"
In build.gradle at common module:
provide "org.glassfish:javax.annotation:${javaxAnnotationVersion}"
An error only occurs if I have 2 module. (module app depended on common).
If I move my Component/Module to module common -> It work.
But when I move that to app module -> Error when compile.
I'm not sure that your issue is a problem with Dagger because I don't see you requesting any dependencies in your Android components.
Nonetheless you need this in your build.gradle to use the depdendency injection annotations.
provided 'javax.annotation:jsr250-api:1.0'
Thanks #plash for your answer.
After I re-check for both module.
I found I only added:
provide "org.glassfish:javax.annotation:${javaxAnnotationVersion}"
in common module.
After I added that provide for both module then compile success.(Dagger generated class.)

Gradle - add dependency to tests of another module

I have a multi-module gradle project that looks like this:
Parent
|--server
|--application (android module)
+--common
The server tests have a dependency on the common module tests. For this, I added
testCompile files(project(':common').sourceSets.test.output.classesDi
compileTestJava.dependsOn tasks.getByPath(':common:testClasses')
and it worked great. Unfortunately, when I tried to do the same thing for the application module that also has a dependency on the common module tests, it wouldn't work. It fails with:
Build file 'application\build.gradle' line: 103
A problem occurred evaluating project ':application'.
Could not find property 'sourceSets' on project ':common'
After googling a bit I also tried
project.evaluationDependsOn(':common')
testCompile files(project(':common').sourceSets.test.output.classesDir)
But fails with another exception:
Project application: Only Jar-type local dependencies are supported. Cannot handle: common\build\classes\test
Any ideas on how to fix this?
There's a couple of approaches solving the problem of importing test classes in this article. https://softnoise.wordpress.com/2014/09/07/gradle-sub-project-test-dependencies-in-multi-project-builds/ The one I used is:
code in shared module:
task jarTest (type: Jar) {
from sourceSets.test.output
classifier = 'test'
}
configurations {
testOutput
}
artifacts {
testOutput jarTest
}
code in module depending on the shared module:
dependencies{
testCompile project(path: ':common', configuration: 'testOutput')
}
And there seems to be a plugin for it as well! https://plugins.gradle.org/plugin/com.github.hauner.jarTest/1.0
Following the approach from sakis, this should be the configuration you need to get the tests available from another project in the Android platform (done for debug variant).
Shared module:
task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
classifier = 'tests'
from "$buildDir/intermediates/classes/test/debug"
}
configurations {
unitTestArtifact
}
artifacts {
unitTestArtifact jarTests
}
Your module:
dependencies {
testCompile project(path: ":libName", configuration: "unitTestArtifact")
}
The solution mentioned by droidpl for Android + Kotlin looks like this:
task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
getArchiveClassifier().set('tests')
from "$buildDir/tmp/kotlin-classes/debugUnitTest"
}
configurations {
unitTestArtifact
}
artifacts {
unitTestArtifact jarTests
}
Gradle for project that is going to use dependencies:
testImplementation project(path: ':shared', configuration: 'unitTestArtifact')
I know it's kinda an old question but the solution mentioned in the following blog solves the problem very nicely and is not a sort of hack or a temporary workaround:
Shared test sources in Gradle multi-module project
It works something like this:
// in your module's build.gradle file that needs tests from another module
dependencies {
testCompile project(path: ':path.to.project', configuration: 'test')
}
Also you should note that in the very last paragraph he mentioned that you need to enable Create separate module per source set in IntelliJ settings. But it works fine without using that option too. Probably due to changes in the recent IntelliJ versions.
EDIT: IntelliJ recognizes this fine as of 2020.x versions.
I think you could use gradles java test fixtures. This will automatically create a testFixtures source set, in which you can write your test that you want to reuse.
Test fixtures are configured so that:
they can see the main source set classes
test sources can see the test fixtures classes
For example, if you have some class in common module:
public class CommonDto {
private final Long id;
private final String name;
// getters/setters and other methods ...
}
Then in the common module, you could write into src/testFixtures/java following utils:
public class Utils {
private static final CommonDto A = new CommonDto(1, "A");
private static final CommonDto B = new CommonDto(2, "B");
public static CommonDto a() { return A; }
public static CommonDto b() { return B; }
}
Then in you other modules you could add this to reuse Utils class
dependencies {
// other dependencies ...
testImplementation(testFixtures(project(":common")))
}
All of this is better explained in the documentation that I provided initially. There are some nuances that you need to take into account until you create this not to leak test classes into production.

Categories

Resources