You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android9(API28)下Apache Cordova绑定HTTP URL到HTML5 Video标签问题

问题:Cordova Android项目中HTML5 Video无法加载HTTP视频资源
  • 本地绝对/相对路径的视频可正常播放
  • 绑定localhost:8080、本地IPv4+8080地址的视频无法加载
  • 绑定外部HTTP视频地址(如http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4)也无法加载

现有代码配置

sample_basic.html

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: https://ssl.gstatic.com http://192.168.1.142:8080 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="../css/index.css">
<title>Hello World</title>
<script src="../js/cordova.js"></script>
<script src="../js/jquery-3.7.1.min.js"></script>
<script src="../js/sample_basic.js"></script>
<style>
.first {
    margin-left: 5%;
    margin-top: 33%;
    margin-bottom: 5%;
    width: 100vw;
    height: 25vw;
}

.first h1 {
    margin-bottom: 10%;
    width: 90vw;
    text-align: center;
}

.first textarea {
    width: 90vw;
    text-align: left;
    height: 17vw;
    padding-left: -50px;
}

.second {
    width: 100vw;
    height: 50vw;
    text-align; center;
    margin-top: 15%;
    margin-bottom: 10%;
}

.second video {
    width: 90vw;
    height: 50vw;
    margin-left: 5%;
    margin-top: 5%;
}

.third {
    width: 90vw;
    height: 25vw;
    text-align: center;
    margin-left: 5%;
    display: none;
}

.third textarea {
    width: 90vw;
    text-align: left;
    height: 12vw;
    padding-left: -50px;
    margin-top: 5%;
}

.fourth {
    width: 90vw;
    height: 25vw;
    text-align: center;
    margin-left: 5%;
    display: none;
}

.fourth button {
    width: 30vw;
    height: 10vw;
    text-align: center;
    color: white;
    background-color: blue;
}
</style>
</head>
<body>
<div>
    <div class="first">
        <h1>Intro VOD</h1>
        <textarea readonly>
* Your new VOD viewing for 2024 has been uploaded.
* Please watch the video below.
* If you don't finish watching it, you will not be able to move to the next page.
        </textarea>
    </div>
    <div class="second">
        <video id="myVideo" controls>
            <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
        </video>
    </div>
    <div class="third">
        <textarea readonly>
* You've finished watching VOD.
* I'll save the record of your viewing results.
        </textarea>
    </div>
    <div class="fourth">
        <button id="vodYes">
            YES
        </button>
    </div>
</div>
</body>
</html>

AndroidManifest.xml

<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:tools="http://schemas.android.com/tools"
    android:hardwareAccelerated="true" android:versionCode="10000" android:versionName="1.0.0" package="io.cordova.hellocordova" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:usesCleartextTraffic="false" android:networkSecurityConfig="@xml/network_security_config">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="org.apache.http.legacy"/>
    </application>
    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />

</manifest>

network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2:8080</domain>
        <domain includeSubdomains="true">192.168.1.142:8080</domain>
        <domain includeSubdomains="true">localhost:8080</domain>
        <domain includeSubdomains="true">10.0.2.2</domain>
        <domain includeSubdomains="true">192.168.1.142</domain>
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>

MainActivity.java

/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
 */

package io.cordova.hellocordova;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;

import org.apache.cordova.CordovaActivity;

public class MainActivity extends CordovaActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // enable Cordova apps to be started in the background
        Bundle extras = getIntent().getExtras();
        if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
            moveTaskToBack(true);
        }

        // Temporal Setting
        launchUrl = "file:///android_asset/www/html/sample_basic.html";

        // Check paths
        String getDirectory = Environment.getExternalStorageDirectory() + "/Android/data";
        Log.i(getDirectory, "Directory: " + getDirectory); // /storage/emulated/0/Android/data

        // Set by <content src="index.html" /> in config.xml
        loadUrl(launchUrl);
    }
}

sample_basic.js

var watchTime = 0;
$(document).ready(function() {
    // initialization
    var video = $("#myVideo")[0];

    // Real-time viewer's viewing time record
    $(video).on('timeupdate', function() {
        watchTime = video.currentTime;
    });

    // Prevent viewers from manipulating the playback button slider backwards
    $(video).on('seeking', function(event) {
        // Move playback time to viewing time if slider is manipulated backwards
        if (watchTime < video.currentTime) {
            alert('A slider operation has been detected.\nAfter a while, play back from the previous viewing point.');
            video.currentTime = watchTime;
            video.play();
        }
    });

    // Processing events that occur when a video is played
    $(video).on('ended', function(event) {
        // Processed by comparing the maximum length of the video to the viewer's viewing time
        if (video.currentTime === video.duration) {
            // the content to be processed when the maximum length of the video matches the viewer's viewing time
            console.log("You have finished watching the video.");
            alert("You have finished watching the video.");
            $('.third').show();
            $('.fourth').show();
        }
    });
});

问题排查与解决方案

1. 网络安全配置问题

  • 问题点:AndroidManifest.xml中android:usesCleartextTraffic="false"全局禁用了明文HTTP流量,而network_security_config.xml仅添加了本地服务器域名,未包含外部HTTP视频的域名(如clips.vorwaerts-gmbh.de)。
  • 修复:
    • 若需允许所有HTTP明文流量,将AndroidManifest.xml中android:usesCleartextTraffic改为true;
    • 若仅允许指定域名,在network_security_config.xml的domain-config中添加外部视频域名:
      <domain includeSubdomains="true">clips.vorwaerts-gmbh.de</domain>
      

2. Content-Security-Policy(CSP)配置

  • 问题点:当前CSP的default-src未包含外部HTTP视频的域名,尽管media-src设为*,但部分Android WebView可能仍受default-src限制。
  • 修复:将外部视频域名添加到default-src中,或确保media-src规则生效:
    <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: https://ssl.gstatic.com http://192.168.1.142:8080 http://clips.vorwaerts-gmbh.de 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
    

3. Cordova导航白名单

  • 问题点:Cordova默认限制页面导航和资源加载,需在config.xml中添加允许访问的域名。
  • 修复:在项目根目录的config.xml中添加:
    <allow-navigation href="http://*/*" />
    <allow-navigation href="https://*/*" />
    <!-- 或更严格的指定域名 -->
    <allow-navigation href="http://clips.vorwaerts-gmbh.de/*" />
    <allow-navigation href="http://192.168.1.142:8080/*" />
    

4. 本地服务器连接问题

  • 问题点:模拟器访问本地localhost:8080需使用10.0.2.2:8080(Android模拟器的本地映射地址),真机需确保与服务器在同一局域网且服务器允许外部访问。
  • 修复:
    • 模拟器中使用http://10.0.2.2:8080/xxx.mp4;
    • 真机测试时,确认服务器防火墙开放8080端口,且设备与服务器在同一WiFi下。

内容的提问来源于stack exchange,提问作者Jinwoo Jeon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 15:29:51