B4A Library [Tool] Simple Library Compiler - Build libraries without Eclipse

Status
Not open for further replies.
The purpose of Simple Library Compiler (SLC) is to make it easier to build libraries. SLC is responsible for taking the Java source code files and generating the Jar and XML files.

As I see it, it can be useful in two cases:
- Creating wrappers for 3rd party SDKs.
- Modifying and extending existing open source libraries.

Do note that you still need to provide the source code. This tool only helps with the building steps.

SS-2013-06-04_19.25.38.png


How to use

Using SLC is quite simple. The main project folder should include a folder named src and optionally a folder named libs.
The Java source code files should be under the 'src' folder. Java files are saved based on the package name. So if the package is com.example then the structure will be:

SS-2013-06-04_19.29.16.png


Under 'libs' folder you can put any additional libraries that should be referenced during compilation.
The 'bin' folder will be created during the build.

When you press on the Compile button the code will be compiled and the Jar file and XML files will be outputted to the "additional libraries folder" that is set in Basic4android configuration.

Wrapper example

The attached zip file includes a very simpler wrapper that wraps Flurry Analytics library.

The source code:

SS-2013-06-04_19.37.03.png


In order to compile it (and use it) you should download their SDK and copy FlurryAgent.jar to the project 'libs' folder and to the 'additional libraries folder'.

Tips

- A simple example is included in the package (FirstLib). It is recommended to start with it.
- You can use a text editor such as Notepad++ to write the Java code.
- Tutorials about libraries development are available in this forum: http://www.b4x.com/android/forum/forums/libraries-developers-questions.32/
- There is no installer. You should just unzip the package and run the program.
- If you need to include any additional files, such as .so files, in the jar then you can create a folder named 'additional'. Any file or folder inside this folder will be added to the jar file.
- Command line mode - You can also run this tool from the command line. It expects two arguments: library name and project path.

- B4J_SimpleLibraryCompiler is included in the zip file. It creates B4J libraries.
- In order to write the library code with Eclipse you need to reference Java 7 and also reference jfxrt.jar:

SS-2013-12-02_10.01.50.png


V1.12 (B4A) - source and target raised to Java 8.
V1.11 - SLC tools compiled with .Net Framework 4.
V1.10 - Adds support for the new structure of Additional libraries folder.
March 2018 - New zip with doclet v1.07.
V1.06 - Fixes the missing "bin\classes" issue.
V1.05 - Fixes an issue with old compiled class files not being deleted.
V1.03 - Fixes an issue related to B4A v5.
V1.02 - Allows usages of Java 7 features.
V1.01 - Fixes an issue with ignore field.

Download link: www.b4x.com/android/files/SimpleLibraryCompiler.zip

You should use Java 8 with SLC (at least when generating the XML).
 
Last edited:

agb2008

Member
Licensed User
Longtime User
I am trying to create a B4J library. Source .java files were in cp1251 encoding - so I converted them to UTF-8 w/o BOM using Notepad++.
Compilation complete without any errors - but when at the stage: "Creation XML file" I've got errors for each .java file: "error: unmappable
character for encoding Cp1251
" and then text in wrong encoding... But why ? I've already converted all files in my project to UTF-8.
Could you please advice ?
 

Asim A Baki

Active Member
Licensed User
Longtime User
I can't compile vitamio bundle library from source, it gives an error, while I successfully exported the jar and javadoc from eclipse


B4X:
Starting step: Compiling Java code.
javac 1.7.0_51
D:\Downloads\VitamioBundle-4.2.0-eclipse-source\VitamioBundle-4.2.0-B4A\src\uk\co\martinpearman\b4a\vitamio\widget\MediaController.java:3: error: package io.vov.vitamio.widget does not exist
import io.vov.vitamio.widget.OutlineTextView;
                            ^
1 error


Error.
 

Asim A Baki

Active Member
Licensed User
Longtime User
Now after successful compilation with now warnings, when I try to compile my B4A project I face this error

class file for io.vov.vitamio.widget.VideoView not found
java.lang.UnsatisfiedLinkError: Couldn't load vinit from loader dalvik.system.PathClassLoader[DexPathList[[zip file "xxxxpro-1.apk"],nativeLibraryDirectories=[/data/app-lib/xxxxpro-1, /vendor/lib, /system/lib]]]: findLibrary returned null

I used DependsOn in the project
When I remove it I get a mismatch with Build error

Any Ideas?
 
Last edited:

b4xscripter

Member
Licensed User
Longtime User
Just one question. I'm wrapping a library with an event methods, just like Location_LocationChanged from the LocationManager.
I am not good in Java and I don't know how to "take" the event from a java code. Here goes my code:

B4X:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package io.socket;

import java.net.MalformedURLException;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

/**
*
* @author XXXXXX
*/
public class SocketIOClient {
private SocketIO socket;
public SocketIOClient(String host) throws MalformedURLException {
   
                        this.socket = new SocketIO(host);
                socket.connect(new IOCallback() {
            @Override
            public void onMessage(JSONObject json, IOAcknowledge ack) {
                try {
                    System.out.println("Server said:" + json.toString(2));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onMessage(String data, IOAcknowledge ack) {
                System.out.println("Server said: " + data);
            }

            @Override
            public void onError(SocketIOException socketIOException) {
                System.out.println("an Error occured");
                socketIOException.printStackTrace();
            }

            @Override
            public void onDisconnect() {
                System.out.println("Connection terminated.");
            }

            @Override
            public void onConnect() {
                System.out.println("Connection established");
            }

            @Override
            public void on(String event, IOAcknowledge ack, Object... args) {
                System.out.println("Server triggered event '" + event + "'");
            }
                        });
                                }
public void initialize(String host) throws MalformedURLException        
{
          SocketIOClient sc = new SocketIOClient(host);
          socket = sc.socket;
}
public void emit(String event,String jsonStr) throws ParseException {

                        org.json.simple.JSONObject jsonConf = null;
                        jsonConf = (org.json.simple.JSONObject)new JSONParser().parse(jsonStr);
                        socket.emit("joinCloud",jsonConf);              
}
}


From B4A, after the library is compiled, I can see the emit and initialize methods. But I need to "catch" the methods with @override.
Can I do it using de Simple Library Compiler?

Thank in advance, guys!
 

b4xscripter

Member
Licensed User
Longtime User
Well, using the Simple Library Compiler I could compile it:

B4X:
package anywheresoftware.b4a.SocketIOClient;

import anywheresoftware.b4a.BA.Permissions;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.*;
import anywheresoftware.b4a.BA;
import android.telephony.*;



import java.net.MalformedURLException;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.json.simple.parser.ParseException;
import io.socket.*;



@Permissions(values={"android.permission.INTERNET"})
@ShortName("SocketIOClient")
@DependsOn(values={"json-org","json-simple-1.1.1","WebSocket","socket2"})
@ActivityObject
@Events(values={"OnConnect(json as String)"})



public class SocketIOClient {
private SocketIO socket;
private BA ba;
private String eventName;
public void connect(String host) throws MalformedURLException {
   
      this.socket = new SocketIO(host);
          socket.connect(new IOCallback() {
            @Override
            public void onMessage(JSONObject json, IOAcknowledge ack) {
                try {
                    System.out.println("Server said:" + json.toString(2));
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onMessage(String data, IOAcknowledge ack) {
                System.out.println("Server said: " + data);
            }

            @Override
            public void onError(SocketIOException socketIOException) {
                System.out.println("an Error occured");
                socketIOException.printStackTrace();
            }

            @Override
            public void onDisconnect() {
                System.out.println("Connection terminated.");
            }

            @Override
            public void onConnect() {
                System.out.println("Connection established");
                ba.raiseEvent(this, eventName + "_onconnect","OK");
            }

            @Override
            public void on(String event, IOAcknowledge ack, Object... args) {
                System.out.println("Server triggered event '" + event + "'");
            }
                        });
                                }
public void initialize(BA ba, String EventName) throws MalformedURLException        
{
          this.ba = ba;
          this.eventName = EventName.toLowerCase(BA.cul);
}

}


Here goes my question because I don't understand very well what name should I use in my case to get the event working.....


B4X:
@Events(values={"OnConnect(json as String)"})

Should I put this one?

B4X:
Sub OnConnect(valor As String)
Msgbox("connected!","info")  

End Sub



Or this one, supposing that I initialize it this way:


B4X:
     Sub Globals

    Dim socket As SocketIOClient

End Sub

Sub Activity_Create(FirstTime As Boolean)
     DisableStrictMode
     socket.initialize("socket")
     socket.connect("http://192.168.1.3:8080/")

End Sub

Sub socket_onconnect(valor As String)
Msgbox("connected!","info")  

End Sub


I supposed this last name because of the:

B4X:
ba.raiseEvent(this, eventName + "_onconnect","OK");


Could anyone help me?

Thank you!!!!
 

ac9ts

Active Member
Licensed User
Longtime User
I have successfully compiled the source. I am having an issue with the generated XML file. I am getting the following error but am unsure on where to look since there are no source line numbers listed. I am using v1.03.

B4X:
Starting step: Compiling Java code.
Completed successfully.
Starting step: Creating jar file.
Completed successfully.
Starting step: Creating XML file.
java.lang.NullPointerException
    at BADoclet.writeClass(BADoclet.java:175)
    at BADoclet.start(BADoclet.java:376)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.tools.javadoc.DocletInvoker.invoke(DocletInvoker.java:310)
    at com.sun.tools.javadoc.DocletInvoker.start(DocletInvoker.java:189)
    at com.sun.tools.javadoc.Start.parseAndExecute(Start.java:366)
    at com.sun.tools.javadoc.Start.begin(Start.java:219)
    at com.sun.tools.javadoc.Start.begin(Start.java:205)
    at com.sun.tools.javadoc.Main.execute(Main.java:64)
    at com.sun.tools.javadoc.Main.main(Main.java:54)

Error.

It seems to be tripping up on figuring out what to do with parameter type "Locale"
This is the code being parsed.
B4X:
    /**
     * Sets the launch options.
     *
     * @param relaunchIfRunning Launches the app even if the same application is running on the receiver
     * @param locale The {@link Locale}
     */

    public void setLaunchOptions(boolean relaunchIfRunning, Locale locale) {
        mLaunchOptions = new LaunchOptions.Builder().setLocale(locale).setRelaunchIfRunning(relaunchIfRunning).build();
    }

and this is the last lines of the XML file.
B4X:
<method>
            <name>setLaunchOptions</name>
            <comment>Sets the launch options.
relaunchIfRunning: Launches the app even if the same application is running on the receiver
locale: The (@link Locale)</comment>
            <returntype>void</returnt
 
Last edited:

ac9ts

Active Member
Licensed User
Longtime User
I'm wrapping a SDK and I don't want to change names (unless I have to) as the library compiles as is. Is the change you are suggesting to get it through the XML generation? Is it getting stuck on set/get combinations?
 

ac9ts

Active Member
Licensed User
Longtime User
What are the rules that the parser is using to build the XML file? I changed the line as suggested and it parsed it but I'm getting the same error further in. If having a method name capitalized causes it to be exposed and lower case "hides" it, there are many other methods that were parsed that have lower case names. I'm not a Java guy (that's why I purchased b4a) so any little hint on what I need to do to complete this library would be helpful.

I'm not sure how easy this would be to do but if the line that is causing this error could be displayed, it would make it a bit easier to debug.
 
Last edited:

ac9ts

Active Member
Licensed User
Longtime User
So, based on the error I'm receiving, is there a "set" without a passed parameter or a "get" with a void return type? I'm grasping at straws here.

I am changing certain names such as setUpLauncher() to setupLauncher() as I know these are not properties. Should I also change them to _setupLauncher() or something else so the "set" is not parsed?

B4X:
java.lang.NullPointerException
    at BADoclet.writeClass(BADoclet.java:175)
    at BADoclet.start(BADoclet.java:376)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.tools.javadoc.DocletInvoker.invoke(DocletInvoker.java:310)
    at com.sun.tools.javadoc.DocletInvoker.start(DocletInvoker.java:189)
    at com.sun.tools.javadoc.Start.parseAndExecute(Start.java:366)
    at com.sun.tools.javadoc.Start.begin(Start.java:219)
    at com.sun.tools.javadoc.Start.begin(Start.java:205)
    at com.sun.tools.javadoc.Main.execute(Main.java:64)
    at com.sun.tools.javadoc.Main.main(Main.java:54)

Error.
 
Last edited:
Status
Not open for further replies.
Top