我收到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)

(我删除了包名、URL和其他可能的标识符)

在Android 7和更低版本上,一切都正常,我没有在Manifest中设置Android:usesCleartextTraffic(并且将其设置为true没有帮助,这是默认值),也没有使用网络安全信息。如果我调用NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(),它将使用相同的apk文件,为Android 8返回false,为旧版本返回true。我试图在谷歌关于Android O的信息中找到一些关于这一点的信息,但没有成功。


当前回答

它可能对某人有用。

我们最近在Android 9上遇到了同样的问题,但我们只需要在WebView中显示一些Url,没有什么特别的。因此,将android:usesCleartextTraffic=“true”添加到Manifest中是有效的,但我们不想因此而危及整个应用程序的安全性。因此,修复方法是将链接从http更改为https

其他回答

在AndroidManifest中,我找到了这个参数:

android:networkSecurityConfig="@xml/network_security_config"

而@xml/network_security_config在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="false"/>
</network-security-config>  

只是我将cleartextTrafficPermitted更改为true

好吧,我已经想通了。这是由于我添加了Manifest参数android:targetSandboxVersion=“2”,因为我们也有即时应用程序版本-它应该确保用户从即时应用程序升级到常规应用程序后,不会在传输过程中丢失数据。然而,模糊的描述表明:

指定此应用程序要使用的目标沙盒。更高的sanbox版本将具有更高的安全级别。此属性的默认值为1。

显然,它还增加了新级别的安全策略,至少在Android 8上如此。

如果可能,请将url从HTTP更改为HTTPS;

成功了!!!

创建文件-res/xml/network_security.xml

在network_security.xml->中

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

打开AndroidManifests.xml:

 android:usesCleartextTraffic="true" //Add this line in your manifests

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/AppTheme">

我们面临着一个非常相似的问题,弄清楚这个问题很痛苦。对于那些不幸的灵魂,他们将不得不面对这一切,下面是我们所做的:

ionic应用程序在浏览器(Chrome和Firefox)中运行良好,部署到苹果的应用商店,并与AWS上的API进行了良好的通信。然后我们开始了Android版本。在模拟器中,我们的https API请求甚至不会被发送出去。在物理设备上,https请求也不会发送(在部署到Google Play上的“内部测试”后)

在模拟器中运行我们的应用程序打开铬,键入“chrome://inspect“,等待,单击到仿真器实例的链接,并能够查看网络选项卡。请求将快速从(挂起)循环到(取消),而不会发送到服务器。

看了一遍stackoverflow,主要建议是使用cleartextPermitted workournd禁用https,这是一个糟糕的想法。

另一个常见的建议是使用原生http,但如果我们必须有两个代码库,那么使用ionic有什么意义,我想保留我的http拦截器。

添加了network_security_config.xml文件(这可能不是严格必要的,但它删除了Android Studio中的编译警告。)

单击浏览器中的锁定图标,检查服务器上的SSL证书。看起来不错。(也许是因为它真的不是,但我有一个手动超控,我很久以前就添加了,现在已经忘记了)。还有很多其他的追尾…

最后使用sslshopper的工具验证了我们的SSL证书:https://www.sslshopper.com/ssl-checker.html

事实证明,虽然我们的证书是好的,但证书链不是。这将在诊断中显示为红色虚线箭头。

基本上,您必须获取您的SSL证书并创建一个捆绑包,方法是附加提供证书的组织的SSL证书,并附加任何其他SSL证书来认证认证者,直到整个链干净为止。我们使用了一个提供的捆绑包,但它并没有充分地通过链条。

修复SSL链:

cat your-purchased-cert-site-com.crt > your-site.bundle.crt
cat other-org-cert-sectigoRSA-bla-bla-bla.crt >> your-site.bundle.crt
cat another-org-cert-USERTrust-bla-bla-bla.crt >> your-site.bundle.crt
cat some-final-high-level-org-cert.crt >> your-site.bundle.crt

然后,在我们的例子中,对于ubuntu上的nginx:

将你的-site.bundle.crt放在可以使用的地方。(在我们的例子中,是/var/ssl)

update /etc/nginx/sites-available/site-name.conf:
ssl_certificate /var/ssl/your-site.bundle.crt
ssl_certificate /var/ssl/your-private-key.key

然后重新启动web服务器(在我们的例子中是nginx:sudo-systemctl-restart nginx)

用sslshopper的检查器检查,你应该可以看到绿色箭头。

启动了模拟器,API调用就完成了。