【问题标题】:html5 video does not play in android webview, but works in (mobile) chromehtml5 视频不能在 android webview 中播放,但可以在(移动)chrome 中播放
【发布时间】:2013-11-04 12:51:00
【问题描述】:

我有一个(客户)网站,它使用 js brightcove player 来呈现 html5 视频。 (阅读:我无法编辑网站本身)

在移动 Chrome 中,视频可以正常工作,一切都很好。但是在我的 Android 应用程序中,使用呈现完全相同页面的 WebView 无法播放视频。

我已经阅读了许多类似的 SO 问题,并确保已完成以下操作:

  • 关闭网络视图插件(关闭 Flash),以确保使用的是 html5 视频而不是 Flash 版本。
  • javascript 显然已启用
  • web 视图上安装了 webchromeclient。
  • 覆盖 webchromeclient 中的 onShowCustomView(不幸的是,它从未被调用)
  • 已为 Activity 开启硬件加速

有些帖子建议手动调用视频的play()方法,这不是一个好主意,但是无论如何也不可能,因为brightcove播放器的视频标签在一个iframe中并且没有通过javascript获取它的方法。

现在我已经没有什么想法了,问题可能出在什么地方或地方。任何建议都非常感谢。 LogCat 中唯一相关的日志消息是:

10-25 14:01:01.503: D/VideoLayerManager(1307): Reinit GLResource for VideoLayer

我的 WEBVIEW 设置

课程内容可以从这里 goo.gl/GVtgD0 下载。

    webView = (WebView)findViewById(R.id.webView);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.getSettings().setAllowFileAccess(true);
            webView.setSoundEffectsEnabled(true);
            webView.setWebChromeClient(new WebChromeClient());
            webView.loadUrl("file:///emulated/0/GA_nHanceK12/temp/class1-sub1-top2/index.html"));

我身边的日志

07-16 14:44:11.787: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.787: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.787: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.797: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.797: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.797: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.807: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.807: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.817: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.817: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.817: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.817: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.827: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.827: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.837: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.837: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.837: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.847: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.847: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.847: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.857: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.857: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.857: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.857: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.857: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.867: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.867: D/MediaPlayer_Java(27539): [FXN.ASD] setDataSource :: uri = file:////storage/emulated/0/GA_nHanceK12/temp/class1-sub1-top2/_cp_n_m_
07-16 14:44:11.867: E/MediaPlayer-JNI(27539): [FXN][ASD]getVideoSurfaceTexture: null surface texture
07-16 14:44:11.867: E/MediaPlayer(27539): error (1, -2147483648)
07-16 14:44:11.917: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.917: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.917: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.917: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.927: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.927: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.927: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.927: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.927: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:11.937: E/MediaPlayer_Java(27539): Error (1,-2147483648)
07-16 14:44:12.488: D/VideoLayerManager(27539): Reinit GLResource for VideoLayer

【问题讨论】:

  • Brightcove 播放器在此自定义 WebView 中工作,它实现了您上面列出的内容。如果您的播放器使用此功能,您可能能够缩小您所缺少的范围。 code.google.com/p/html5webview
  • 谢谢,我试试看
  • 你解决了吗?
  • 您应该设置一个示例网站,人们可以点击它来尝试一下。 WebViews 和视频不能相处——尤其是当你把 javascript 混在一起的时候。我仍在寻找一种在所有 Android 版本中使用 JavaScript 播放视频的可靠方法。
  • 能听视频黑屏吗?

标签: javascript android webview html5-video brightcove


【解决方案1】:

This answer 可能会回答您的问题。

我尝试过使用 API 16 (4.1 JB),但这个 sample Brightcove video 仅在全屏时播放。

您可以在全屏模式下强制启动视频,并在用户要求或视频结束时退出。

我相信这是由 WebView 类本身引起的,因为 4.1 JellyBean 是从普通的 Android 浏览器到 Google Chrome 的过渡。虽然较新的 4.1 版本的默认浏览器变成了 Chrome,但 WebViews 仍在使用旧引擎,因此无法正确呈现视频。

另一种解决方案是重定向用户并强制他使用他的浏览器(如果幸运的话,它是 chrome 并且会显示视频)。

【讨论】:

  • 我尝试在 chrome webbrowser 中运行,课程内容播放良好。有人还建议全屏播放视频。实际上我也尝试过(通过在活动标签android:theme="@android:style/Theme.Holo.Light.NoActionBar.Fullscreen" 中执行此操作)但没有运气
【解决方案2】:

我致力于在 android 中播放 html5 视频,这对我有用:

我的活动

public class Test extends Activity {

    HTML5WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mWebView = new HTML5WebView(this);

        if (savedInstanceState != null) {
            mWebView.restoreState(savedInstanceState);
        } else {    
            mWebView.loadUrl("http://player.vimeo.com/video/27244727");
        }

        setContentView(mWebView.getLayout());
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mWebView.saveState(outState);
    }

    @Override
    public void onStop() {
        super.onStop();
        mWebView.stopLoading();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (mWebView.inCustomView()) {
                mWebView.hideCustomView();
            //  mWebView.goBack();
                //mWebView.goBack();
                return true;
            }

        }
        return super.onKeyDown(keyCode, event);
    }
}

我的自定义网页视图

public class HTML5WebView extends WebView {

    private Context                             mContext;
    private MyWebChromeClient                   mWebChromeClient;
    private View                                mCustomView;
    private FrameLayout                         mCustomViewContainer;
    private WebChromeClient.CustomViewCallback  mCustomViewCallback;

    private FrameLayout                         mContentView;
    private FrameLayout                         mBrowserFrameLayout;
    private FrameLayout                         mLayout;

    static final String LOGTAG = "HTML5WebView";

    private void init(Context context) {
        mContext = context;     
        Activity a = (Activity) mContext;

        mLayout = new FrameLayout(context);

        mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(a).inflate(R.layout.custom_screen, null);
        mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.main_content);
        mCustomViewContainer = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.fullscreen_custom_content);

        mLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);

        // Configure the webview
        WebSettings s = getSettings();
        s.setBuiltInZoomControls(true);
        s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
        s.setUseWideViewPort(true);
        s.setLoadWithOverviewMode(true);
      //  s.setSavePassword(true);
        s.setSaveFormData(true);
        s.setJavaScriptEnabled(true);
        mWebChromeClient = new MyWebChromeClient();
        setWebChromeClient(mWebChromeClient);

        setWebViewClient(new WebViewClient());

setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);

        // enable navigator.geolocation 
       // s.setGeolocationEnabled(true);
       // s.setGeolocationDatabasePath("/data/data/org.itri.html5webview/databases/");

        // enable Web Storage: localStorage, sessionStorage
        s.setDomStorageEnabled(true);

        mContentView.addView(this);
    }

    public HTML5WebView(Context context) {
        super(context);
        init(context);
    }

    public HTML5WebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public HTML5WebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public FrameLayout getLayout() {
        return mLayout;
    }

    public boolean inCustomView() {
        return (mCustomView != null);
    }

    public void hideCustomView() {
        mWebChromeClient.onHideCustomView();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if ((mCustomView == null) && canGoBack()){
                goBack();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    private class MyWebChromeClient extends WebChromeClient {
        private Bitmap      mDefaultVideoPoster;
        private View        mVideoProgressView;

        @Override
        public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)
        {
            //Log.i(LOGTAG, "here in on ShowCustomView");
            HTML5WebView.this.setVisibility(View.GONE);

            // if a view already exists then immediately terminate the new one
            if (mCustomView != null) {
                callback.onCustomViewHidden();
                return;
            }

            mCustomViewContainer.addView(view);
            mCustomView = view;
            mCustomViewCallback = callback;
            mCustomViewContainer.setVisibility(View.VISIBLE);
        }

        @Override
        public void onHideCustomView() {
            System.out.println("customview hideeeeeeeeeeeeeeeeeeeeeeeeeee");
            if (mCustomView == null)
                return;        

            // Hide the custom view.
            mCustomView.setVisibility(View.GONE);

            // Remove the custom view from its container.
            mCustomViewContainer.removeView(mCustomView);
            mCustomView = null;
            mCustomViewContainer.setVisibility(View.GONE);
            mCustomViewCallback.onCustomViewHidden();

            HTML5WebView.this.setVisibility(View.VISIBLE);
            HTML5WebView.this.goBack();
            //Log.i(LOGTAG, "set it to webVew");
        }


        @Override
        public View getVideoLoadingProgressView() {
            //Log.i(LOGTAG, "here in on getVideoLoadingPregressView");

            if (mVideoProgressView == null) {
                LayoutInflater inflater = LayoutInflater.from(mContext);
                mVideoProgressView = inflater.inflate(R.layout.video_loading_progress, null);
            }
            return mVideoProgressView; 
        }

         @Override
         public void onReceivedTitle(WebView view, String title) {
            ((Activity) mContext).setTitle(title);
         }

         @Override
         public void onProgressChanged(WebView view, int newProgress) {
             ((Activity) mContext).getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress*100);
         }

         @Override
         public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
             callback.invoke(origin, true, false);
         }
    }


    static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS =
        new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}

custom_screen.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android">
    <FrameLayout android:id="@+id/fullscreen_custom_content"
        android:visibility="gone"
        android:background="@color/black"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
    <LinearLayout android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout android:id="@+id/error_console"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
        />

        <FrameLayout android:id="@+id/main_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
        />
    </LinearLayout>
</FrameLayout>

video_loading_progress.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/progress_indicator"
         android:orientation="vertical"
         android:layout_centerInParent="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content">

       <ProgressBar android:id="@android:id/progress"
           style="?android:attr/progressBarStyleLarge"
           android:layout_gravity="center"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content" />

       <TextView android:paddingTop="5dip"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:text="loading_video" android:textSize="14sp"
           android:textColor="?android:attr/textColorPrimary" />
 </LinearLayout>

【讨论】:

  • 嗯,能不能给我视频链接,我可以试试健身
  • 我会给你课程内容,你必须使用 index.html 提供将课程内容加载到 Webview 的文件夹,Webview 应该能够播放内容中的视频。
  • 内容在哪里?
  • goo.gl/GVtgD0这是课程内容,请将其放入SDCARD并尝试播放课程内容。
  • 您必须自己下载整个 rar 文件,并将其放入 SDCARD/Internal(哪个是主要文件)中的任何位置,并为该文件夹中存在的 index.html 文件提供硬编码路径
【解决方案3】:

这可能无济于事,但您应该只为 Android 提供 download the source for Firefox 并将其捆绑到您的应用中,如果它可以让您的生活更轻松。我为一个需要 websockets 并且我们需要向后兼容性的项目执行此操作。

【讨论】:

  • 你能多解释一下吗
  • 首先下载firefox代码,看看你能不能让它编译和启动。如果您克服了这个障碍,那么您可以将 firefox 源代码转换为库项目并将其包含到您的应用程序中。或者,您可以将整个源代码复制到您的应用程序中。请记住,Firefox 浏览器也会在活动中启动。您可以找到活动的布局并隐藏您不想显示的元素(如地址栏),然后以编程方式将您的页面/数据加载到其中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 2012-11-07
相关资源
最近更新 更多