OkHttp:<-- HTTP FAILED:java.net.UnknownServiceException:网络安全策略不允许与 10.0.2.2 进行 CLEARTEXT 通信
Posted
技术标签:
【中文标题】OkHttp:<-- HTTP FAILED: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 【发布时间】:2020-05-08 09:55:47 【问题描述】:我已在我的 android 应用中成功实现 使用 Firebase 身份验证的 google 登录。
如您所见,我已使用我的帐户登录,它出现在 Firebase 控制台上。
firebaseAuthWithGoogle 功能在用户使用 Google 登录后通过 Firebase 对用户进行身份验证:
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 用户表通过这段代码sn-p:
//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();
);
);
所以在用户被成功认证之后,对服务器的调用失败了,这行显然被执行了:
Toast.makeText(LoginActivity.this,"Login failed AFTER API CALL",Toast.LENGTH_SHORT).show();
我使用 Retrofit 作为 http 客户端 以及 okhttp 作为 http body 拦截器 来记录 http 请求,如下所示:
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 Text “Login failed AFTER API CALL” 后,我在日志中有这个:
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
所以我发现这是导致错误的原因:
网络安全不允许与 10.0.2.2 进行 CLEARTEXT 通信 政策
通过***后,我发现我需要创建这个文件:
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 项目上。 我认为这应该解决了这个问题。但是,我仍然有完全相同的问题。我仍然在日志中收到此错误:
网络安全不允许与 10.0.2.2 进行 CLEARTEXT 通信 政策
【问题讨论】:
您可以在清单文件的“应用程序”标签中设置“android:usesCleartextTraffic="true"”。如果您的 API/Link 不支持 https 并且您使用的是“Android P”或更高版本,则会出现此问题。 【参考方案1】:在 AndroidManifest.xml 中,只需使用这一行。它解决了我的问题。
<application
...
android:usesCleartextTraffic="true">
</application>
【讨论】:
【参考方案2】:将其用于安全配置文件:
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>
它解决了我的问题:)
【讨论】:
我收到此错误:xml 中的 xml "network_security_config" 在基本 xml 文件夹中没有声明;当在与此限定符不匹配的配置中查询资源时,这可能会导致崩溃以上是关于OkHttp:<-- HTTP FAILED:java.net.UnknownServiceException:网络安全策略不允许与 10.0.2.2 进行 CLEARTEXT 通信的主要内容,如果未能解决你的问题,请参考以下文章
Android应用程序崩溃okhttp3 HTTP FAILED:javax.net.ssl.SSLException:读取错误:系统调用期间I/O错误,软件导致连接中止
OKHTTP - SSLSocket duplex close failed
OKHTTP - SSLSocket duplex close failed