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
I guess the problem is that it wont show an error, but you dont know which resource is which (as it is just an array of integers).
I tried it today with one of my Wrappers which i did not get to work due to exact this problem...

i tried today to write the code you suggested

B4X:
    public static final class styleable {
        //public static int[] WeekView = BA.applicationContext.getResources().getIdentifier("WeekView", "styleable", BA.packageName);
        public static int WeekView_firstDayOfWeek = BA.applicationContext.getResources().getIdentifier("WeekView_firstDayOfWeek", "styleable", BA.packageName);
        public static int WeekView_hourHeight = BA.applicationContext.getResources().getIdentifier("WeekView_hourHeight", "styleable", BA.packageName);
        public static int WeekView_textSize = BA.applicationContext.getResources().getIdentifier("WeekView_textSize", "styleable", BA.packageName);
        public static int WeekView_headerColumnPadding = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnPadding", "styleable", BA.packageName);
        public static int WeekView_columnGap = BA.applicationContext.getResources().getIdentifier("WeekView_columnGap", "styleable", BA.packageName);
        public static int WeekView_headerColumnTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnTextColor", "styleable", BA.packageName);
        public static int WeekView_noOfVisibleDays = BA.applicationContext.getResources().getIdentifier("WeekView_noOfVisibleDays", "styleable", BA.packageName);
        public static int WeekView_headerRowPadding = BA.applicationContext.getResources().getIdentifier("WeekView_headerRowPadding", "styleable", BA.packageName);
        public static int WeekView_headerRowBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_headerRowBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_dayBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_dayBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_hourSeparatorColor = BA.applicationContext.getResources().getIdentifier("WeekView_hourSeparatorColor", "styleable", BA.packageName);
        public static int WeekView_todayBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_todayBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_hourSeparatorHeight = BA.applicationContext.getResources().getIdentifier("WeekView_hourSeparatorHeight", "styleable", BA.packageName);
        public static int WeekView_todayHeaderTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_todayHeaderTextColor", "styleable", BA.packageName);
        public static int WeekView_eventTextSize = BA.applicationContext.getResources().getIdentifier("WeekView_eventTextSize", "styleable", BA.packageName);
        public static int WeekView_eventTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_eventTextColor", "styleable", BA.packageName);
        public static int WeekView_headerColumnBackground = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnBackground", "styleable", BA.packageName);
        public static int WeekView_dayNameLength = BA.applicationContext.getResources().getIdentifier("WeekView_dayNameLength", "styleable", BA.packageName);
        public static int WeekView_overlappingEventGap = BA.applicationContext.getResources().getIdentifier("WeekView_overlappingEventGap", "styleable", BA.packageName);
        public static int WeekView_eventMarginVertical = BA.applicationContext.getResources().getIdentifier("WeekView_eventMarginVertical", "styleable", BA.packageName);
        public static int WeekView_xScrollingSpeed = BA.applicationContext.getResources().getIdentifier("WeekView_xScrollingSpeed", "styleable", BA.packageName);
        public static int[] WeekView = {WeekView_firstDayOfWeek,WeekView_hourHeight,
            WeekView_textSize,WeekView_headerColumnPadding,WeekView_columnGap,WeekView_headerColumnTextColor,
            WeekView_noOfVisibleDays,WeekView_headerRowPadding,WeekView_headerRowBackgroundColor,
            WeekView_dayBackgroundColor,WeekView_hourSeparatorColor,WeekView_todayBackgroundColor,
            WeekView_hourSeparatorHeight,WeekView_todayHeaderTextColor,WeekView_eventTextSize,
            WeekView_eventTextColor,WeekView_headerColumnBackground,WeekView_dayNameLength,
            WeekView_overlappingEventGap,WeekView_eventMarginVertical,WeekView_xScrollingSpeed};

See this now :D

DayView001.png


DayView002.png


DayView003.png


It works! But in this case i use the exact order like the rgen created the ints... Dont know whether this matters
 

thedesolatesoul

Expert
Licensed User
Longtime User

thedesolatesoul

Expert
Licensed User
Longtime User
Infoupdate:
In the last weeks i found out that the order of the int[] array entries does not count. I tried exact order, i tried totally different order. Both works fine.
You are right, the order of entries definitely doesnt matter. Its just really a shortcut to load all the attributes quickly.
However, I think I didnt see your code properly previously.
How are you loading the attr inside the styleable with:
B4X:
public static int WeekView_firstDayOfWeek = BA.applicationContext.getResources().getIdentifier("WeekView_firstDayOfWeek", "styleable", BA.packageName);
I had to change "styleable" to "attr" to get it to work.
 

DonManfred

Expert
Licensed User
Longtime User
B4X:
        //public static int WeekView = BA.applicationContext.getResources().getIdentifier("WeekView", "styleable", BA.packageName);
this was the line created by RGen

I followed your advice how this should work. With THIS result
B4X:
        public static int[] WeekView = {WeekView_firstDayOfWeek,WeekView_hourHeight,
            WeekView_textSize,WeekView_headerColumnPadding,WeekView_columnGap,WeekView_headerColumnTextColor,
            WeekView_noOfVisibleDays,WeekView_headerRowPadding,WeekView_headerRowBackgroundColor,
            WeekView_dayBackgroundColor,WeekView_hourSeparatorColor,WeekView_todayBackgroundColor,
            WeekView_hourSeparatorHeight,WeekView_todayHeaderTextColor,WeekView_eventTextSize,
            WeekView_eventTextColor,WeekView_headerColumnBackground,WeekView_dayNameLength,
            WeekView_overlappingEventGap,WeekView_eventMarginVertical,WeekView_xScrollingSpeed};
this is the line i created manually (must be the last line in this block)

And this is the complete code
B4X:
public static final class styleable {
        //public static int[] WeekView = BA.applicationContext.getResources().getIdentifier("WeekView", "styleable", BA.packageName);
        public static int WeekView_firstDayOfWeek = BA.applicationContext.getResources().getIdentifier("WeekView_firstDayOfWeek", "styleable", BA.packageName);
        public static int WeekView_hourHeight = BA.applicationContext.getResources().getIdentifier("WeekView_hourHeight", "styleable", BA.packageName);
        public static int WeekView_textSize = BA.applicationContext.getResources().getIdentifier("WeekView_textSize", "styleable", BA.packageName);
        public static int WeekView_headerColumnPadding = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnPadding", "styleable", BA.packageName);
        public static int WeekView_columnGap = BA.applicationContext.getResources().getIdentifier("WeekView_columnGap", "styleable", BA.packageName);
        public static int WeekView_headerColumnTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnTextColor", "styleable", BA.packageName);
        public static int WeekView_noOfVisibleDays = BA.applicationContext.getResources().getIdentifier("WeekView_noOfVisibleDays", "styleable", BA.packageName);
        public static int WeekView_headerRowPadding = BA.applicationContext.getResources().getIdentifier("WeekView_headerRowPadding", "styleable", BA.packageName);
        public static int WeekView_headerRowBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_headerRowBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_dayBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_dayBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_hourSeparatorColor = BA.applicationContext.getResources().getIdentifier("WeekView_hourSeparatorColor", "styleable", BA.packageName);
        public static int WeekView_todayBackgroundColor = BA.applicationContext.getResources().getIdentifier("WeekView_todayBackgroundColor", "styleable", BA.packageName);
        public static int WeekView_hourSeparatorHeight = BA.applicationContext.getResources().getIdentifier("WeekView_hourSeparatorHeight", "styleable", BA.packageName);
        public static int WeekView_todayHeaderTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_todayHeaderTextColor", "styleable", BA.packageName);
        public static int WeekView_eventTextSize = BA.applicationContext.getResources().getIdentifier("WeekView_eventTextSize", "styleable", BA.packageName);
        public static int WeekView_eventTextColor = BA.applicationContext.getResources().getIdentifier("WeekView_eventTextColor", "styleable", BA.packageName);
        public static int WeekView_headerColumnBackground = BA.applicationContext.getResources().getIdentifier("WeekView_headerColumnBackground", "styleable", BA.packageName);
        public static int WeekView_dayNameLength = BA.applicationContext.getResources().getIdentifier("WeekView_dayNameLength", "styleable", BA.packageName);
        public static int WeekView_overlappingEventGap = BA.applicationContext.getResources().getIdentifier("WeekView_overlappingEventGap", "styleable", BA.packageName);
        public static int WeekView_eventMarginVertical = BA.applicationContext.getResources().getIdentifier("WeekView_eventMarginVertical", "styleable", BA.packageName);
        public static int WeekView_xScrollingSpeed = BA.applicationContext.getResources().getIdentifier("WeekView_xScrollingSpeed", "styleable", BA.packageName);
        public static int[] WeekView = {WeekView_firstDayOfWeek,WeekView_hourHeight,
            WeekView_textSize,WeekView_headerColumnPadding,WeekView_columnGap,WeekView_headerColumnTextColor,
            WeekView_noOfVisibleDays,WeekView_headerRowPadding,WeekView_headerRowBackgroundColor,
            WeekView_dayBackgroundColor,WeekView_hourSeparatorColor,WeekView_todayBackgroundColor,
            WeekView_hourSeparatorHeight,WeekView_todayHeaderTextColor,WeekView_eventTextSize,
            WeekView_eventTextColor,WeekView_headerColumnBackground,WeekView_dayNameLength,
            WeekView_overlappingEventGap,WeekView_eventMarginVertical,WeekView_xScrollingSpeed};

See this now :D
 

thedesolatesoul

Expert
Licensed User
Longtime User
I think I can make RGen generate this if I parse the styleable.xml. I just need the names and the order wont matter.

This is how I did it manually:
B4X:
public static class styleable {
          public static final int RippleView_rv_alpha = BA.applicationContext.getResources().getIdentifier("RippleView_rv_alpha", "attr", BA.packageName);
           public static final int RippleView_rv_centered = BA.applicationContext.getResources().getIdentifier("RippleView_rv_centered", "attr", BA.packageName);
           public static final int RippleView_rv_color = BA.applicationContext.getResources().getIdentifier("RippleView_rv_color", "attr", BA.packageName);
           public static final int RippleView_rv_framerate = BA.applicationContext.getResources().getIdentifier("RippleView_rv_framerate", "attr", BA.packageName);
           public static final int RippleView_rv_rippleDuration = BA.applicationContext.getResources().getIdentifier("RippleView_rv_rippleDuration", "attr", BA.packageName);
           public static final int RippleView_rv_ripplePadding = BA.applicationContext.getResources().getIdentifier("RippleView_rv_ripplePadding", "attr", BA.packageName);
           public static final int RippleView_rv_type = BA.applicationContext.getResources().getIdentifier("RippleView_rv_type", "attr", BA.packageName);
           public static final int RippleView_rv_zoom = BA.applicationContext.getResources().getIdentifier("RippleView_rv_zoom", "attr", BA.packageName);
           public static final int RippleView_rv_zoomDuration = BA.applicationContext.getResources().getIdentifier("RippleView_rv_zoomDuration", "attr", BA.packageName);
           public static final int RippleView_rv_zoomScale = BA.applicationContext.getResources().getIdentifier("RippleView_rv_zoomScale", "attr", BA.packageName);

         public static final int[] RippleView = {
         /*      0x7f01000b, 0x7f01000c, 0x7f01000d, 0x7f01000e,
               0x7f01000f, 0x7f010010, 0x7f010011, 0x7f010012,
               0x7f010013, 0x7f010014*/
               RippleView_rv_alpha,
               RippleView_rv_framerate,
               RippleView_rv_rippleDuration,
               RippleView_rv_zoomDuration,
               RippleView_rv_color,
               RippleView_rv_centered, 
               RippleView_rv_type,
               RippleView_rv_ripplePadding,
               RippleView_rv_zoom,
               RippleView_rv_zoomScale
           };
       }
 

DonManfred

Expert
Licensed User
Longtime User
Are those called by the library code?
sometimes, yes...

Drawable/test.png
->
B4X:
 public static final int RippleView_rv_centered = BA.applicationContext.getResources().getIdentifier("RippleView_rv_centered", "drawable", BA.packageName);
raw/test.jpg
->
B4X:
 public static final int RippleView_rv_centered = BA.applicationContext.getResources().getIdentifier("RippleView_rv_centered", "raw", BA.packageName);

both are subpart of "ID"
 

tchart

Well-Known Member
Licensed User
Longtime User
thedesolatesoul, thanks for your tool. Its proving very helpful.

BTW I was getting an "already added" error message when compiling if I included the #AdditionalRes declaration to the resource files I needed. To resolve I just renamed R.java to RX.java and replaced any reference to R to be RX. That has fixed the issue for the library. Im not sure if there is a better way to resolve this. Its a bit catch 22 as I need R.java to compile the library but then the compiler is finding duplicates in res\values files when B4A generates its R.java file.

Also, it might pay to get your tool to add a dummy package name to the start of the R.java output. It threw me for a while why it wasn't compiling until I realised it was missing the package name.
 

thedesolatesoul

Expert
Licensed User
Longtime User
I did update it to add a packagename to it, see RGenerator2

I think naming the class from R to Rx isnt probably the best thing to do. What is better is to put the R.java in the right package, and in the source files import from that particular package.
If you are getting an 'aready added' message (which i havent seen btw), you might have worse issues than you think...it maybe that multiple res sources have the same resource file names and they may be overwriting each other.
 

tchart

Well-Known Member
Licensed User
Longtime User
I did update it to add a packagename to it, see RGenerator2

thedesolatesoul, I do have RGenerator2. I see it adds the "import anywheresoftware.b4a.BA;" but it does not include a package name. Do I need to do anything special?

Also thedesolatesoul, any chance you would be willing to share the python code?
 
Last edited:

thedesolatesoul

Expert
Licensed User
Longtime User
thedesolatesoul, I do have RGenerator2. I see it adds the "import anywheresoftware.b4a.BA;" but it does not include a package name. Do I need to do anything special?
Yes there is no package name, because that depends on where you want to put it.

Also thedesolatesoul, any chance you would be willing to share the python code?
Sure, if you have a gitlab account, i'll just add you as a member to the repo.
 

tchart

Well-Known Member
Licensed User
Longtime User
Thanks, my gitlab account is gdbgeek.

Regarding the package name, can you just add a place holder package name as a reminder? Maybe "package com.remember.to.update.the.package.name"?
 
Top