Автоматическое воспроизведение видео Vimeo в веб-браузере Android

Мне удалось получить видео Vimeo для загрузки и воспроизведения, используя следующее. Однако autoplay=1, как указано в документах vimeo oembed, не загружается автоматически при загрузке. Кто-нибудь нашел способ автоматического воспроизведения (также нужно ловить событие, когда видео заканчивается)

mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setAppCacheEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);

// how plugin is enabled change in API 8
if (Build.VERSION.SDK_INT < 8) {
  mWebView.getSettings().setPluginsEnabled(true);
} else {
  mWebView.getSettings().setPluginState(PluginState.ON);
}
mWebView.loadUrl("http://player.vimeo.com/video/24577973?player_id=player&autoplay=1&title=0&byline=0&portrait=0&api=1&maxheight=480&maxwidth=800");

4 ответа

Этот ответ относится только к Vimeo. После примерно дюжины неудачных попыток вот что у меня работает. Возможно, это поможет кому-то еще. Тысяча извинений оригинальным авторам других ответов SO. Ниже я "позаимствовал" несколько шаблонов - просто подумал, что было бы удобно иметь все это в одном месте и не требовать их для моего собственного кода.

Во-первых, я не нашел способа встроить проигрыватель Vimeo (то есть вы не можете напрямую попасть в поток mp4 - по крайней мере, нелегко или надежно - я уверен, что это намеренно). Во-вторых, Vimeo предлагает библиотеку javascript для инструментов своего игрока, и ее использование довольно неизбежно. Осторожно, требуется передача сообщений, что является более новой функцией браузера. Это задокументировано на их странице API. В-третьих, как документировано в других разделах SO, вам нужно быть очень осторожным, чтобы дождаться готовности частей стека и не прыгать с помощью оружия. В-четвертых, проигрыватель Vimeo включает в себя особенно бесполезное фоновое изображение, предназначенное для сообщения о том, что плагин отсутствует или сломан (небольшая рамка фильма, общий значок для этого). Что на самом деле означает, что ваш javascript где-то разбомбил, и ничего не работает. Если вы видите немного фильма на пустом экране, проверьте свой JavaScript.

Шаг 1. Настройте WebView. У вас есть это правильное выше. Для справки вот что я использовал.

mWebView = new WebView((Context) this);
mWebView.setLayoutParams(new LayoutParams(windowWidth, windowHeight));

mWebView.getSettings().setJavaScriptEnabled(true);
 // Watch the sdk level here, < 12 requires 'false
 // Wanted to force HTML5/264/mp4, you may want flash
 //    where still available
mWebView.getSettings().setPluginState(PluginState.OFF);
mWebView.getSettings().setLoadWithOverviewMode(true);
mWebView.getSettings().setUseWideViewPort(true);
mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");

wcc = new MyWebChromeClient();
mWebView.setWebChromeClient(wcc);

wvc = new MyWebViewClient();
mWebView.setWebViewClient(wvc);

Шаг 2. Вам нужен WebChromeClient, если вы хотите, чтобы видео работало в WebView. Это задокументировано здесь: http://developer.android.com/reference/android/webkit/WebView.html (см. Поддержка видео HTML).

Опять же, для справки вот что я использовал.

private class MyWebChromeClient extends WebChromeClient {
    @Override
    public void onProgressChanged(WebView view, int progress) {
        if(progress == 100) {
          // Your page is loaded, but not visible,
          // add whatever navigation elements you plan to use here.
          // N.B. these are JAVA, not JS nav elements
        }
    }

    @Override
    public boolean onConsoleMessage(ConsoleMessage cm) {

     // I like to watch in the console. And, since it was
     // a very convenient way to monitor the javascript, I
     // use it for that too. Purists will object, no doubt

       if(cm.message().equalsIgnoreCase("EVENT -- Finish")) {
            Log.i(TAG, "---> Finishing . . .");
            // Depart the activity
            finish();
       } else {
            Log.d(TAG, " **Console ["+cm.sourceId()+"] ("+cm.lineNumber()+") ["+cm.message()+"]");
       }
       return(true);
   }

       @Override
       public View getVideoLoadingProgressView() {
                        // Something entertaining while the bytes arrive
            Log.i(TAG, " -------------> Loading Progress . . . ");
            LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            return(inflater.inflate(R.layout.loading_video, null));
       }

       @Override
       public void onShowCustomView(View v, WebChromeClient.CustomViewCallback callback) {
                       // With great sadness, I report that this never fires.
                       // Neither does the 'hide'.
       }

       @Override
       public void onHideCustomView() {
       }

}

WebViewClient выглядит следующим образом:

private class MyWebViewClient extends WebViewClient {

    @Override
    public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            String injection = injectPageMonitor();
            if(injection != null) {
            Log.d(TAG, " ---------------> Page Loaded . . .");
                Log.d(TAG, "  Injecting . . . ["+injection+"]");
                view.loadUrl(injection);
            }
    }

}

Шаг 3. Вам нужно собрать чуть-чуть Javascript, чтобы уволить игрока. Я использовал это:

public String injectPageMonitor() {
   return( "javascript:" +
               "jQuery(document).ready( function() { " +
               "console.log(' === Page Ready ===> Setting up');" +
               "console.log(' ==== Sending PLAY Command ===');" +
               "var froogaloop = $f('froog');" +
               "setTimeout(function() {  froogaloop.api('play'); }, 3000);" +
  "});");
}

Быстрое объяснение.,, Я использую jQuery в моем JS, это будет ниже. Это только для удобства, вы можете делать прямые JS, если хотите облегчить нагрузку. Обратите внимание, что после того, как все остальное будет готово, скрипт ждет еще 3 секунды, чтобы фактически выстрелить. В мои более слабые моменты я представляю, что добрые люди в Vimeo имеют сломанный "готовый" обратный вызов. 3 секунды, кажется, делают это.

Шаг 4. Вам нужно немного HTML и JavaScript на странице. Я поместил его в текстовый файл внутри ресурсов (raw/vimeo_frame.html). Файл выглядит так:

<!DOCTYPE html>
<html>
<head>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript">jQuery.noConflict();</script>
<script src="http://a.vimeocdn.com/js/froogaloop2.min.js"></script>

<script type="text/javascript">

   jQuery(document).ready( function() { 
       var showing_player = false;
       var froogaloop = $f('froog');

           console.log(' === Page Ready ===> Setting up');
       jQuery('.froog_container_class').hide();
       jQuery('.console').css('height', '100%');

       froogaloop.addEvent('ready', function() { 

             console.log('====  PLAYER READY ====> Setting Play Callback');
                froogaloop.addEvent('play', function(data) { 
                console.log('EVENT -- Play');
                /* No idea why, but if the player isn't displayed, it goes
                   straight to 'pause'. Probably a feature. So I give it 4x4px
                   to do it's thing during setup */
                jQuery('.froog_container_class').show();
                jQuery('.froog_container_class').css('height', '4px');
                jQuery('.froog_container_class').css('width', '4px');
                jQuery('.froog_container_class').css('overflow', 'hidden');
            });

           /* I don't want to reveal the video until it is actually
              playing. So I do that here */
           var showingPlayer = false;
           froogaloop.addEvent('playProgress', function(data) {
               if(!showingPlayer && data.percent > 0) {
                  showingPlayer = true;
                  jQuery('.froog_container_class').show();
                  jQuery('.froog_container_class').css('height', '_windowHeight');
                  jQuery('.froog_container_class').css('width', '_windowWidth');
                  /* Most tablets I tested aren't quick enough to make this work
                     but one can still hope */
                  jQuery('#loading').fadeOut('slow');
               }
           });

       });
});
</script>
</head>
<body>
<style>
  body {
     background-image: url('http://<SomethingEntertainingToWatch>.png');
     background-size: contain;
  }
  .mask {
     float: left;
     height: _windowHeight;
     width: _windowWidth;
     z-index: 100;
     background: transparent;
     display: inline;
     position: absolute;
     top: 0;
     left: 0;
   }
   .froog_container_class {
      position: absolute;
      height: _windowHeight;
      width: _windowWidth;
      left: 0;
      top: 0;
      display: inline;
      z-index: 1;
    }
    #froog {
      display: inline;
      height: _windowHeight;
      width: _windowWidth;
      postion: absolute;
      top: 0;
      left: 0;
    }
</style>
<div id="loading" class="loading"><h1>Loading</h1><img class="loading_anim" src="http://foo.bar.com/assets/global/loading.gif"/>
</div>
<!-- Completely optional, I put a div in front of the player to block controls -->
<div id="mask" class="mask">
</div>
<div id="froog_container" class="froog_container_class">
   <iframe id="froog" src="_targetUrl?api=1&title=0&byline=0&portrait=0&player_id=froog" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
   </iframe>
</div>
</body>
</html>

И я загружаю этот HTML-файл так:

public String genMainHTML() {
    String code = null;
    try {
        Resources res = getResources();
        InputStream in_s = res.openRawResource(R.raw.vimeo_frame);

        byte[] b = new byte[in_s.available()];
        in_s.read(b);
        code = new String(b);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if(code != null) {
            code = code.replaceAll("_windowHeight", "" + windowHeight + "px");
            code = code.replaceAll("_windowWidth", "" + windowWidth + "px");
            code = code.replaceAll("_targetUrl", targetUrl);
            return(code);
    }  else  {
            return(null);
    }
}

И впрыскивать это так:

mDomain = "http://player.vimeo.com";
mWebView.requestFocus(View.FOCUS_DOWN);
targetUrl = extras.getString("URL");
String meat = genMainHTML();
mWebView.loadDataWithBaseURL(mDomain, meat, "text/html", "utf-8", null);

setContentView(mWebView);

Уф! Когда WebView будет готов, войдут html и js, включая iframe с проигрывателем Vimeo. Когда документ загружен, мы ждем, когда проигрыватель будет готов. Когда плеер готов, мы добавляем несколько слушателей. И через 3 секунды мы запускаем метод API'play'.

Эти полировщики яблок в аудитории, для полноты, могут задаваться вопросом, как остановить видео? Два бита Во-первых, когда он заканчивается, я останавливаю его, наблюдая за выводом на консоль сообщения, которое я отображаю. Таким образом:

public String injectPageFinisher() {
    return( "javascript:" +
            "jQuery(document).ready( function() { " +
              "console.log(' === Page Ready ===> Tearing down');" +
              "console.log(' ==== Sending PAUSE Command ===');" +
              "var froogaloop = $f('froog');" +
          "froogaloop.api('pause');" +
              "jQuery('#froog_container').html('');" +
            "});");
    }

Который можно вставить так:

@Override
public void onPause() {
    super.onPause();
    if(isFinishing()){
        // Unload the page
        if(mWebView != null) {
            Log.i(TAG, " ------> Destroying WebView");
            mWebView.destroy();
        }
    }
    finish();
}

Второй бит, где видео завершает свою маленькую самость. Таким образом, в приведенном выше vimeo_frame.html сразу после обратного вызова play я добавляю:

froogaloop.addEvent('finish', function(data) { 
    console.log('EVENT -- Finish');
});

А в Activity я добавил немного, чтобы следить за этим - см. Выше в переопределении onConsoleMessage.

ОДНАКО - на момент написания этой статьи я до сих пор не разобрался с одной ноющей проблемой. MediaPlayer продолжает существовать после исчезновения WebView и всех его потомков. Я уверен, что это создает некоторые проблемы, но я еще не идентифицировал их.

Мы столкнулись с той же проблемой, и кажется, что Android WebView(как и на iOS) не запрограммированы на автоматический запуск видео, так как возможно, что это будет включено в чей-то тарифный план. Вы действительно должны нажать на него, если вы не хотите взять Google WebView в качестве отправной точки и катиться самостоятельно. Это не так просто, как кажется, мы попробовали!

Вот простое решение

Шаг 1- Убедитесь, что у вас есть minSdkVersion 17

Шаг 2- mWebView.getSettings().setMediaPlaybackRequiresUserGesture(false); Вставьте эту строку в класс Vimeo.

Надеюсь, это поможет кому-то новичку в этом. Пожалуйста, попробуйте следующие настройки для вашего веб-просмотра.

WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setAppCacheEnabled(true);
webSettings.setMediaPlaybackRequiresUserGesture(false);

И добавьте autoplay=1 к URL-адресу вашего видео Vimeo

webView.loadUrl(resLink + "?autoplay=1");

Ссылка resLink будет выглядеть как "https://player.vimeo.com/video/your_video_id"

У меня была та же проблема, я думаю, что вы могли бы использовать это, чтобы это произошло:

public abstract void setMediaPlaybackRequiresUserGesture (логическое требование)

Добавлено в уровень API 17 Устанавливает, требует ли WebView пользовательский жест для воспроизведения мультимедиа. По умолчанию это правда.

Параметры требуют, требует ли WebView пользовательский жест для воспроизведения мультимедиа

Надеюсь помочь вам хоть немного!

Другие вопросы по тегам