Java Question Wrappers for Android Libraries

socialnetis

Active Member
Licensed User
Longtime User
Hi, I'm trying to make a wrapper for Aviary (a powerful photo editor).
The SDK it's not a single .jar file, is an Android Library instead. It has activities, resources, manifest, .so libraries (one for each architecture: armeabi, armeabi-v7a, x86), etc.

When you download the SDK without importing it to Eclipse, the "bin" and "gen" folders are empty. When you import it to eclipse, this folders creates some files. In the "bin" folder there is now a "Aviary-SDK.jar" file, and under "gen" there is a "R.java" file.

If you want to use this SDK, you need to reference this whole Android project, and just use some intents to open the Aviary activity for editors, and wait for the result when you are done.

This is what I have tried so far, and failed:
- Get the Aviary-SDK.jar under "bin" (that is created once you import the project), and paste it in the B4A AddLibraries
- Copy the libs from the libs folder from Aviary project, to the B4A AddLibraries.
- Create a Java Library (the wrapper), and import the external jars needed (android 4, B4AShared, Aviary-SDK, and the jars under lib/ folder from the Aviary project)
- Merge the res/ folder from the Aviary project, with the Objects/res folder of a B4A project (and mark it as read only).

When trying to use this wrapper, I get this error:
java.lang.NoClassDefFoundError: com.aviary.android.feather.R$layout

This is the R.java file under /gen folder in the Aviary project. Which I'm not referencing at all, and don't think that should be necesary.

I think that my approach is really far away from what should be done. I'm not even referencing the .so files.

Any ideas on where to start digging?
 

warwound

Expert
Licensed User
Longtime User
You have some extra steps to take to wrap an android library project into a b4a library.
Take a look at this io.vov.vitamio.R class from the Vitamio android project library:

B4X:
package io.vov.vitamio;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static int ic_launcher=0x7f020000;
        public static int mediacontroller_bg=0x7f020001;
        public static int mediacontroller_pause01=0x7f020002;
        public static int mediacontroller_pause02=0x7f020003;
        public static int mediacontroller_pause_button=0x7f020004;
        public static int mediacontroller_play01=0x7f020005;
        public static int mediacontroller_play02=0x7f020006;
        public static int mediacontroller_play_button=0x7f020007;
        public static int mediacontroller_seekbar=0x7f020008;
        public static int mediacontroller_seekbar01=0x7f020009;
        public static int mediacontroller_seekbar02=0x7f02000a;
        public static int mediacontroller_seekbar_thumb=0x7f02000b;
    }
    public static final class id {
        public static int mediacontroller_file_name=0x7f070004;
        public static int mediacontroller_play_pause=0x7f070000;
        public static int mediacontroller_seekbar=0x7f070003;
        public static int mediacontroller_time_current=0x7f070001;
        public static int mediacontroller_time_total=0x7f070002;
    }
    public static final class layout {
        public static int mediacontroller=0x7f030000;
    }
    public static final class raw {
        public static int libarm=0x7f040000;
    }
    public static final class string {
        public static int mediacontroller_play_pause=0x7f050006;
        public static int vitamio_init_decoders=0x7f050001;
        public static int vitamio_name=0x7f050000;
        public static int vitamio_videoview_error_button=0x7f050005;
        public static int vitamio_videoview_error_text_invalid_progressive_playback=0x7f050003;
        public static int vitamio_videoview_error_text_unknown=0x7f050004;
        public static int vitamio_videoview_error_title=0x7f050002;
    }
    public static final class style {
        public static int MediaController_SeekBar=0x7f060000;
        public static int MediaController_Text=0x7f060001;
    }
}

The wrapped Vitamio library references this R class to load resources, these resources will have been added to the b4a project's various Objects\res\? folders.
So i copied this R class into my b4a Vitamio wrapper library and modified it:

B4X:
package io.vov.vitamio;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Hide;

@Hide
public class R {
   @Hide
   public static final class attr {
   }

   @Hide
   public static final class drawable {
      public static int ic_launcher = BA.applicationContext.getResources().getIdentifier("ic_launcher", "drawable", BA.packageName);
      public static int mediacontroller_bg = BA.applicationContext.getResources().getIdentifier("mediacontroller_bg", "drawable", BA.packageName);
      public static int mediacontroller_pause01 = BA.applicationContext.getResources().getIdentifier("mediacontroller_pause01", "drawable", BA.packageName);
      public static int mediacontroller_pause02 = BA.applicationContext.getResources().getIdentifier("mediacontroller_pause02", "drawable", BA.packageName);
      public static int mediacontroller_pause_button = BA.applicationContext.getResources().getIdentifier("mediacontroller_pause_button", "drawable", BA.packageName);
      public static int mediacontroller_play01 = BA.applicationContext.getResources().getIdentifier("mediacontroller_play01", "drawable", BA.packageName);
      public static int mediacontroller_play02 = BA.applicationContext.getResources().getIdentifier("mediacontroller_play02", "drawable", BA.packageName);
      public static int mediacontroller_play_button = BA.applicationContext.getResources().getIdentifier("mediacontroller_play_button", "drawable", BA.packageName);
      public static int mediacontroller_seekbar = BA.applicationContext.getResources().getIdentifier("mediacontroller_seekbar", "drawable", BA.packageName);
      public static int mediacontroller_seekbar01 = BA.applicationContext.getResources().getIdentifier("mediacontroller_seekbar01", "drawable", BA.packageName);
      public static int mediacontroller_seekbar02 = BA.applicationContext.getResources().getIdentifier("mediacontroller_seekbar02", "drawable", BA.packageName);
      public static int mediacontroller_seekbar_thumb = BA.applicationContext.getResources().getIdentifier("mediacontroller_seekbar_thumb", "drawable", BA.packageName);
   }

   @Hide
   public static final class id {
      public static int mediacontroller_file_name = BA.applicationContext.getResources().getIdentifier("mediacontroller_file_name", "id", BA.packageName);
      public static int mediacontroller_play_pause = BA.applicationContext.getResources().getIdentifier("mediacontroller_play_pause", "id", BA.packageName);
      public static int mediacontroller_seekbar = BA.applicationContext.getResources().getIdentifier("mediacontroller_seekbar", "id", BA.packageName);
      public static int mediacontroller_time_current = BA.applicationContext.getResources().getIdentifier("mediacontroller_time_current", "id", BA.packageName);
      public static int mediacontroller_time_total = BA.applicationContext.getResources().getIdentifier("mediacontroller_time_total", "id", BA.packageName);
   }

   @Hide
   public static final class layout {
      public static int mediacontroller = BA.applicationContext.getResources().getIdentifier("mediacontroller", "layout", BA.packageName);
   }

   @Hide
   public static final class raw {
      public static int libarm = BA.applicationContext.getResources().getIdentifier("libarm", "raw", BA.packageName);
   }

   @Hide
   public static final class string {
      public static int mediacontroller_play_pause = BA.applicationContext.getResources().getIdentifier("mediacontroller_play_pause", "string", BA.packageName);
      public static int vitamio_init_decoders = BA.applicationContext.getResources().getIdentifier("vitamio_init_decoders", "string", BA.packageName);
      public static int vitamio_name = BA.applicationContext.getResources().getIdentifier("vitamio_name", "string", BA.packageName);
      public static int vitamio_videoview_error_button = BA.applicationContext.getResources().getIdentifier("vitamio_videoview_error_button", "string", BA.packageName);
      public static int vitamio_videoview_error_text_invalid_progressive_playback = BA.applicationContext.getResources().getIdentifier("vitamio_videoview_error_text_invalid_progressive_playback", "string", BA.packageName);
      public static int vitamio_videoview_error_text_unknown = BA.applicationContext.getResources().getIdentifier("vitamio_videoview_error_text_unknown", "string", BA.packageName);
      public static int vitamio_videoview_error_title = BA.applicationContext.getResources().getIdentifier("vitamio_videoview_error_title", "string", BA.packageName);
   }

   @Hide
   public static final class style {
      public static int MediaController_SeekBar = BA.applicationContext.getResources().getIdentifier("MediaController_SeekBar", "style", BA.packageName);
      public static int MediaController_Text = BA.applicationContext.getResources().getIdentifier("MediaController_Text", "style", BA.packageName);
   }
}

The wrapped Vitamio library can now correctly find the resources it requires - the resources are compiled into the b4a APK and the modified io.vov.vitamio.R class returns the correct resource ids.

Martin.
 

socialnetis

Active Member
Licensed User
Longtime User
Thx for the response, I have come with a solution too.

This is what I did:
- Export the complete Android project as a Jar file (lets say MySDK.jar), but without the /libs and /res folder (and also unmark the Android Manifest)
- Copy the jar files from /libs of the Android Project in the AddiotionalLibraries folder from B4A
- Create the wrapper (let's say "MyWrapper") as usual, when you import the external jars, you also need to import the jars from the /libs folder from the Android project, and the "MySDK.jar" file. And use the "@DependsOn" notation to reference this jars when compiling the b4a project.
- In my case, I also had .so libraries in the /libs folder. So I added to the "MyWrapper" project under a folder called "lib" ("libs" didn't worked for me).
- Export the MyWrapper as usual.

And when you want to use it in a b4A project, you need to merge the /res folder from the Android Project, with the Objects/res folder from the b4a project.

Hope this helps!
 

socialnetis

Active Member
Licensed User
Longtime User
Hey warwound, is that Vitamio v3?
Right now I'm starting a radio app for a local radio, that uses wma files under the mms protocol. I have tested the demo Vitamio app under eclipse and, tested my link and it works. Are you going to upload that wrapper? The currently wrapper in the forum is from and older version and you need to install extra plugins, which is not a nice approach for users.
 
Top