[Android Software Development] Lanchon:
hmmm... strange, AS3 C8 didn't work for me.

anyway, yes you can add static fields, there is a sample in the docs:

https://github.com/DexPatcher/dexpa...st/patch/src/main/java/test/Main.java#L68-L79

on each class there potentially is a static method called "static constructor" or "class constructor" or "<clinit>" that is executed as the class loads. if an exception is thrown from this method (i think) the class loading fails with an java Error.

static { /*...*/ } blocks in a class are all linked together into the static constructor, and other stuff too.

when you include a static field in a class such as:

static int staticField = 100;

the compiler can choose to do either of 2 things:

- if the type is a simple value type, then the compiler can choose to embed its initial value in the field itself.

- or it can choose to generate code to initialize the field and include the code in a generated static constructor for the class.

(NOTE: recent JDK compilers choose to do the 2nd thing, most if not all of the time, in effect deprecating the use of the initial value of static fileds in java bytecode.)

so when you add a static field, a static constructor can be generated and it MUST be dealt with. should we ignore it? extremely dangerous! some "new" java features like MyClass.class also generate code that goes into the static constructor and ignoring the <clinit> can **BREAK** the code output by the compiler. (for example, MyClass.class could evaluate to null !!!)

but what to do? what if the compiler chooses to NOT generate <clinit>? dexpatcher would fail if you target <clinit> and there is no such method!

so first do this to make sure there always is a <clinit>, independent of which compiler you are using:

https://github.com/DexPatcher/dexpa...st/patch/src/main/java/test/Main.java#L81-L84

now we have to instruct DXP to add <clinit> but... <clinit> can't be annotated!

that's why an "annotation equivalent" can be defined with staticConstructorAction:

https://github.com/DexPatcher/dexpa...st/patch/src/main/java/test/Main.java#L65-L66

btw, this is what happens when <clinit> is ignored;

https://github.com/DexPatcher/dexpa.../patch/src/main/java/test/Main.java#L167-L190

DXP complains that the statics will loose their init values:

https://github.com/DexPatcher/dexpatcher-tool/blob/v1.2.1/test/shell-test-ref.txt#L64-L65

and see here how all initial values are lost at runtime:

https://github.com/DexPatcher/dexpatcher-tool/blob/v1.2.1/test/shell-test-ref.txt#L201-L208

(NOTE: DXP ignores the simple initial values in the fields themselves if <clinit> is ignored, so that no mater what type of compiler you use you get consistent behavior.)

in short, you should never ever ignore <clinit>s: it's very dangerous, potentially breaking compiler code elsewhere.

but...

what happens if the source class already has a <clinit>? you can't just DexReplace it, that would effectively ignore the original constructor and be very dangerous as well. this is what happens when you replace a <clinit>:

https://github.com/DexPatcher/dexpa.../patch/src/main/java/test/Main.java#L211-L237

(this time look for the runtime output yourself, but you guessed it: whatever initial values were defined in the original code are all lost.)

so what to do if both the source and the patch contain <clinit>s for the same class? the only safe way to deal with this is combining them like this:

https://github.com/DexPatcher/dexpa.../patch/src/main/java/test/Main.java#L263-L294

the original <clinit> is renamed to a regular private static method, then a new <clinit> is added which calls the old one.

DexPatcher does its best to hide the complexity of patching, but some complexity cannot be hidden (eg: the inextricable link between static fields and <clinit> code) and you actually need to be aware of it. DXP might feel a bit daunting at times -binary patching is intrinsically hard- but then, i'm here to help! :)