5

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

AlexS
  • 5,295
  • 3
  • 38
  • 54

1 Answers1

3

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

AlexS
  • 5,295
  • 3
  • 38
  • 54
  • Any work around to get it copied without switching to Ant? – Singagirl Oct 10 '15 at 08:03
  • @DmitriyR Which build-system do you use? I don't think there is [going to be] a good workaround for the eclipse-plugin. – AlexS Oct 13 '15 at 10:40
  • I use Eclipse, so finally I managed to export unsigned .apk and then wrote a script adding the path to apk and signing and ziplaligning. Inconvenient but works. Major problem that I can't deploy it straight from Eclipse to emulator. – Singagirl Oct 13 '15 at 12:15
  • @DmitriyR The time I wrote this answer I was digging into the eclipse-plugin and found a non-configurable filter, that filtered out META-INF. So I think there is no better solution than yours. But the answer is already 2 years old, so maybe there are some new options and features in the plugin regarding this problem. – AlexS Oct 14 '15 at 07:29
  • Unfortunately Google discontinued Eclipse as a platform for Android development introducing something heavy weight like Android Studio. I still can't migrate to new tool where maybe the problem can be resolved using Gradle. However Gradle is another story. – Singagirl Oct 15 '15 at 08:36
  • @DmitriyR I know that google discontinued eclipse-plugin, but there had been new releases since my last investigation. So I had a look at the latest sources of the eclipse-plugin: Unfortunately there is nothing new regarding this issue. The [ExportHelper](https://android.googlesource.com/platform/sdk/+/tools_r22.6/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java) just ignores everything in `META-INF` (see line 405). Maybe you can change this to make your own eclipse-plugin... – AlexS Oct 15 '15 at 08:51
  • I wish it was hosted at GitHub, I could fork it and continue working on the plug-in. let me try a work around, it does check as case sensitive, if I change its name in lower case, maybe it still will working ? – Singagirl Oct 15 '15 at 10:15
  • @DmitriyR Nice idea. The lowercase folder will be in your JAR/APK, but I don't think this will solve your problem, since the ServiceLoader is probably looking for a uppercase `META-INF` and I think the ClassLoader is case sensitive. But you can give it a try. I'm exited about your results. (According to this [bug](https://netbeans.org/bugzilla/show_bug.cgi?id=174802) it would work on windows :P ). – AlexS Oct 15 '15 at 11:44
  • You are right, ServiceLoader isn't flexible. (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ServiceLoader.java#336), but funny thing I use a custom class loader anyway so I can add special handling of META-INF in both cases. Thanks, – Singagirl Oct 17 '15 at 14:25
  • @Dmitriy Just wondering: Why can't you switch to AndroidStudio? – AlexS Oct 17 '15 at 17:00
  • There are several reasons, few of major ones: 1) AndroidStudio is heavier than Eclipse and my company doesn't supply a good performing development hardware. 2) It requires a separate install of a Git client for Windows (Eclipse has it embedded, 3) For some reason AndroidStudio generates 20% bigger APK comparing to Eclipse, 4) AndroidStudio doesn't like if linked libraries use some not Android supported API even if they are not used directly, 5) Gradle build process is really slow. I still consider AndroidStudio has some usability problems. – Singagirl Oct 23 '15 at 22:02
  • @DmitriyR Sounds reasonable and interesting. Especially the part concerning APK-size. – AlexS Oct 24 '15 at 08:11
  • It was my biggest disappointment that size increased, and all my attempts playing with different build parameters didn't help. – Singagirl Nov 06 '15 at 05:29