androidmeta-infserviceloader

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)?


Solution

  • 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).