Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.net.UnknownServiceException: CLEARTEXT communication to t.main.wedeep.com.cn not permitted by network security policy

I got above error when i use mockhttpserver to test http request, the following code is how i create service.

   fun <T> getService(clazz: Class<T>): T {
        val client = OkHttpClient.Builder().addInterceptor(HeaderInterceptor()).addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE })
                .build()
        return Retrofit.Builder()
                .baseUrl(mockWebServer.url(""))
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(GSON))
                .build()
                .create(clazz)
    }

This is my Test code.

@UninstallModules(HomePageDataModule::class)
@HiltAndroidTest
class TestHomePageViewModel {


    private lateinit var viewModel: HomePageViewModel

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @Inject
    lateinit var cpd: CompositionDao

    @Inject
    lateinit var csd: CompositionsDao

    @Inject
    lateinit var hpds: HomePageDataSource

    @Inject
    lateinit var ss :HomePageService

    @Before
    fun init() {
        hiltRule.inject()
        viewModel = HomePageViewModel(HomeCompositionsRepository(cpd, csd, hpds, Util.GSON))

    }





    @Test
    fun testObserveHomeData() {

        val data = Util.getFileString("mainpage.json")
        val rr  = GSON.fromJson(data,Array<HomePreviewView>::class.java)
        println(rr)
        enqueueResponse("mainpage.json")
        runBlocking {
            val result = ss.getHomeData()
            Assert.assertNotEquals(rr.size,result.body()!!.size)
        }
}

Everything works smoothly on my app except running my unit test code. There is a similar problem , but my issue has a little difference compare to that one. Plenty of ways from that similar question i have tried, but not work.

PS: If the test code run on Junit4Test but not AndroidJunit4Test, it works properly. But now i need to exectue a integrate test. So this part of code need to be executed on AndroidJunit4Test

like image 866
Cyrus Avatar asked Jul 22 '20 10:07

Cyrus


People also ask

What is cleartext not permitted?

Cleartext is any transmitted or stored information that is not encrypted or meant to be encrypted. When an app communicates with the server using a cleartext network traffic, such as HTTP, it could raise the risk of eavesdropping and tampering of content.

How do I clear HTTP traffic?

Open the AndroidManifest. xml file and under the <application> tag, add the specific line that android:usesCleartextTraffic=”true” enables the HTTP connection, which is disabled by default after the release of Marshmallow. Now run your application.

How do I get a clear text permit?

Resolution. If your application must support loading plain http:// URLs, you can opt into enabling cleartext traffic by using an AndroidManifest. xml file that includes an android:usesCleartextTraffic="true" application attribute.


3 Answers

Solution 1)

Add the following attribute to the <application tag in AndroidManifest.xml:

android:usesCleartextTraffic="true"

Solution 2)

Add android:networkSecurityConfig="@xml/network_security_config" to the <application tag in app/src/main/AndroidManifest.xml:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:theme="@style/AppTheme">

With a corresponding network_security_config.xml in app/src/main/res/xml/:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
like image 180
Quick learner Avatar answered Oct 20 '22 00:10

Quick learner


In my case, I added this to the android manifest file:

android:usesCleartextTraffic="true"

like image 23
saurav singh Avatar answered Oct 19 '22 23:10

saurav singh


Problem finally solved according to @Yuri Schimke prompt.

First step: mockwebserver use https

 val mockWebServer = MockWebServer().apply {
        val localhost: String = InetAddress.getByName("localhost").canonicalHostName
        val localhostCertificate: HeldCertificate = HeldCertificate.Builder().addSubjectAlternativeName(localhost)
                .build()
        val serverCertificates = HandshakeCertificates.Builder()
                .heldCertificate(localhostCertificate)
                .build()
        useHttps(serverCertificates.sslSocketFactory(), false)
    }

Second step: use unsafe okhttp client

  private fun getUnsafeOkHttpClient(): OkHttpClient.Builder? {
        return try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf<TrustManager>(
                    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> {
                            return arrayOf()
                        }


                    }
            )

            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())

            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.getSocketFactory()
            val builder: OkHttpClient.Builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier(HostnameVerifier { hostname, session -> true })
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }

After finished this, you can create your own service as following code.

fun <T> getService(clazz: Class<T>): T {
        val client =getUnsafeOkHttpClient()!!.addInterceptor(HeaderInterceptor())
                .addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE })
                .build()
        return Retrofit.Builder()
                .baseUrl(mockWebServer.url(""))
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(GSON))
                .build()
                .create(clazz)
    }

Hope this is helpful if you have okhttp unit tests on AndroidJunit4

like image 25
Cyrus Avatar answered Oct 19 '22 22:10

Cyrus