Android Pie:WebView 在某些站点上显示纯 HTTP 错误,即使使用 usesClearTextTraffic=“true”

Android Pie: WebView showing error for plain HTTP on some sites, even with usesClearTextTraffic="true"

提问人:O'Rooney 提问时间:11/14/2018 最后编辑:O'Rooney 更新时间:2/3/2019 访问量:15941

问:

我们的 android 应用程序中有一个 WebView,最终用户可以浏览到他们想要的任何网站。Android Pie 默认禁用纯 HTTP,因此我们在清单中添加了 usesClearTextTraffic=“true”。

这适用于某些网站,但不适用于其他网站,例如 google.com!在不起作用的网站上,我们仍然会得到 net::ERR_CLEARTEXT_NOT_PERMITTED,就好像我们没有设置清单设置一样。

Screenshot of webview HTTP error

我认为它可能与 HSTS 有关,但在这种情况下,我只希望 WebView 立即重定向到 HTTPS。

那么问题来了,为什么Android WebView仍然无法通过纯HTTP浏览某些网站,即使在清单中打开了usesClearTextTraffic?

(PS:我们没有网络安全配置)

我们正在 Google Pixel 1XL 上进行测试。

纯 HTTP 不起作用:

纯HTTP工作:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.umajin.umajinviewer">

    <permission android:name="com.umajin.umajinviewer.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="com.umajin.umajinviewer.permission.C2D_MESSAGE" />

    <application android:label="Umajin Preview"
                 android:icon="@mipmap/ic_launcher"
                 android:theme="@android:style/Theme.NoTitleBar">
        <activity android:name="Umajin"
                  android:label="Umajin Preview"
                  android:configChanges="orientation|screenSize|keyboardHidden"
                  android:screenOrientation="fullSensor"
                  android:icon="@mipmap/ic_launcher"
                  android:largeHeap="true"
                  android:windowSoftInputMode="stateHidden|adjustPan"
                  android:launchMode="singleTask"
                  android:usesCleartextTraffic="true"
                  >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter
                android:priority="1">
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.umajin.umajinviewer" />
            </intent-filter>
        </receiver>
        <service android:name=".MyIntentService" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="<redacted>"/>

        <!-- Specify which class to instantiate for the alarm messages -->
        <receiver android:name="com.umajin.app.AlarmReceiver" >
        </receiver>

        <!-- Use this receiver if you to excute something at boot -->
        <!-- Required if you want alarms to survive a device restart -->
        <receiver
           android:name="com.umajin.umajinviewer.BootReceiver"
           android:enabled="true"
           android:exported="true"
           android:label="BootReceiver">
           <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED" />
           </intent-filter>
        </receiver>
        <!-- end boot receiver -->

        <!-- Add this to play private video files in fullscreen externally through intents. -->
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.umajin.umajinviewer.files"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>
        <!-- Android Pie specific fix for crash on Google Maps. Throws a ClassNotFoundException when it fails to
             find "org.apache.http.ProtocolVersion".
             See https://stackoverflow.com/questions/50782806/android-google-maps-java-lang-noclassdeffounderror-failed-resolution-of-lorg-a -->
        <uses-library android:name="org.apache.http.legacy" android:required="false"/>
    </application>

    <uses-feature android:glEsVersion="0x00020000" /> 
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
    <uses-feature android:name="android.hardware.location" android:required="false" />
    <uses-feature android:name="android.hardware.location.gps" android:required="false" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <!-- WRITE no longer implies READ. By agreement, we always ask 
         for both at a time as the user prompts are identical and it can appear to 
         a user that they have been asked for the same thing twice even though the
         underlying permission asked for may be different. -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!-- FINE and COARSE permissions result in the same prompt being displayed to the
         user. It can appear to the user that they have been asked for the same thing
         twice. By agreement, we always ask for both in one request
         to the user to avoid confusing the user. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.NFC" />
    <!-- Used for Samsung fingerprint scanner. -->
    <uses-permission android:name= "com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>

    <!-- Required for Bluetooth LE -->
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    <!-- Use this permission if you want your applications to launch on startup -->
    <!-- Required if you want alarms to survive a device restart -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <!-- Required for WIFI scanning -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest> 
Android HTTP Web视图

评论

0赞 Ümañg ßürmån 11/16/2018
你能发布你的清单吗?
0赞 O'Rooney 11/20/2018
当然,我已经添加了清单。谢谢
1赞 Ümañg ßürmån 11/20/2018
请查看解决方案

答:

18赞 Ümañg ßürmån 11/20/2018 #1

溶液:

正如我所观察到的,您在标签中使用了。Manifest.xmlandroid:usesCleartextTraffic="true"<activity>

正如您在 Activity 标签的文档中看到的那样,它没有在文档中提供的语法中提供任何此类功能。

正如您在下面的屏幕截图中看到的,明文流量的描述非常简单。

About Clear Text Traffic

此外,如果您查看应用程序标记的文档,您会注意到这是 .android:usesCleartextTrafficApplication Tag

因此,这里唯一需要的解决方法是从活动标记中删除属性,并在应用程序标记中使用它,并且没有 活动标记支持 .android:usesCleartextTraffic

从 Android 9 (Pie) 开始,明文流量默认处于停用状态。

因此,解决方案将是:

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

尝试一下,如果您有任何与此相关的问题,请发表评论。

评论

0赞 O'Rooney 11/21/2018
唯一的谜团是为什么有些网站显然在没有它的情况下工作。也许它们位于 HSTS 列表中,因此在 Web 视图中重定向到 HTTPS。
0赞 Ümañg ßürmån 11/21/2018
@O'鲁尼:是的,无论如何,我很高兴这个答案有所帮助。:)
0赞 Pxaml 6/19/2019
我遵循了所有这些步骤,但我的 webview 在这些设备中仍然是黑色的。任何其他想法
0赞 Pxaml 6/19/2019
你能看一看@stackoverflow.com/questions/56634016/ 吗...