如何在 Picasso 上启用 TLS v 1.2 以在 Kotlin 中使用 https 加载图像

Posted

技术标签:

【中文标题】如何在 Picasso 上启用 TLS v 1.2 以在 Kotlin 中使用 https 加载图像【英文标题】:How can i enable TLS v 1.2 on Picasso for loading images with https in Kotlin 【发布时间】:2020-11-08 18:40:32 【问题描述】:

根据我对堆栈的研究,我已经在 Kotlin 中实现了一个解决方案

我创建了一个自定义 Kotlin 类,它实现了 SSLSocketFactory 类,还添加了用于将该类传递给加载我的图像的活动的代码。我的代码编译成功,因为没有交配错误,但很难从添加的链接加载我的图像。

这是自定义类 Tls12SocketFactory.kt

    import java.io.IOException
    import java.net.Socket
    import javax.net.ssl.SSLSocket
    import javax.net.ssl.SSLSocketFactory`

    
class Tls12SocketFactory (
    private val delegate : SSLSocketFactory //constructor..u need to pass an instance of SSL Socket factory
) : SSLSocketFactory() 

    private val protocols = arrayOf("TLSv1.1","TLSv1.2") //array of two version of TLS

    override fun getDefaultCipherSuites(): Array<String> = delegate.defaultCipherSuites //return an array of strings
    //a variable of defaultCipherSuites returns an array of strings

    override fun getSupportedCipherSuites(): Array<String> = delegate.supportedCipherSuites //return an array of strings

    //four parameterss..it uses it to create socket..no return value..for creating sockets
    override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean) =
        enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose))

    //another socket no return typ..assign
    override fun createSocket(host: String, port: Int) =
        enableTLSOnSocket(delegate.createSocket(host, port))

    //no return type..reduces code by eliminating brace = inplace of 
    override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int) =
        enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort))

    //no return type
    override fun createSocket(host: InetAddress, port: Int) =
        enableTLSOnSocket(delegate.createSocket(host, port))

    //no return type
    override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int) =
        enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort))

    //a nullable parameter and no return type for it not to be null socket!.apply
    private fun enableTLSOnSocket(socket: Socket?) = socket?.apply 
        //if the socket is an instance of SSLSocket
        if (this is SSLSocket && isTLSServerEnabled(this)) 
            enabledProtocols = protocols
        
    



    private fun isTLSServerEnabled(sslSocket: SSLSocket) = sslSocket.supportedProtocols.any  it in protocols 

    

我还在我的主要活动类中创建了两个函数

第一个函数是provideX509TrustManager,它返回下面的X509TrustManager

 private fun provideX509TrustManager(): X509TrustManager? 
    try 
        //its a staic class calling the getInstance method which takes a params of DefaultAlgorithm
        val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
        //this is casting null as Keystore
        factory.init(null as KeyStore?)
        //referencing a variable inside TrustManagerFactory
        val trustManagers = factory.trustManagers
        //returns the first element in trustManager and cast as X509TrustManager
        return trustManagers[0] as X509TrustManager
     catch (exception: NoSuchAlgorithmException) 
        Log.e(javaClass.simpleName, "not trust manager available", exception)
     catch (exception: KeyStoreException) 
        Log.e(javaClass.simpleName, "not trust manager available", exception)
    
    return null

另一个函数是finalConvert,它返回一个OkHttpClient对象,也传递了我上面声明的方法

//returns OKHttpClient
fun finalConvert() : OkHttpClient 
    //gets an sslcontext

    val sslContext: SSLContext = SSLContext.getInstance("TLSv1.2")


    sslContext.init(null, null, null)
    val noSSLv3Factory: SSLSocketFactory

    noSSLv3Factory = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 
        Tls12SocketFactory(sslContext.socketFactory)
     else 
        sslContext.socketFactory
    

           //OkHttpClient is built
   val okb = OkHttpClient.Builder()

        .sslSocketFactory(noSSLv3Factory, provideX509TrustManager()!!)

    return okb.build();

最后,在我的 onCreate 中,我将方法传递给了在 Picasso 对象上调用的下载器方法,如下所示

try 
        val p = Picasso.Builder(this)
            .downloader(OkHttp3Downloader(finalConvert()))
            .build()

        p.load(
            "https://sdo.gsfc.nasa.gov/assets/img/latest/latest_2048_HMIIC.jpg")
            .fit().centerCrop()
           .placeholder(android.R.drawable.sym_contact_card)
            .error(android.R.drawable.sym_def_app_icon)
            .into(img_pics)
     catch (e: Exception) 
        Toast.makeText(this," error as a result of " + e.localizedMessage,Toast.LENGTH_LONG).show()
    

这是我的 build.graddle 文件。我不知道我做错了什么

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android 
    compileSdkVersion 29
    buildToolsVersion "30.0.0"

    defaultConfig 
        applicationId "com.gitapp.tlsimageloader"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    

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



dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    //implementation 'com.squareup.picasso:picasso:2.71828'
    //implementation 'com.squareup.picasso:picasso:2.4.0'
    implementation 'com.squareup.okhttp3:okhttp:3.10.0'
    implementation 'com.squareup.picasso:picasso:2.5.2'
    implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
    implementation 'androidx.core:core-ktx:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    //implementation 'com.squareup.okhttp3:okhttp:4.7.2'

    implementation 'com.github.bumptech.glide:glide:4.11.0'
    // Glide v4 uses this new annotation processor -- see https://bumptech.github.io/glide/doc/generatedapi.html
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
    testImplementation 'com.squareup.okhttp3:mockwebserver:4.7.2'

完整代码here

【问题讨论】:

【参考方案1】:

OkHttp 会自动为您执行此操作。只需升级到 3.12.12 或 4.8.0 并删除大部分代码。

https://github.com/square/okhttp/blob/okhttp_3.12.x/okhttp/src/main/java/okhttp3/internal/platform/AndroidPlatform.java#L442-L465

【讨论】:

我做了升级...从答案似乎没有变化,因为图像还没有加载..你能提供更多上下文 Yuri 请你指出我需要删除的代码 Tls12SocketFactory,提供X509TrustManager。只需调用 OkHttpClient()

以上是关于如何在 Picasso 上启用 TLS v 1.2 以在 Kotlin 中使用 https 加载图像的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 应用程序中启用 TLS 1.2 支持(在 Android 4.1 JB 上运行)

如何在 Nginx 中启用 TLS 1.2?

如何在Android应用程序中启用TLS 1.2支持(在Android 4.1 JB上运行)

.NET 4.5.1 中的 WCF 客户端:使用 WebRequest 时如何启用 TLS 1.2?

如何在 Java 7 中启用 TLS 1.2

如何在 IBM java 1.6 中启用 TLS 1.2?