Kotlin Multiplatform Mobile - ignore SSL errors

How to ignore any SSL errors in kotlin multiplatform mobile project

Some times mobile developers use a development server with invalid or expired SSL certificate.

In case of use ktor as http client you can ignore SSL errors for development environment in the following way:

Example

build.gradle.kts

kotlin {
    android()
    val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
        if (System.getenv("SDK_NAME")?.contains("simulator") == true)
            ::iosX64
        else
            ::iosArm64

    iOSTarget("ios") {
        binaries {
            framework {
                baseName = "shared"
            }
        }
    }
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt")
                implementation("io.ktor:ktor-client-core:1.3.2-1.4.0-rc")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9-native-mt")
                implementation("io.ktor:ktor-client-android:1.3.2-1.4.0-rc")
                implementation("io.ktor:ktor-client-core-jvm:1.3.2-1.4.0-rc")
            }
        }
        val androidTest by getting
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:1.3.2-1.4.0-rc")
                implementation("io.ktor:ktor-client-core:1.3.2-1.4.0-rc")
            }
        }
        val iosTest by getting
    }
}

Shared

val httpClient = HttpClient(httpEngine()) 

expect fun httpEngine(): HttpClientEngine

Android

import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.engine.android.Android
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.X509TrustManager

actual fun httpEngine(): HttpClientEngine = Android.create {
    sslManager = { conn ->
        val sslContext: SSLContext = SSLContext.getInstance("SSL")
        sslContext.init(null, trustAllCerts, SecureRandom())
        conn.sslSocketFactory = sslContext.socketFactory
        conn.hostnameVerifier = HostnameVerifier { _, _ -> true }
    }
}

private val trustAllCerts: Array<X509TrustManager> = arrayOf(
    object : X509TrustManager {
        @Throws(CertificateException::class)
        override fun checkClientTrusted(
            chain: Array<X509Certificate?>?,
            authType: String?
        ) {}

        @Throws(CertificateException::class)
        override fun checkServerTrusted(
            chain: Array<X509Certificate?>?,
            authType: String?
        ) {}

        override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
    }
)

iOS

import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.engine.ios.Ios
import platform.Foundation.NSURLCredential
import platform.Foundation.NSURLSessionAuthChallengeUseCredential
import platform.Foundation.create
import platform.Foundation.serverTrust

actual fun httpEngine(): HttpClientEngine = Ios.create {
    
    handleChallenge { _, _, challenge, completionHandler ->
        completionHandler(
            NSURLSessionAuthChallengeUseCredential,
            NSURLCredential.create(challenge.protectionSpace.serverTrust)
        )
    }
}

Result

As a result, you can make https requests to the server without a valid SSL certificate.

ATTENTION!: Don’t use this approach in PRODUCTION!