Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The API method for using this SDK in android has an exception #44

Closed
SunriseCompany opened this issue Jul 3, 2017 · 12 comments
Closed

Comments

@SunriseCompany
Copy link

java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar:classes2.dex)

when I wirte this:“
String uri = "https://horizon-testnet.stellar.org";
Server server=null;
try {
server = new Server(uri);
}catch (Throwable e){
e.printStackTrace();
System.out.println("==========异常");
}

”then,has an exception,

@overcat
Copy link
Member

overcat commented Jul 14, 2017

The project used HttpClient, but it is deprecated in Android SDK 23.
You can check here: https://developer.android.com/sdk/api_diff/23/changes.html

@bartekn
Copy link
Contributor

bartekn commented Jul 14, 2017

I prepared a JAR file without dependencies: https://www.dropbox.com/s/0z3bu5c67mv9eka/stellar-sdk.jar?dl=0 Please do not use it in production, just check if it works for you and let me know.

@luizjrrd
Copy link

@srayhunter
Copy link

@SunriseCompany I have committed the fixes for the ability to use Android with the java sdk. Check it out here - https://github.com/srayhunter/java-stellar-sdk

Feedback welcome!

@eschgi
Copy link

eschgi commented Jan 7, 2018

@srayhunter I have tried your fixes but with no luck. I get apk build errors when i use my own compiled version of the java-stellar-sdk jar. I've build the jar with gradlew.bat build. I have also tried to change the guava dependency from guava to guava-android, but without luck.

Have you maybe a working android sample project?

@eschgi
Copy link

eschgi commented Jan 7, 2018

@srayhunter I get this error when i build the apk: Error:Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'.

More than one file was found with OS independent path 'javax/annotation/CheckReturnValue.java'

Someone know what i'm doing wrong?

@srayhunter
Copy link

srayhunter commented Jan 7, 2018

@eschgi I found a couple issues last night that I will fix today and let you know when those are committed. Thank you for the feedback! Much appreciated.

@eschgi
Copy link

eschgi commented Jan 7, 2018

@srayhunter Ok perfect. Eventually for the future it would be better to use OkHttp for all http requests. OkHttp supports additionally HTTP/2 and supports also asynchronous programming patterns.

@nono3551
Copy link

@srayhunter @bartekn
Hello is there any sollution for this issue? I am using newest android studio and compiling project with SDK 26 and this library is not working. I saw that there were some changes in android SDK but is there any way I can make this lib working?

Thank you.

@reverbel
Copy link

reverbel commented Jan 20, 2018

After spending some time on this issue, I confirm that java-stellar-jdk does not work on Android because it uses Apache classes that cannot be loaded into the Android plataform. The culprit classes live on packages org.apache.http and org.apache.commons.codec.

Surprisingly, the problem shows up even on recent (6.0 and later) versions of Android, after support for the Apache HTTP client was officially removed from the platform (https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html).

What happens on earlier versions of Android is clear. Those versions are bundled with a legacy version of Apache's HttpClient, which depends on Commons Codec. The legacy versions of HttpClient and Codec are loaded as part of the Android platform, taking precedence over any classes in the application's classpath.

java-stellar-jdk does not work with the legacy Apache classes, as it calls HttpClient and Codec methods that do not exist on those ancient classes. Moreover, the legacy classes prevent java-stellar-jdk from using newer versions of those classes. The newer versions of those classes collide with the (pre-loaded) legacy versions. The Android bytecode translator detect the conflicts and does not convert the newer class files into the dex format.

One would expect that this problem would vanish from Android 6.0 (API 23) on, after support to the legacy Apache classes was officially dropped from the platform. However, this did not happen, and here is where things get messy. Even though those classes are not exposed as part of any user-visible Android APIs, it appears that they somehow remain existing within Android and still prevent applications to load newer HttpClient and Codec versions.

To demonstrate the problem, I ran a quick experiment on Android 7.0. My experiment did not use java-stellar-jdk at all. This is the relevant code:

import org.apache.commons.codec.binary.Base64;
...
    public void onClick(View view) {
        String base64Encoded = "...";
        Base64 base64Codec = new Base64();
        byte[] decoded = base64Codec.decode(base64Encoded);
        Snackbar.make(view, "decoded: " + Arrays.toString(decoded),
                      Snackbar.LENGTH_LONG)
                .setAction("Action", null).show();
                }
        }

The code above fails with the following exception:

java.lang.NoSuchMethodError: No virtual method decode(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
    at com.example.codecandhttptest.MainActivity$1.onClick(MainActivity.java:35)
    at android.view.View.performClick(View.java:6261)
    at android.view.View$PerformClick.run(View.java:23748)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6776)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

The exception above was produced on Android 7.0, by an app that had commons-codec:1.5 as one of the its dependencies:

dependencies {
    ...
    implementation 'commons-codec:commons-codec:1.5'
}

Note the information at the end of the first line of the stack trace above (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar). Instead of loading class org.apache.commons.codec.binary.Base64 from commons-codec:1.5, Android 7.0 is still using a legacy version of that class, which has no method decode(String).

To remove any doubt, I ran a second test. Grabbed the source code for commons-codec:1.5, refactored it so that there would be no conflict with the legacy classes anymore (just renamed org.apache.* to org.apache.android.*), and made my quick app use the refactored version of commons-codec:

dependencies {
    ...
    implementation files('libs/commons-codec-1.5-refactored.jar')
}

Now the app ran with no errors, correctly showing the decoded string.

@reverbel
Copy link

reverbel commented Jan 20, 2018

Apologies for the very long comment above. Some additional thoughts...

This would be an easy way of making java-stellar-jdk work on Android:

  1. Create refactored versions the Apache jars commons-codec, httpclient, and fluent-hc, with packages org.apache.* renamed to org.apache.android.*.
  2. Create a special version of java-stellar-jdk that uses the renamed (org.apache.android.*) Apache packages instead of the original ones.

Of course this "solution" has two big inconveniences. First, the trouble of keeping parallel versions of Apache projects just to circumvent a silly Android-specific name clashing issue. Second, the trouble of having a special version of java-stellar-jdk for Android.

The second inconvenience could be avoided by using dependency injection, so that java-stellar-jdk is
configured at runtime to depend either on org.apache.* packages or on org.apache.android.* packages.

It appears that the ideal solution for running java-stellar-jdk on Android would be to move away from Apache HttpClient and Commons Codec.

@bartekn bartekn mentioned this issue Jan 24, 2018
@bartekn
Copy link
Contributor

bartekn commented Jan 24, 2018

Fix for Android related-issues is now being reviewed: #72

You can check it out but pulling android branch and running ./gradlew jar to build a JAR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants