aws-sdk-android icon indicating copy to clipboard operation
aws-sdk-android copied to clipboard

Unable to connect over IOT for minSDK version 19

Open haransanjay opened this issue 1 year ago • 12 comments

Describe the bug My app is connected to AWS IoT using aws-android-sdk-core and aws-android-sdk-iot. I am using org.eclipse.paho:org.eclipse.paho.client.mqttv3 for the client side. However, when using minSdkVersion lower than 26(in my case it is 19), I get the error message "Could not find class 'javax.net.ssl.SNIHostName', referenced from method org.conscrypt.Platform."

To Reproduce A code sample or steps:

  • set Android minsdkversion to 19 Your code
  • Here is the app gradle file plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id ("kotlin-kapt") id("com.apollographql.apollo3") version "4.0.0-alpha.1" }

android { namespace 'com.eprintitsaas.avision.app' compileSdk 33

defaultConfig {
    applicationId "com.eprintitsaas.avision.app"
    minSdk 19
    targetSdk 29
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    configurations.all {
        resolutionStrategy {
            force 'androidx.preference:preference:1.1.1'
            force 'com.android.support:support-v4:25.1.1'
            exclude group: "com.android.support", module: "support-core-utils"
            exclude group: "com.android.support", module: "support-core-ui"
            exclude group: 'com.google.code.gson', module: 'gson'
        }
    }
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = '1.8'
}
apollo {
    service("service") {
        packageName.set("com.eprintitsaas.avision.app")
    }
}

}

dependencies { implementation(files("libs/commons.jar")) implementation files('libs/WorkpathLib.aar') implementation files('libs/WorkpathLib-javadoc.jar')

implementation project(path: ':aws-android-sdk-core')
implementation project(path: ':aws-android-sdk-iot')

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'


implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")

//firebase
implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")

/*RETROFIT 2.9.0*/
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")

implementation("com.squareup.retrofit2:converter-scalars:2.6.4")

implementation("com.jakewharton:butterknife:10.2.3")
kapt ("com.jakewharton:butterknife-compiler:10.2.3")

implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")



implementation("com.apollographql.apollo3:apollo-runtime:4.0.0-alpha.1")
implementation("com.apollographql.apollo:apollo-coroutines-support:2.5.14")


implementation("com.github.devsideal:VectorChildFinder:1.0.0")
implementation("androidx.multidex:multidex:2.0.1")

implementation ("androidx.appcompat:appcompat:1.6.1")
implementation ("com.google.android.material:material:1.9.0")
implementation ("androidx.constraintlayout:constraintlayout:2.1.4")


implementation ("com.android.support:support-core-utils:28.0.0")


implementation ("com.dropbox.core:dropbox-core-sdk:3.1.5")


implementation ("com.google.code.gson:gson:2.10.1")

implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
implementation ("com.intuit.sdp:sdp-android:1.1.0")
implementation 'org.bouncycastle:bcpkix-jdk15on:1.67'
implementation "org.minidns:minidns-hla:0.3.2"

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'androidx.preference:preference:1.1.1'


implementation 'com.github.bumptech.glide:glide:4.15.1'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'

}

Which AWS service(s) are affected?

  • aws-android-sdk-auth-core
  • aws-android-sdk-auth-iot

Expected behaviour It should be able to connect over iot

Screenshots

Screenshot 2023-10-27 at 4 01 16 PM

Environment Information (please complete the following information):

  • AWS Android SDK Version: [2.73.0]
  • Device: [Nexus 5 API 19]
  • Android Version: [Android kitkat 4.4]
  • Specific to simulators: [No]

Additional context I am encountering an error only after switching to minsdkversion 19 and installing the app on KitKat 4.4 Android OS. I have added AWS SDKs as modules and am also using the latest Eclipse Paho library.

haransanjay avatar Oct 27 '23 10:10 haransanjay

Hello @haransanjay, thanks for reaching out. Can you briefly explain why you're using implementation project(path: ':aws-android-sdk-core') instead of implementation 'com.amazonaws:aws-android-sdk-core:2.73.0' etc.? We'll look into the rest of the issue as well.

tjleing avatar Oct 30 '23 19:10 tjleing

Hello @tjleing, thank you for your response. The implementation was updated to the latest version, which works fine with Android SDK 26. However, there is an issue with Android 19 and this was a legacy implementation I have received.

haransanjay avatar Oct 31 '23 06:10 haransanjay

I tried replicating the issue with minSDK set to 19 and I am able to connect, publish and subscribe messages. Could you share your code snippet ? Also which device are you testing this on?

ankpshah avatar Nov 03 '23 22:11 ankpshah

Hello @ankpshah, Thank you for your response. Below is the MQTTManager class that I am using to establish a connection. Device names: Nexus 5 API 19, Pixel 6 API 19

class MQTTManager {

interface OnSubscribeDone {
    fun onSubscribed()
    fun onReconnect(globalEndPoint: String)

}
companion object {


     lateinit var context: Context

    lateinit var mqttManager: AWSIotMqttManager
    private var keyStorePath = "./"

    lateinit var topic: String
    lateinit var onSubscribeDone: OnSubscribeDone

    fun setContext(con: Context, onSubscribeDone: OnSubscribeDone) {
        context = con
        this.onSubscribeDone = onSubscribeDone
    }

    @Throws(Exception::class)
    fun mqttConnect(
        context: Context,
        globalEndPoint: String,
        certificate: String,
        privateKey: String,
        endPoint: String,
        thingName: String,
        custId: String,
    ) {
        val uniqId = UUID.randomUUID().toString()

        keyStorePath = context.getFilesDir().toString()+ "/"
        val keystoreFileName = "name.bks"
        val keystoreFilePassword = "pass"

        AWSIotKeystoreHelper.createKeystore(keyStorePath,
            keystoreFileName,
            keystoreFilePassword)

        topic = "cmd/+/" + custId + "/+/" + thingName + "/+"
        mqttManager = AWSIotMqttManager(
            thingName,
            endPoint)


        val assetManager = context.assets
        var input: InputStream = privateKey.byteInputStream()
        var size: Int = input.available()
        val buffer = ByteArray(size)
        input.read(buffer)
        input.close()
        val privateKeyPem = String(buffer)

        input = certificate.byteInputStream()
        size = input.available()
        val buffer2 = ByteArray(size)
        input.read(buffer2)
        input.close()
        val clientCertificate = String(buffer2)

        val uniqueId = UUID.randomUUID().toString()

// if (!AWSIotKeystoreHelper.isKeystorePresent(keyStorePath, keystoreFileName)) { AWSIotKeystoreHelper.saveCertificateAndPrivateKey(uniqueId, clientCertificate, privateKeyPem, keyStorePath, keystoreFileName, keystoreFilePassword) // } // retrieve the keystore val keystore: KeyStore = AWSIotKeystoreHelper.getIotKeystore( uniqueId, keyStorePath, keystoreFileName, keystoreFilePassword )

        // wait for connection
        Thread.sleep(3000)
        mqttManager.connectUsingALPN(keystore
        ) { status, throwable ->
            if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Connecting) {
                Utils.showErrorLog("MQTT", "status: Connecting")
            }
            if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Connected) {
                Utils.showErrorLog("MQTT", "status: Connected")
                //Subscribe
                subscribe()

            }
            if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.ConnectionLost) {
                Utils.showErrorLog("MQTT", "status: ConnectionLost")
            }
            if (status == AWSIotMqttClientStatusCallback.AWSIotMqttClientStatus.Reconnecting) {
                Utils.showErrorLog("MQTT", "status: Reconnecting")

                reconnectMQTT(globalEndPoint)

            }
        }

    }

    private fun reconnectMQTT(globalEndPoint: String) {
        Utils.showErrorLog("MQTT", "Reconnect")
        onSubscribeDone.onReconnect(globalEndPoint)
    }

    private fun subscribe() {

        mqttManager.subscribeToTopic(topic,
            AWSIotMqttQos.QOS0,
            object : AWSIotMqttSubscriptionStatusCallback {
                override fun onSuccess() {
                    Utils.showErrorLog("MQTT", "MQTT SUBSCRIBED")

                    onSubscribeDone.onSubscribed()
                }

                override fun onFailure(exception: Throwable) {
                    Utils.showErrorLog("MQTT_FAILURE", exception.toString())
                }
            }, object : AWSIotMqttNewMessageCallback {
                override fun onMessageArrived(topic: String?, data: ByteArray?) {
                    Utils.showErrorLog("MQTT_MSG", topic.toString())
                    Utils.showErrorLog("MQTT_DATA", String(data!!))

                    val json = JSONObject(String(data))
                    if(json.has("kioskToken")){
                        val kioskToken=json.getString("kioskToken")
                        Utils.showErrorLog("KIOSK_TOKEN", kioskToken)

                        if(kioskToken.isNotEmpty()){
                            AppPreferences.saveStringToUserDefaults(context,
                                Constants.PrefKey.REQUEST_KIOSK_TOKEN,
                                kioskToken)
                        }
                    }

                }

            })
    }

    

}

}

haransanjay avatar Nov 06 '23 14:11 haransanjay

Looks like desugaring hasn't been enabled on your project. Should look like this:

android {
    compileOptions {
        // Support for Java 8 features
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

tylerjroach avatar Nov 06 '23 14:11 tylerjroach

@tylerjroach I have added desugaring but still getting the same issue.

Screenshot 2023-11-06 at 8 27 50 PM

haransanjay avatar Nov 06 '23 14:11 haransanjay

Are you sure that you are running AWS SDK for Android 2.73.0?

See https://github.com/eclipse/paho.mqtt.java/issues/633 and https://github.com/eclipse/paho.mqtt.java/pull/666.

This issue came from the Paho library and members on our team previously worked to help resolve this issue, which appears to be fixed in April 2020.

tylerjroach avatar Nov 06 '23 15:11 tylerjroach

Upon further looking, I believe you are missing the conscrypt-android library as referenced in our iot pom: https://repo1.maven.org/maven2/com/amazonaws/aws-android-sdk-iot/2.73.0/aws-android-sdk-iot-2.73.0.pom

Our recommendation is to use our published libraries, rather than adding them directly. By adding directly, you are potentially missing transitive dependencies that are no longer being pulled in.

tylerjroach avatar Nov 06 '23 15:11 tylerjroach

Hi @tylerjroach I will incorporate your suggestions and get back to you with the updated result.

haransanjay avatar Nov 06 '23 17:11 haransanjay

Looks like desugaring hasn't been enabled on your project. Should look like this:

android {
    compileOptions {
        // Support for Java 8 features
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

I tried to use the latest version of coreLibraryDesugaring, but I couldn't update beyond coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.3'.

I am receiving an error while attempting to update to the latest version.

Could not resolve all files for configuration ':app:detachedConfiguration11'. Failed to transform FakeDependency.jar to match attributes {artifactType=_internal-d8-desugar-methods, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}. Execution failed for D8BackportedMethodsGenerator: /Users/sanjaysmacbook/.gradle/android/FakeDependency.jar. Unsupported desugared library configuration version, please upgrade the D8/R8 compiler

Gradle version is : distributionUrl=https://services.gradle.org/distributions/gradle-7.4-bin.zip

Below is the Gradle code for the app.

plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id ("kotlin-kapt") id("com.apollographql.apollo3") version "4.0.0-alpha.1" }

android { namespace 'com.eprintitsaas.avision.app' compileSdk 33

defaultConfig {
    applicationId "com.eprintitsaas.avision.app"
    minSdk 19
    targetSdk 29
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    configurations.all {
        resolutionStrategy {
            force 'androidx.preference:preference:1.1.1'
            force 'com.android.support:support-v4:25.1.1'
            exclude group: "com.android.support", module: "support-core-utils"
            exclude group: "com.android.support", module: "support-core-ui"
            exclude group: 'com.google.code.gson', module: 'gson'
        }
    }
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    coreLibraryDesugaringEnabled true
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = '1.8'
}
apollo {
    service("service") {
        packageName.set("com.eprintitsaas.avision.app")
    }
}

}

dependencies { implementation(files("libs/commons.jar")) implementation files('libs/WorkpathLib.aar') implementation files('libs/WorkpathLib-javadoc.jar')

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'


implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")

implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")


implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")
implementation("com.squareup.retrofit2:converter-scalars:2.6.4")

implementation("com.jakewharton:butterknife:10.2.3")
kapt ("com.jakewharton:butterknife-compiler:10.2.3")


implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")



implementation("com.apollographql.apollo3:apollo-runtime:4.0.0-alpha.1")
implementation("com.apollographql.apollo:apollo-coroutines-support:2.5.14")


implementation("com.github.devsideal:VectorChildFinder:1.0.0")


implementation("androidx.multidex:multidex:2.0.1")

implementation ("androidx.appcompat:appcompat:1.6.1")
implementation ("com.google.android.material:material:1.9.0")
implementation ("androidx.constraintlayout:constraintlayout:2.1.4")


implementation ("com.android.support:support-core-utils:28.0.0")


implementation ("com.dropbox.core:dropbox-core-sdk:3.1.5")


implementation ("com.google.code.gson:gson:2.10.1")

implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
implementation ("com.intuit.sdp:sdp-android:1.1.0")
implementation 'org.bouncycastle:bcpkix-jdk15on:1.67'
implementation "org.minidns:minidns-hla:0.3.2"

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'androidx.preference:preference:1.1.1'


implementation 'com.github.bumptech.glide:glide:4.15.1'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'

implementation 'com.amazonaws:aws-android-sdk-iot:2.73.0'
implementation 'com.amazonaws:aws-android-sdk-core:2.73.0'

coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.3'

}

haransanjay avatar Nov 07 '23 09:11 haransanjay

@tylerjroach @ankpshah I am unable to create a SocketFactory object because Android API level 16 lacks TLS 1.2 support.

haransanjay avatar Nov 07 '23 18:11 haransanjay

Hello, We pushed an update in version 2.69.0 to add TLS 1.2 support on older Android devices wherever possible. If the device does not actually support TLS1.2, we cannot resolve this issue. TLS 1.2 is the minimum TLS protocol level for all AWS API endpoints

ankpshah avatar Feb 27 '24 21:02 ankpshah