OkHttp:<-- HTTP 失败:java.net.UnknownServiceException:网络安全策略不允许与 10.0.2.2 的 CLEARTEXT 通信 [英] OkHttp: <-- HTTP FAILED: java.net.UnknownServiceException: CLEARTEXT communication to 10.0.2.2 not permitted by network security policy

查看:59
本文介绍了OkHttp:<-- HTTP 失败:java.net.UnknownServiceException:网络安全策略不允许与 10.0.2.2 的 CLEARTEXT 通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已在我的 Android 应用中成功实现了使用 Firebase 身份验证的 Google 登录.

I have implemented google sign-in with Firebase authentication in my Android app succesfully.

如您所见,我已使用我的帐户登录并显示在 Firebase 控制台上.

As you see, I have logged-in with my account and it appears on the Firebase console.

函数 firebaseAuthWithGoogle 在用户使用 Google Sign-in 登录后使用 Firebase 进行身份验证:

The function firebaseAuthWithGoogle authenticates the user with Firebase after he logs-in with Google Sign-in:

private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
    Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mFirebaseAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCredential:success");
                    final FirebaseUser user = mFirebaseAuth.getCurrentUser();


                    //This is to connect to the http server and save the user data in my MySql database
                    FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(LoginActivity.this, new OnSuccessListener<InstanceIdResult>() {
                        @Override
                        public void onSuccess(InstanceIdResult instanceIdResult) {
                            String userToken = instanceIdResult.getToken();
                            String uid = user.getUid();
                            String name = user.getDisplayName();
                            String email = user.getEmail();
                            String profileUrl = user.getPhotoUrl().toString();
                            String coverUrl = "";
                            UserInterface userInterface = ApiClient.getApiClient().create(UserInterface.class);
                            Call<Integer> call = userInterface.signin(new LoginActivity.UserInfo(uid,name,email,profileUrl,coverUrl,userToken));

                            call.enqueue(new Callback<Integer>() {
                                @Override
                                public void onResponse(Call<Integer> call, Response<Integer> response) {
                                    progressDialog.dismiss();
                                    Toast.makeText(LoginActivity.this,"Login succesfull AFTER API CALL",Toast.LENGTH_SHORT).show();
                                    startActivity(new Intent(LoginActivity.this,MainActivity.class));
                                    finish();

                                }

                                @Override
                                public void onFailure(Call<Integer> call, Throwable t) {
                                    progressDialog.dismiss();
                                    Toast.makeText(LoginActivity.this,"Login failed AFTER API CALL",Toast.LENGTH_SHORT).show();

                                }
                            });
                        }
                    });
                } else {
                    // If sign in fails, display a message to the user.


                 Log.w(TAG, "signInWithCredential:failure", task.getException());
                    }

                    // ...
                }
            });
}

函数 firebaseAuthWithGoogle 的另一件事是:连接到 http Apache 服务器并将用户信息保存在 MySQL 用户表 通过这个代码片段:

Another thing the function firebaseAuthWithGoogle does is: Connect to the http Apache server and save the user information in a MySQL users table through this code snippet:

 //This is to connect to the http server and save the user data in my MySql database
                        FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(LoginActivity.this, new OnSuccessListener<InstanceIdResult>() {
                            @Override
                            public void onSuccess(InstanceIdResult instanceIdResult) {
                                String userToken = instanceIdResult.getToken();
                                String uid = user.getUid();
                                String name = user.getDisplayName();
                                String email = user.getEmail();
                                String profileUrl = user.getPhotoUrl().toString();
                                String coverUrl = "";
                                UserInterface userInterface = ApiClient.getApiClient().create(UserInterface.class);
                                Call<Integer> call = userInterface.signin(new LoginActivity.UserInfo(uid,name,email,profileUrl,coverUrl,userToken));

                                call.enqueue(new Callback<Integer>() {
                                    @Override
                                    public void onResponse(Call<Integer> call, Response<Integer> response) {
                                        progressDialog.dismiss();
                                        Toast.makeText(LoginActivity.this,"Login succesfull AFTER API CALL",Toast.LENGTH_SHORT).show();
                                        startActivity(new Intent(LoginActivity.this,MainActivity.class));
                                        finish();

                                    }

                                    @Override
                                    public void onFailure(Call<Integer> call, Throwable t) {
                                        progressDialog.dismiss();
                                        Toast.makeText(LoginActivity.this,"Login failed AFTER API CALL",Toast.LENGTH_SHORT).show();

                                    }
                                });
                            }
                        });
                    } 

所以在用户成功通过身份验证之后,对服务器的调用失败了,这行代码显然被执行了:

So after the user has been succesfully authenticated, the call to the server fails and this line is obviously executed:

 Toast.makeText(LoginActivity.this,"Login failed AFTER API CALL",Toast.LENGTH_SHORT).show();  

我使用 Retrofit 作为 http 客户端以及 okhttp 作为 http主体拦截器记录http请求如下:

I am using Retrofit as an http client along with okhttp as an http body interceptor to log the http requests as follows:

ApiClient.java

ApiClient.java

  public  static  Retrofit getApiClient(){
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(httpLoggingInterceptor)
                .build();

        if(retrofit==null){
            retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                    .client(httpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

        }
        return retrofit;
    }
}

所以在 Toast 文本 Login failed AFTER API CALL" 出现在模拟器上之后,我在日志上有这个:

So after the Toast Text "Login failed AFTER API CALL" appears on the emulator, I have this on the log:

D/OkHttp: --> POST http://10.0.2.2/friendster/public/app/login
    Content-Type: application/json; charset=UTF-8
    Content-Length: 413
D/OkHttp: {"CoverUrl":"","email":"MyEmail@gmail.com","name":"Ahmed Ghrib","profileUrl":"https://lh6.googleusercontent.com/-S8l_5gZaXJ8/AAAAAAI/AAAAAAAAAAA/ACHi3rfObo6-Ta-wxrMUvcAZ8Yg/s96-c/photo.jpg","uid":"YACACYYDcGVr26N8OHuTuQlQqvU2","userToken":"ecxdtFaKldI:APA91bHb1PAA5hU6i1oMqnSsDXXkAaXNb6dynyaYmhU_soHTWmLXud6REjCpqTjsGpgdBh1NMYUqAr3SaTUWapN4v73zkvyYD2f3yegUP3H38eeU_JtH7NOSMKbF4U"}
D/OkHttp: --> END POST (413-byte body)
W/e.myapplicatio: Verification of okhttp3.internal.http.ExchangeCodec okhttp3.internal.connection.RealConnection.newCodec$okhttp(okhttp3.OkHttpClient, okhttp3.Interceptor$Chain) took 134.353ms
D/OkHttp: <-- HTTP FAILED: java.net.UnknownServiceException: CLEARTEXT communication to 10.0.2.2 not permitted by network security policy  

所以我发现这是导致错误的原因:

So I found-out that this is causing the error:

网络安全不允许与 10.0.2.2 的 CLEARTEXT 通信政策

CLEARTEXT communication to 10.0.2.2 not permitted by network security policy

在通过 StackOverflow 之后,我发现我需要创建这个文件:

After going through StackOverflow, I found-out that I needed to create this file:

src/main/res/xml/network_security_config.xml

src/main/res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">api.example.com(to be adjusted)</domain>
    </domain-config>
</network-security-config> 

并将其添加到清单中:

 <application
     ---
        android:networkSecurityConfig="@xml/network_security_config">  

使用 Postman 测试了我的数据库后,我确定问题出在我的 Android 项目中.
我认为这应该已经解决了这个问题.但是,我仍然有完全相同的问题.我仍然在日志中收到此错误:

Having tested my database with Postman, I am sure the problem lies in my Android project.
I thought that this should've solved the issue. But, I still have the exact same issue. I still get this error in the log:

网络安全不允许与 10.0.2.2 的 CLEARTEXT 通信政策

CLEARTEXT communication to 10.0.2.2 not permitted by network security policy

推荐答案

将其用于安全配置文件:

Use this instead for the security configuration file:

src/main/res/xml/network_security_config.xml

src/main/res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!--Set application-wide security config using base-config tag.-->
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>  

它解决了我的问题:)

这篇关于OkHttp:&lt;-- HTTP 失败:java.net.UnknownServiceException:网络安全策略不允许与 10.0.2.2 的 CLEARTEXT 通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆