Search code examples
androidandroid-gradle-pluginokhttpback4app

Gradle dependency issue with com.squareup.okhttp3 library


I am integrating Back4App into my app and am following the android tutorials step by step and am now in the live-query portion of the tutorial and encountered an issue with duplicate okhttp3 libraries. I am able to build the project successfully, however when attempting to run, I receive compilation error stating

Program type already present: okhttp3.internal.ws.WebSocketReader$FrameCallback

My App level build.gradle is

apply plugin: 'com.android.application'
android {
    compileSdkVersion 27
    defaultConfig {
        applicationId 'my.app.id'

        //multiDexEnabled true

        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"


        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }

    configurations.all {
        // OkHttp 3.5.0+ includes the websockets API, so we need this to prevent a conflict
        //exclude module: 'okhttp-ws'
    }

    packagingOptions {
        exclude 'META-INF/rxjava.properties'
    }
}

dependencies {
    // Google GCM Firebase stuff
    implementation 'com.parse.bolts:bolts-android:1.4.0'
    implementation 'com.google.firebase:firebase-core:16.0.3'

    implementation 'com.google.firebase:firebase-messaging:17.3.0'

    // Back4App library
    implementation 'com.parse:parse-android:1.16.3'


    // Back4App Live Query Client
    // *************************************************** //
    implementation 'com.github.tgio:parse-livequery:1.0.3'
    // *************************************************** //

    // in-app billing
    implementation 'com.android.billingclient:billing:1.1'
    // Arch COmponents ViewModelProviders Library
    implementation "android.arch.lifecycle:extensions:$rootProject.lifecycle_version"
    annotationProcessor "android.arch.persistence.room:compiler:$rootProject.room_version"
    // For Room Dependencies
    implementation "android.arch.persistence.room:runtime:$rootProject.room_version"
    //implementation "android.arch.persistence.room:compiler:$room_version"
    // Room -- Optionales
    implementation "android.arch.persistence.room:rxjava2:$rootProject.room_version"
    // Room Test helpers
    testImplementation "android.arch.persistence.room:testing:$rootProject.room_version"
    implementation 'de.hdodenhof:circleimageview:2.2.0'
    implementation 'com.android.support:design:27.1.1'
    implementation 'com.android.support:support-v4:27.1.1'
    implementation 'com.android.support:support-v13:27.1.1'
    implementation 'com.android.support:cardview-v7:27.1.1'
    implementation 'org.jetbrains:annotations-java5:15.0'
    implementation 'com.android.support:recyclerview-v7:27.1.1'
    implementation 'com.android.support:support-vector-drawable:27.1.1'
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    // AndroidJUnitRunner and JUnit Rules
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
    // Espresso dependencies
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-accessibility:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-web:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso.idling:idling-concurrent:3.0.2'
    // Espresso dependency either "compile" or "androidTestImplementation", depends on app's implementation
    androidTestImplementation 'com.android.support.test.espresso:espresso-idling-resource:3.0.2'
    // Required -- JUnit 4 framework
    testImplementation 'junit:junit:4.12'
    // Optional -- Mockito framework
    testImplementation 'org.mockito:mockito-core:2.15.0'
    androidTestImplementation 'com.android.support:support-annotations:27.1.1'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
}

repositories {
    jcenter()
    google()
    maven {
        url "https://maven.google.com"
    }
}
apply plugin: 'com.google.gms.google-services'

this is the Activity that I am testing

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;

import com.parse.Parse;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.SaveCallback;

import org.json.JSONObject;

import tgio.parselivequery.BaseQuery;
import tgio.parselivequery.LiveQueryClient;
import tgio.parselivequery.LiveQueryEvent;
import tgio.parselivequery.interfaces.OnListener;

public class QueryExample extends AppCompatActivity {

    // Subscription
    final tgio.parselivequery.Subscription sub = new BaseQuery.Builder("message")
            .where("destination", "pokelist")
            .addField("content")
            .build()
            .subscribe();



    // Back4App's Parse setup
    private void initializeParse() {

        Parse.initialize(new Parse.Configuration.Builder(this)
                .applicationId(getResources().getString(R.string.back4app_server_url))
                .clientKey(getResources().getString(R.string.back4app_client_key))
                .server("https://parseapi.back4app.com/")
                .build());

        initLiveQueryClient();
    }

    // Init Live Query Client
    private void initLiveQueryClient() {

        // Example: 'wss://livequerytutorial.back4app.io'
        LiveQueryClient.init("wss://"+"myprototype.back4app.io",
                getResources().getString(R.string.back4app_app_id),
                true);

        LiveQueryClient.connect();
    }

    int numPokes = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_live_query_example);
        EditText pokeText = findViewById(R.id.pokeText);

        initializeParse();

        sub.on(LiveQueryEvent.CREATE, new OnListener() {
            @Override
            public void on(JSONObject object) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        EditText pokeText = findViewById(R.id.pokeText);
                        numPokes++;
                        if(numPokes == 1) {
                            pokeText.setText("Poked " + numPokes + " time.");
                        }
                        else {
                            pokeText.setText("Poked " + numPokes + " times.");
                        }
                    }
                });
            }
        });

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                ParseObject poke = new ParseObject("Message");
                poke.put("content", "poke");
                poke.put("destination", "pokelist");
                poke.saveInBackground(new SaveCallback() {
                    @Override
                    public void done(ParseException e) {
                        Snackbar.make(view, "Poke has been sent!", Snackbar.LENGTH_LONG)
                                .setAction("Action", null).show();
                    }
                });
            }
        });
    }
}

I notice when commenting out

implementation 'com.github.tgio:parse-livequery:1.0.3'

from my app level build.gradle, am able to compile and run the app, however the QueryExample Activity above crashes due to it missing the okhttp3-ws import

I have researched numerous Stack Overflow questions regarding this problem and implemented this solution Here. The reasoning is explained in this Github Forum (deprecation) however, similar to cinder92 comment on Mar 21, 2017 , the problem persists. Has anyone gone through this issue and if so found a solution? My Activity briefly ran until it crashed with error log

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.kungfu.tuga, PID: 25976
                  java.lang.NoClassDefFoundError: Failed resolution of: Lokhttp3/ws/WebSocketListener;
                      at tgio.parselivequery.LiveQueryClient.getNewRequestId(LiveQueryClient.java:128)
                      at tgio.parselivequery.BaseQuery$Builder.<init>(BaseQuery.java:100)
                      at com.kungfu.tuga.utilities.the_wire.QueryExample.<init>(QueryExample.java:27)
                      at java.lang.Class.newInstance(Native Method)
                      at android.app.Instrumentation.newActivity(Instrumentation.java:1174)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
                      at android.app.ActivityThread.-wrap11(Unknown Source:0)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
                      at android.os.Handler.dispatchMessage(Handler.java:106)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
                   Caused by: java.lang.ClassNotFoundException: Didn't find class "okhttp3.ws.WebSocketListener" on path: DexPathList[[zip file "/data/app/com.kungfu.tuga-9jJWU4yht8e1tuYOuZmIQQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.kungfu.tuga-9jJWU4yht8e1tuYOuZmIQQ==/lib/x86, /system/lib, /vendor/lib]]
                      at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
                      at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
                      at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                      at tgio.parselivequery.LiveQueryClient.getNewRequestId(LiveQueryClient.java:128) 
                      at tgio.parselivequery.BaseQuery$Builder.<init>(BaseQuery.java:100) 
                      at com.kungfu.tuga.utilities.the_wire.QueryExample.<init>(QueryExample.java:27) 
                      at java.lang.Class.newInstance(Native Method) 
                      at android.app.Instrumentation.newActivity(Instrumentation.java:1174) 
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669) 
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) 
                      at android.app.ActivityThread.-wrap11(Unknown Source:0) 
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) 
                      at android.os.Handler.dispatchMessage(Handler.java:106) 
                      at android.os.Looper.loop(Looper.java:164) 
                      at android.app.ActivityThread.main(ActivityThread.java:6494) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

Solution

  • Yes, I faced this issue too, however, if you set your gradle like this:

    implementation ('com.parse:parse-android:1.16.3'){
        exclude group: "com.squareup.okhttp3"
    }
    

    It will work without any trouble. (: