What is the criteria Realm uses in android to tell two different files are the same RealmObject?
Is it just the class name or the whole package name?
More specifically.
Say that I have com.company.MyRealmObject.kt and I refactor it to com.company2.MyRealmObject.kt.
Say that I have com.company.MyRealmObject.kt in Gradle module :app and I move it to Say that I have com.company.MyRealmObject.ktin Gradle module:library_db`
Would those action make Realm consider that MyRealmObject before and after the change are different RealmObjects hence requiring a migration, or would they be considered the same RealmObjects regardless of package and file as they have the same simple class name?
Thank you.
From my experiments, as long as the name of the class is the same, Realm will consider it the same RealmObject.
The name of the package of file in the project is not relevant, it's all down to the name of the class.
This seems to be in line with this comment: https://github.com/realm/realm-java/issues/6403#issuecomment-454427296
Our proxy classes encode the package path as part of the final class
name, but moving classes should be fine since the simple name is the
same, so it should translate to the same simple name in the Realm
file.
Related
I am investigating custom annotation processors for Android applications.
I have a use case where I would like to be able to use an annotation processor to read/amend the AndroidManifest.xml and add the following intent section for all Activities mentioned there in?
<intent-filter>
<action android:name="com.my.package.name.my_activity.open"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Is this possible?
It is a very interesting question but I don't think you could achieve such a task with an annotation processor since those work at Kotlin/Java code generation level.
How would you annotate XML #Something and have it still be valid XML?
Take a look at this:
KoltinConf18 - Annotation processing in Kotlin
At 7:18 Zack goes over annotation processing in Java and it basically says:
Happens at compile time
And you cannot modify code, just generate more
So by using barebones annotation processing you can't really modify the already existing AndroidManifest.xml.
An alternative would be writing a Gradle plugin that generates those bits of XML and merges it with the current XML file that already exists within the project.
Something from the top of my head could be:
Create an annotation and mark all activities that you want to introduce that bit of code
On the plugin side; when you are writing the Gradle task; you may use reflection and figure out which classes are annotated by such extension. Or just make the programmer put those activities in a specific directory inside the source folder, which would be way easier
With the fully qualified class names, you may look at the <activity> nodes in the AndroidManifest.xml, filter out the class names that don't match the list of annotated class names
Modify those nodes with the piece of code you would like to inject.
To get started on how to write a Gradle plugin take a look here
A simple example to get you started could be:
Step 1
You create a separate module to write your plugin if it gets too cumbersome but for this simple example I decided to stick it right in the build.gradle.kts. It doesn't need to be a kotlin Gradle file, but I am more proficient in Kotlin than in Groovy :)
As you can see I have created a text testFile.txt in the root of the project.
In code I just navigate to it and read it; print it's content and then modify it.
You could do the very same thing with your AndroidManifes.xml. Then you would need to recursively iterate over the source files from your srcDir looking for all of those activities annotated by your special annotation and store all of the fully qualified class names inside a List<String>. Then do the necessary replacements inside the AndroidManifest
Note that with this basic configuration the Gradle task appears in the Gradle tab inside the others category, to change that is a little bit off of the scope of annotation processing.
Step 2, profit
It works, as you can see the file has been updated and the println statements show the previous content of the file before modifying it
You could have a template AndroidManifest_template.xml then using a gradle task go through the AndroidManifest_template.xml and generate the real AndroidManifest.xml which would be used to build the app.
In other words, AndroidManest.xml would be a transient part of the build and you could use any XML preprocessor you want to take the template and turn it into the real file.
In case you want to add these intents conditionally depending on flavour of your app, you could use gradle flavours and manifest merging to achieve this - read more about flavours at https://developer.android.com/studio/build/build-variants
Also refer to following question for example of using gradle to modify manifest
https://stackoverflow.com/a/22759572/9640177
Please explain me what is the purpose and meaning of classes like StringsKt__StringsKt (i.e. doubled class name with one or more underscores in between) and, similarly, StringsKt__StringsJVMKt?
Strings are not the only example, there are many others too. I see them when looking into the structure of the classes.dex file in my .apk.
screenshot here
I'm asking because I faced a situation where I had to explicitly state some of them in my proguard-rules. The app crashed without it.
It is a generated file. A file like that will be generated if there are several Kotlin files named with same JvmName.
Let's take Strings.kt and StringNumberConversions.kt as an example:
// StringNumberConversions.kt
#file:kotlin.jvm.JvmMultifileClass
#file:kotlin.jvm.JvmName("StringsKt")
...
// Strings.kt
#file:kotlin.jvm.JvmMultifileClass
#file:kotlin.jvm.JvmName("StringsKt")
...
Both of them have #file:kotlin.jvm.JvmName("StringsKt"), so StringsKt and StringsKt__StringNumberConversionsKt are generated to distinguish them.
I have multiple activities. For organization purposes I want to to put them in folders without affecting the project. How can this be done?
Just create a new folder.
In fact, you can organize your project and separate the class as you want. This way, you keep your project organized and you can hide some methods and let them to be used only for classes in same package, for example.
I use do:
...\app\src\main\java\com\example\myapp\activities
...\app\src\main\java\com\example\myapp\service
...\app\src\main\java\com\example\myapp\dataprovider
...\app\src\main\java\com\example\myapp\adapters
So, your activities classes would start with:
package com.example.myapp.activities;
And your services would start with:
package com.example.myapp.service;
Also, you may need to adjust your imports:
import com.example.myapp.dataprovider.Class1;
import com.example.myapp.dataprovider.Class2;
However, this should be done automatically by Android Studio.
Just remember that doing that, you are creating a different packages. This way, you have to take a special attention with method accessbility (private, protected, public)
However, since we usually use private and public modifiers, we should not have any problem.
In IPC to interpret data received the process should be knowing the Class structure. So i made a Library of all required classes which are all implementing Parcelable.
In library i have defined aidl files for all calsses and ensured that these file are present in JAR.
In application, i have created same aidl file and place in the same package name as in library.
In aidl file which contains method definitions no error is shown but in code section of Stub() i get that the Library class as return could not be found.
if i create the same library object inside the method it shows valid object, but something with it as return type.
so, i moved one of the class from library to application there is problem with this class.
What have i missed so that library classes are not recognized as return type.
Note: i edited the compiler created class file for aidl in gen folder and added import to my library, error is solved but i cant save it, compiler will overwrite it.
what a shame... Package name of classes in my library had first letter as capital while i messed it by creating package structure in my application with small letter...
Wont delete the Question. someone else might also do same mistake
I know in Proguard you are recommended to keep the fields names of the R inner classes like ID. Because ProGuard doesn't handle the layout xml files. You will end up with broken links
But is there away to obfuscate classes like R$id by some other means, even if it involves doing it before passing it to ProGuard, via Ant.
I am asking this because if you have a button with an id btnSaveArticle, for a hacker it becomes too easy to grasp what the code around is doing by looking at the name.
Could it be possible to copy all the source code, including the resource files to another folder and use ant to run regex to change the names of the R.ids as well as changing where they appear in the layout xml files, and then somehow running generate to re-create the R classes?
Or you could create translation class eg TR then map it to the fields in the R.class
eg.
TR.btnSaveArticle = R.id.DHTXM;
Where DHTXM is some meaning less word that can be used in the layout XML. But in the code you always refer to TR.btnSaveArticle, which will be obfuscated by proguard.
Are there ways to achieve this or am I wasting my time?
Just use below ,add it to you Proguard config file
-keepclassmembers class **.R$* {
public static <fields>;}
I am asking this because if you have a button with an id btnSaveArticle, for a hacker it becomes too easy to grasp what the code around is doing by looking at the name.
Using Hierarchy View, it would take them less than 30 seconds to determine the actual ID of the "Save Article" button, no matter what you name it. And I can envision even faster solutions with a bit of custom tooling.
am I wasting my time?
IMHO, yes.
With the default configuration for Android, ProGuard removes R classes entirely, unless your code performs introspection on them. In the latter case, ProGuard also preserves the fields with their original names, in order not to break the introspection.
That being said, the resource names can also be retrieved from the resource XML files, which ProGuard leaves untouched.
It is possible through Ant, as it allows you to set a different gen and res folder.
So what you do is copy from the originals to those folders and then you edit the files using regex to update to the new names.
You will need a translation class (eg D) like this to map it to the fields in the R.class, so in your code you can work with non obfuscated names.
public final class D{
public static final class id{
D.btnSaveArticle = R.id.btnSaveArticle //DHTXM;
Then you also need to create a different src folder and copy from the original folder. There you run a task to edit the D class so it becomes
D.btnSaveArticle = R.id.DHTXM;
I had to create a java program which is run through ant to swap the names to obfuscated names.
If you do something similar for strings, and styles your XML in the apk would end up looking like this:
<TextView
android:id="#+id/GnvCMa"
android:text="#string/OVuCbd"
style="#style/ZOVkuu.MGTRgZ" />
It is a little time consuming to setup, but once implemented it can be used for other projects.