Android 8:不允许明文HTTP流量

1686

我收到来自使用Android 8的用户的报告,称我的应用程序(使用后端提要)无法显示内容。经过调查,我发现在Android 8上发生以下异常:

08-29 12:03:11.246 11285-11285/ E/: [12:03:11.245, main]: Exception: IOException java.io.IOException: Cleartext HTTP traffic to * not permitted
at com.android.okhttp.HttpHandler$CleartextURLFilter.checkURLPermitted(HttpHandler.java:115)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:458)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.doConnection(AbstractHttpAsyncTask.java:207)
at com.deiw.android.generic.tasks.AbstractHttpAsyncTask.extendedDoInBackground(AbstractHttpAsyncTask.java:102)
at com.deiw.android.generic.tasks.AbstractAsyncTask.doInBackground(AbstractAsyncTask.java:88)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

在 Android 7 及以下版本上,一切正常。我没有在 Manifest 中设置 android:usesCleartextTraffic(将其设置为 true 也没有帮助,因为默认值就是这个),也没有使用网络安全信息。如果我调用 NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(),它会返回 false(针对 Android 8),返回 true(针对旧版本),并且仍然使用同一个 apk 文件。 我试图在 Google 上寻找 Android O 相关的信息,但未获得成功。


6
由于服务器在某些情况下将HTTPS重定向到HTTP,导致我维护的应用程序出现了这种情况。 - Big McLargeHuge
请在此处查看:https://codechacha.com/android-cleartext-http-traffic-issue/ - ikmazameti
我正在构建API级别为30的Android 11应用程序,并在清单文件中的应用程序标记中添加android:usesCleartextTraffic="true"。 - masterxilo
据其他地方报道,直到Android 9才会发生这种情况。这对我来说是个新闻。 - undefined
37个回答

16

向您的清单文件添加android:usesCleartextTraffic="true"可能会解决问题,但这会对数据完整性构成威胁。

出于安全原因,我在清单文件中使用了清单占位符android:usesCleartextTraffic(就像已接受答案的选项3中所述,即@Hrishikesh Kadam的回复),以仅允许在调试环境下使用明文。

在我的build.gradle(:app)文件中,我添加了一个类似于以下内容的清单占位符:

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

        debug {
            manifestPlaceholders.cleartextTrafficPermitted ="true"
        }
    }

注意上面这行中的占位符名称cleartextTrafficPermitted
            manifestPlaceholders.cleartextTrafficPermitted ="true"

然后在我的Android清单文件中,我使用了相同的占位符...

AndroidManifest.xml -

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="${cleartextTrafficPermitted}"
        ...>
        ...
    </application>
</manifest>

因此,在调试环境下才允许明文传输。


16

Xamarin Form 的简单且最易实现的解决方案

针对 Android

  1. 进入 Android 项目,然后点击 属性,

enter image description here

  1. 打开 AssemblyInfo.cs 文件,并将以下代码粘贴其中:

    [assembly: Application(UsesCleartextTraffic =true)]

enter image description here

针对 iOS

使用 NSAppTransportSecurity:

Enter image description here

您需要在 info.plist 文件中,在 NSAppTransportSecurity 字典下设置 NSAllowsArbitraryLoads 键为 YES

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

Plist配置


1
这个非常好用,太棒了 @Hemant Ramphul - Raj K
1
绝对棒极了! - Ivan Spajić

13

好的,我已经弄清楚了。这是由于我添加了Manifest参数android:targetSandboxVersion="2"造成的,因为我们还有Instant App版本 - 它应该确保用户从Instant App升级到常规应用程序时不会丢失他的数据。然而,正如模糊的描述所示:

指定此应用程序想要使用的目标沙盒。更高的沙盒版本将具有更高的安全级别。

此属性的默认值为1。

显然它也在Android 8上增加了新的安全策略。


10
我建议同时添加开发和生产环境的网络配置:
添加 res/xml/network_security_config_dev.xml
<?xml version="1.0" encoding="utf-8"?>
 <network-security-config>
    <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain>
 </domain-config>
</network-security-config>

addres/xml/network_security_config_prod.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="false">
    <domain includeSubdomains="true">yourdomain.com</domain>
  </domain-config>
</network-security-config>

在 Android Studio 中的 Gradle 脚本下,找到 build.gradleandroid.app),并查找 buildTypesreleasedebug(如果不存在,则创建):
buildTypes {

release {
    minifyEnabled false
    manifestPlaceholders.securityConfig = "@xml/network_security_config_prod"
 }

 debug {
    manifestPlaceholders.securityConfig = "@xml/network_security_config_dev"
 }

}

在 AndroidManifest.xml 中使用以下 securityConfig 占位符(该占位符在 build.gradle 文件中定义):

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:networkSecurityConfig="${securityConfig}"   <------- here

为什么我首先看到这个答案?没有提到安全问题,什么都没有!我的意思是,人们不能简单地禁用防止中间人攻击、窃听等安全功能。不过你的回答确实解决了 OP 的问题。 - Kaymaz

8

为了将这些答案应用于Xamarin.Android,您可以使用类和程序集级别的属性,而不是手动编辑AndroidManifest.xml

当然需要Internet权限(显然..):

[assembly: UsesPermission(Android.Manifest.Permission.Internet)]

注意:通常情况下,程序集级别的特性被添加到您的AssemblyInfo.cs文件中,但是任何一个在using之下并在namespace之上的文件都可以使用。
接下来,在您的应用程序子类(如果需要,请创建一个)中,您可以添加一个对Resources/xml/ZZZZ.xml文件的引用,并使用NetworkSecurityConfig来配置。
#if DEBUG
[Application(AllowBackup = false, Debuggable = true, NetworkSecurityConfig = "@xml/network_security_config")]
#else
[Application(AllowBackup = true, Debuggable = false, NetworkSecurityConfig = "@xml/network_security_config"))]
#endif
public class App : Application
{
    public App(IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer) : base(javaReference, transfer) { }
    public App() { }

    public override void OnCreate()
    {
        base.OnCreate();
    }
}

Resources/xml 文件夹中创建一个文件(如果需要,创建 xml 文件夹)。
例如: xml/network_security_config 文件,请根据需要进行调整(请参阅其他答案)。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
          <domain includeSubdomains="true">www.example.com</domain>
          <domain includeSubdomains="true">notsecure.com</domain>
          <domain includeSubdomains="false">xxx.xxx.xxx</domain>
    </domain-config>
</network-security-config>

您还可以在应用程序属性上使用 UsesCleartextTraffic 参数:

#if DEBUG
[Application(AllowBackup = false, Debuggable = true, UsesCleartextTraffic = true)]
#else
[Application(AllowBackup = true, Debuggable = false, UsesCleartextTraffic = true))]
#endif

如果您不在域上,而是在本地主机地址为192.168上运行该应用程序,它将无法在互联网上实时发布,而只能在本地网络中使用。 - c-sharp-and-swiftui-devni
Xamarin Forms的语法是什么? - c-sharp-and-swiftui-devni
@rogue39nin 使用我回答的最后一部分:UsesCleartextTraffic = true - SushiHangover

7

对我而言,可行的答案是 @PabloCegarra 提供的这个:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

你可能会收到一个安全警告,涉及cleartextTrafficPermitted="true"

如果你知道需要添加到“白名单”的域名,应该同时使用接受的答案和上面的答案:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">books.google.com</domain>
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </domain-config>
</network-security-config>

这段代码对我来说是有效的,但我的应用程序需要仅从books.google.com检索数据。 这样安全警告就会消失。


6
 cleartext support is disabled by default.Android in 9 and above

 Try This one I hope It will work fine

1 Step:->  add inside android build gradle (Module:App)
            useLibrary 'org.apache.http.legacy'

  android {
               compileSdkVersion 28
              useLibrary 'org.apache.http.legacy'

          }

第二步:->添加清单 在清单中,在应用程序标签中添加。
<application
    android:networkSecurityConfig="@xml/network_security_config">//add drawable goto Step 4

   // Step --->3  add to top this line  
     <uses-library
        android:name="org.apache.http.legacy"
        android:required="false" />

</application>

//步骤4-->> 创建Drawable>>Xml文件>>将其命名为>> network_security_config.xml

   <?xml version="1.0" encoding="utf-8"?>
   <network-security-config>
      <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
           <certificates src="system" />
        </trust-anchors>
      </base-config>
    </network-security-config>

能否在AOSP中更改这个? - Shadow
@Shadow 是的,你可以更改它。 - Ashif
我可以知道具体在哪里更改吗? - Shadow
@Shadow <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">www.yourwebsidedomain.com</domain> </domain-config> - Ashif
不!你又在说应用程序方面了。我问的是如何在框架/<>文件夹类中进行更改? - Shadow

5

在开发应用程序时,我也遇到了"Cleartext HTTP traffic not permitted"错误。 我在应用程序中使用Retrofit2进行网络调用,并且有两个项目环境(dev和production)。 我的生产域具有带有HTTPS调用的SSL证书,而dev则没有https。 配置已添加到构建变体中。 但是,当我切换到dev时,就会触发此问题。 因此,我添加了以下解决方案。

我在清单中添加了cleartext流量。

 android:usesCleartextTraffic="true"

然后我在 Retrofit 配置类中添加了一个连接规范,该规范是在 OKHttp 创建时设置的。

 .connectionSpecs(CollectionsKt.listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT))

下面给出了完整的OkHttpClient创建代码:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .readTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(10, TimeUnit.SECONDS)
        .cache(null)
        .connectionSpecs(CollectionsKt.listOf(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT))
        .addInterceptor(new NetworkInterceptor(context))
        .addInterceptor(createLoggingInterceptor())
        .addInterceptor(createSessionExpiryInterceptor())
        .addInterceptor(createContextHeaderInterceptor())
        .build();

5

2019年12月更新 ionic - 4.7.1

<manifest xmlns:tools=“http://schemas.android.com/tools”>

<application android:usesCleartextTraffic=“true” tools:targetApi=“28”>

请在 AndroidManifest.xml 文件中添加上述内容。 Ionic 的旧版本
  1. Make sure you have the following in your config.xml in Ionic Project:

    <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
                <application android:networkSecurityConfig="@xml/network_security_config" />
                <application android:usesCleartextTraffic="true" />
            </edit-config>
    
  2. Run ionic Cordova build android. It creates Android folder under Platforms

  3. Open Android Studio and open the Android folder present in our project project-platforms-android. Leave it for few minutes so that it builds the gradle

  4. After gradle build is finished we get some errors for including minSdVersion in manifest.xml. Now what we do is just remove <uses-sdk android:minSdkVersion="19" /> from manifest.xml.

    Make sure its removed from both the locations:

    1. app → manifests → AndroidManifest.xml.
    2. CordovaLib → manifests → AndroidManifest.xml.

    Now try to build the gradle again and now it builds successfully

  5. Make sure you have the following in Application tag in App → manifest → Androidmanifest.xml:

    <application
    android:networkSecurityConfig="@xml/network_security_config"  android:usesCleartextTraffic="true" >
    
  6. Open network_security_config (app → res → xml → network_security_config.xml).

    Add the following code:

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config cleartextTrafficPermitted="true">
            <domain includeSubdomains="true">xxx.yyyy.com</domain>
        </domain-config>
    </network-security-config>
    

这里的 xxx.yyyy.com 是您的HTTP API链接。请确保在URL之前不要包含任何Http。

注意:现在使用Android Studio构建应用程序(构建--构建Bundle/APK--构建APK),然后您可以使用该应用程序,它可在Android Pie上正常工作。如果尝试使用ionic Cordova build android构建应用程序,则会覆盖所有这些设置,请确保使用Android Studio构建项目。

如果您安装了任何旧版本的应用程序,请卸载它们并尝试再次安装,否则可能会出现以下错误:

App not Installed


Ionic?Cordova?所以这不是普通的Android构建,而是使用前端技术构建本地应用程序的框架。详情请见:https://ionicframework.com/docs/intro - Weekend
Ionic为您提供在Android应用中的WebView实现,而Cordova则帮助您访问Android原生功能,如麦克风、相机等。 - Gvs Akhil

4
将以下内容放入您的 resources/android/xml/network_security_config.xml 文件中:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

这解决了Cordova / Ionic在Android上出现Failed to load resource: net::ERR_CLEARTEXT_NOT_PERMITTED问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接