Java Question loading dynamically linked library

qle

Member
Licensed User
Longtime User
Hi,
My project requires to read data from a serial (uart) port. (not bluetooth)

I have created a small project in eclipse, for android 2.2 (API 8) that works fine.

I have now converted/exported this to an external library .jar /.xml for b4a, this works quite well and i can access functions within the external library. :)

But the problems occur when i try to load the libserial_port.so "serial_port" in the library.
static {
System.loadLibrary("serial_port");
}

In B4A logs when trying to run the application i get
java.lang.UnsatisfiedLinkError: Couldn't load serial_port: findLibrary returned null

1) I have copied the libseral_port.so to the File.DirInternal
2) Also copied to /system/lib folder

Any help or suggestions you may offer will be greatly appreciated.

Best Regards
Lee.
 

qle

Member
Licensed User
Longtime User
Change to:
System.load(File.Combine(File.getDirInternal(), "serial_port.so"));

File is anywheresoftware.b4a.objects.streams.File

Thank you Erel, This did the trick :)

I can now correctly configure the baud rate of the Serial UART, and read/write the device.

What is the best way to copy the serial_port.so to the File.getDirInternal location?

Can this be done via the .apk package install?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. Add the file to the Files tab.
2. Check if the file exists in File.DirInternal when program starts and if not copy it from File.DirAssets.

While answering another question I realized that there is a simpler way to include the file.
1. Rename it to libserial_port.so
2. Create a folder name lib\armeabi in your eclipse project and put the file there.
3. System.loadLibrary("serial_port"); should now work.
 

qle

Member
Licensed User
Longtime User
1. Add the file to the Files tab.
2. Check if the file exists in File.DirInternal when program starts and if not copy it from File.DirAssets.

This is the method i had to use (see below for rough code in eclipse to deal with it)

2. Create a folder name lib\armeabi in your eclipse project and put the file there.

The eclipse project already has lib\armeabi\libseral_port.so
And using zip7 to look in the .jar, i can see the folders and file.

In the B4A apk package i can also see that lib\armeabi\libseral_port.so exists!

But doing a File.ListFiles in both DirAssets and getDirInternal, after the install, shows that the files does not exist!

For now i have added to the Files Tab in B4A, (this installs it to DirAssets)
And then in the Library (eclipse project) i use
B4X:
static {
      //System.loadLibrary("serial_port");
      try {
         if (File.Exists(File.getDirInternal(), "libserial_port.so") == true){
               System.load(File.Combine(File.getDirInternal(), "libserial_port.so"));
         }else{
            Log.d(TAG,File.getDirInternal());
            Log.d(TAG,"Not Found: File.getDirInternal() libserial_port.so");
            //**************************************************************
            try {
               if (File.Exists(File.getDirAssets(), "libserial_port.so") == true){
                  Log.d(TAG,"Copy serial lib from File.getDirInternal()");
                  File.Copy(File.getDirAssets(), "libserial_port.so", File.getDirInternal(), "libserial_port.so");
                  System.load(File.Combine(File.getDirInternal(), "libserial_port.so"));
               }else{
                  Log.d(TAG,File.getDirInternal());
                  Log.d(TAG,"Not Found: File.getDirAssets() libserial_port.so");
               }
            } catch (IOException e) {
               e.printStackTrace();
            }
            //*********************************************            
         }
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

Im happy with this solution.
Would like to thank you for your help and time, and a big thank you to all the users who posted the valuable information to these forums.

Lee.
 

warwound

Expert
Licensed User
Longtime User
If you B4A library jar contains the .so file in folder lib/armeabi/libserial_port.so then when your B4A application is installed the .so file should automtically be copied to folder data/data/your.package.name/lib.

You can check that on a rooted device, if the device is not rooted i'm not sure how you'd check that the .so library file has been copied across.

Anyway, if the .so library file has been copied across then your B4A library's static constructor can be as simple as:

B4X:
static{
    System.loadLibrary("serial_port");
}

You might find my recent post useful: http://www.b4x.com/forum/bugs-wishlist/21726-wish-compiler-support-so-library-files.html#post125742

Martin.
 

qle

Member
Licensed User
Longtime User
Hi Martin,
I have tried putting libserial_port.so into eclipse
1) lib/armeabi/libserial_port.so
2) libs/armeabi/libserial_port.so
3) lib/libserial_port.so

And rebuild each time.
i can open with 7zip and see that the file does exist in the jar and apk.

but System.loadLibrary("serial_port"); fails each time.

Unfortunately the device is not rooted.

The workaround i have is working well tho, and im happy it works!

Thank you for your time.
 

warwound

Expert
Licensed User
Longtime User
Well from what i understand, if your library .jar contains a .so file in a lib or lib/armeabi folder then, when you compile a B4A app, the app installation will automatically copy the .so file to your app's data/data/your.package.name/lib folder.

The device not being rooted makes things tricky to check.
I guess you could write some temporary B4A code in your app to find out if the .so file exists using the File object's Exists method.

But as your workaround is ok it might not be worth the time.

However if in future you have more than one version of the same .so library (optimalised for different CPUs) then you'd want to get the method i've posted about to work - that way you can leave it to the Android installer to choose and copy the correct .so file.

Martin.
 
Top