Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep 'META-INF/services'-files in apk

I have a custom charset which is already working on JavaSE.

The class of my CharsetProvider is specified in a file java.nio.charset.spi.CharsetProvider which is located in META-INF/services and everything get's loaded normally and works as expected.

However now I'm using the lib on android as well, but the charset isn't loaded in Android-App.

How can I integrate my charset, so that it can be used like expected in an Android-App?

Charset.forName("MyCS");

At the moment I'm doing a workaround like this:

public static String decode(String encoding, byte[] buffer, int offset, int length) {
    String result = "";
    try {
        result = new String(buffer, offset, length, encoding);
    } catch (UnsupportedEncodingException ex) {
        MyCharsetProvider provider = new MyCharsetProvider();
        Charset cs = provider.charsetForName(encoding);
        if (cs == null) {
            Logger.getLogger(Converters.class.getName()).log(
                    Level.SEVERE,null,ex);
            result = new String(buffer, offset, length);
        } else {
            result = cs.decode(ByteBuffer.wrap(buffer, offset, length)).toString();
        }
    }
    return result;
}

Which works, but seems ineffective to me, since everytime I try to decode like this with my own charset, an exception will be thrown and a CharsetProvider-Object will be created.

The creation of course could be reduced by singleton pattern. But the issue is to avoid the direct usage of MyCharsetProvider entirely.

EDIT :

Since META-INF/services/java.nio.charset.spi.CharsetProvider is missing in the apk I though maybe proguard removes it. I then tried the following options in proguard.cfg:

-adaptresourcefilenames **.CharsetProvider
-adaptresourcefilecontents **.CharsetProvider

But the problem still persists. so how can I get these files from META-INF/services into my apk automatically using ant (netbeans)?

like image 544
AlexS Avatar asked Oct 21 '22 08:10

AlexS


1 Answers

ANT

I'm using the following solution now:

I created a custom_rules.xml with the followin targets to copy files in META-INF/services into the unaligned and unsigned apk.

<target name="-post-package" depends="-custom-copy" />

<target name="-copy-custom">
    <zip destfile="${out.packaged.file}"
         update="true"
         basedir="${source.absolute.dir}"
         includes="${custom.copy}" />
</target>

And in ant.properties I added the line

custom.copy=META-INF/services/**

Now I just have to copy relevant files from libraries to the META-INF/services-folder of my own project to include them in the apk. This gives me full control over which classes to be loaded by ServiceLoader.

Remark: Currently I only load implementations that are included in external Java-SE-jars this way. Obfuscation may have to be configured if the implementations are in an android-project.


ECLIPSE-PLUGIN

Using the eclipse-plugin, there's no workaround like in ANT. The problem is the ExportHelper (line 405) which just igores everything in META-INF folders.


Android-Studio/GRADLE

According to this Bug you may define a META-INF-directory in your main project and this will be packaged into your apk. META-INF-folders of libraries are excluded, so that you are forced to specify the implementations you want to use in your own project (I think this is the intention of it).

like image 60
AlexS Avatar answered Oct 24 '22 09:10

AlexS