Tool R Class Generator [Library Development Tool]

What is it?
This is a tool to automatically generate a B4A-type R class (in java) when developing libraries.

This is NOT required for any B4A use code.
This is NOT a requirement for library generation.

This is only required for a particular methodology of library wrapping. It allows you to access resource files from within the library without packaging it yet.

How was it built?
This is a python script turned to an .exe in pyinstaller.

How to run it?
Run this in the folder with the base class of the source you are trying to wrap. It doesnt really matter where you run it from, it will recursively go through every subfolder and analyze any .java files found in those folders.

What does it generate?
It will generate the R.java file in the same folder as itself.
The R class will have the following format (you will need to add the imports).

B4X:
public class R {
        public static final class color {
                public static int material_drawer_selected_text = BA.applicationContext.getResources().getIdentifier("material_drawer_selected_text", "color", BA.packageName);
                public static int material_drawer_secondary_text = BA.applicationContext.getResources().getIdentifier("material_drawer_secondary_text", "color", BA.packageName);
        }
        public static final class dimen {
                public static int material_drawer_margin = BA.applicationContext.getResources().getIdentifier("material_drawer_margin", "dimen", BA.packageName);
                public static int material_drawer_margin = BA.applicationContext.getResources().getIdentifier("material_drawer_margin", "dimen", BA.packageName);
        }
        public static final class string {
                public static int drawer_close = BA.applicationContext.getResources().getIdentifier("drawer_close", "string", BA.packageName);
        }
        public static final class id {
                public static int icon = BA.applicationContext.getResources().getIdentifier("icon", "id", BA.packageName);
                public static int name = BA.applicationContext.getResources().getIdentifier("name", "id", BA.packageName);
        }
}

Usage?
By embedding the R.java file in your library you will be able to access resources added using #AdditionalRes.

Bugs?
It generates a lot of duplicate identifiers.
Havent really tested it in a real library.

Download?
RGenerator2:
https://www.dropbox.com/s/sri0h96u0zyjp30/RGenerator2.exe?dl=0
RGenerator Version 1:
https://www.dropbox.com/s/9vhdilztbjxxe5x/RGenerator.zip?dl=0

Credits?
@warwound for identifying this method of accessing resources.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Usage?
By embedding the R.java file in your library you will be able to access resources added using #AdditionalRes.
Sounds interesting! Will try that in a future wrapping project :)

Thank you for sharing!
 

thedesolatesoul

Expert
Licensed User
Longtime User
Sounds interesting! Will try that in a future wrapping project :)

Thank you for sharing!
I used to try to get the library working without the extra resources (usually loaded on init or a constructor).
Later I realized its easier to generate an R class and just load the AdditionalRes.
 

thedesolatesoul

Expert
Licensed User
Longtime User
Honestly i dont know whether it works lol

But all what i have expected were available in the class :)
I used it yesterday, and it did miss a couple of identifiers. Also it added duplicates (I can fix this).
So its buggy but a lot better than starting from scratch.
 

corwin42

Expert
Licensed User
Longtime User
Hmm, since we have the #AdditionalRes keyword it isn't required to use such helper functions to get the resources like in the generated R.java class.

If a library needs resources just create it in Eclipse as an Android Project. Then copy all resources to the res folder of this project. The R.java file will be generated automagically in the Eclipse project so it compiles and you can create the jar. Later in the B4A project you can add the resources with the #AdditionalRes keyword.

See the AppCompat library. It is created this way.

Erel explained how to wrap a library with resources here. Additionally to Erels method you can even join the wrapper library project and the project for the wrapped library together into one project.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
in the Eclipse project
Then i´m doing somwhat wrong ALL THE TIME... Eclipse does not create a res-folder for me.
BUT i dont use Eclipse to compile... I always use SLC for the compiling (i have included the SLC in Eclipse to compile directly from eclipse (with the SLC sure)

When i try to wrap a library i always have the issue that in eclipse the r-file is missing and i need to rwrite all sources who depends on values from R class. For me this tool make sense...

But probably i´m doing something wrong in Eclipse too ;)
 

thedesolatesoul

Expert
Licensed User
Longtime User
Hmm, since we have the #AdditionalRes keyword it isn't required to use such helper functions to get the resources like in the generated R.java class.

If a library needs resources just create it in Eclipse as an Android Project. Then copy all resources to the res folder of this project. The R.java file will be generated automagically in the Eclipse project so it compiles and you can create the jar. Later in the B4A project you can add the resources with the #AdditionalRes keyword.

See the AppCompat library. It is created this way.

Erel explained how to wrap a library with resources here. Additionally to Erels method you can even join the wrapper library project and the project for the wrapped library together into one project.
Thank you @corwin42 . I wasnt aware of that (or that tutorial).
If I understand you correctly, I can just import it as an Android project. It will build a jar file, which I will take and reference in my library project.

I guess then my tools isnt really needed but to be honest it gives you a pretty fast shortcut, as once you generate the R.java, its a drag/drop into eclipse (with all the source .java).
 

thedesolatesoul

Expert
Licensed User
Longtime User
Then i´m doing somwhat wrong ALL THE TIME... Eclipse does not create a res-folder for me.
But probably i´m doing something wrong in Eclipse too ;)
It is because we use a 'Java project' for the wrapper, but its the 'Android project' that will have the res files etc. It requires ADT to be working correctly in eclipse.
I might give it a shot sometime but considering i've already put in effort for this tool and it seems faster in my workflow I'll stick to it for now.
 

thedesolatesoul

Expert
Licensed User
Longtime User
I've uploaded RGenerator2.
This is massively improved from version 1.
- Can deal with multiple symbols on the same line
- Removes any duplicates
- Adds the BA import at the start

Pretty much generated a flawless R file for me now.

I did try the Android Project method, but it was so incredibly messy and error prone (that I ended up deleting my whole source! good thing i set up GitLab!), I prefer this method as it works in one shot.
 

thedesolatesoul

Expert
Licensed User
Longtime User
Just to add more information about R class generation.
Sometimes the identifier is an array of resources, so it is an int[] instead of int. These are particularly used when loading the whole style attributes in one go, they are actually just an array of individual resources.
The RGenerator obviously doesnt cope with these.

There are three ways to cope with these but they are pretty raw:
1. Add the res files to an Android project in Eclipse as @corwin42 mentioned above.
2. Just add the res files as AdditionalRes to a B4A project. A compile will generate the full R.java file in Object/gen. Its pretty hard coded so I am not sure if it will have conflicts later on with multiple libraries.
3. Do it manually. Each entry in the array consists of a resource type and a counter.
 

thedesolatesoul

Expert
Licensed User
Longtime User
Can you drop an example for this?

I have several librarywrapping-tryings where i stuck at such a point.
Here is the best information I found on the subject: http://stackoverflow.com/a/6646113

Which makes my Step2 kind of wrong.

I know this is manual labour but this is how I think you would go about it:
(untested)
B4X:
public static int civ_primary_color = ...
public static int civ_secondary_color = ...

public static int[] civ = {civ_primary, civ_secondary};

The question is how do you figure out the order? I believe they will be in the same order defined in the attribute set or styleable.
 

DonManfred

Expert
Licensed User
Longtime User
The question is how do you figure out the order?
Im not sure but i think the order does not matter cause most of the "original libs" (so far i seen them in wrappers i did and run into problems cause of exactly this (using complete STYLEABLE blocks)) are using the values "by name" and not "by order"

Will try out the sample you posted on a project i actually get stuck about this issue.Will keep you informed

Thank you for your snippet!
 

DonManfred

Expert
Licensed User
Longtime User
I wrote a part of r class for a new wrapper. With you suggestion the command
B4X:
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.WeekView, 0, 0);
does not show an error now. Not sure actully if it will work... Keep you updated
 
Top