Auto playing vimeo videos in Android webview

后端 未结 4 2012
一向
一向 2020-12-03 09:04

I\'ve managed to get a vimeo video to load and play, using the following. However the autoplay=1 as indicated in the vimeo oembed docs doesn\'t auto play on load. Anyone fou

相关标签:
4条回答
  • 2020-12-03 09:40

    This answer is specific to Vimeo only. After about a dozen failed attempts, here's what I have working. Perhaps it will help somebody else. A thousand apologies to the original authors of other SO answers. I have 'borrowed' a number of patterns below -- just thought it would be handy to have all this in one place, and do not claim them for my own code.

    First, I have not found a way around embedding the Vimeo player (i.e. you can't get at the mp4 stream directly -- at least not easily or reliably -- I'm pretty sure that's deliberate). Second, Vimeo offers a javascript library to instrument their player, and using it is fairly unavoidable. Beware, it requires message passing, which is a newer browser feature. This is documented on their API page. Third, as is documented elsewhere on SO, you need to be very careful to wait for parts of the stack to become ready, and to not gun-jump. Fourth, the Vimeo player includes a particularly unhelpful background image meant to convey that the plugin is missing or broken (a little frame of film, common icon for this). What is really means is that your javascript has bombed out someplace, and nothing at all is running. If you see the little bit of film on a blank screen, check your javascript.

    Step 1. Set up a WebView. You have this correct above. For reference, here is what I used.

    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);
    

    Step 2. You need the WebChromeClient if you want video to work on the WebView. That's documented here: http://developer.android.com/reference/android/webkit/WebView.html (See HTML Video Support).

    Again, for reference here is what I used.

    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() {
           }
    
    }
    

    The WebViewClient looks like this:

    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);
                }
        }
    
    }
    

    Step 3. You need to build a tiny bit of Javascript to fire the player. I used this:

    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);" +
      "});");
    }
    

    Quick explanation . . . I use jQuery in my JS, that's coming below. That's only for convenience, you can do straight JS if you want to lighten the load. Note that after everything else is ready, the script waits another 3 seconds to actually fire. In my weaker moments, I imagine that the kind folks at Vimeo have a broken "ready" callback. 3 Seconds seems to do it.

    Step 4. You need some HTML and JavaScript on the page. I put it in a text file inside the resources (raw/vimeo_frame.html). The file looks like this:

    <!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>
    

    And I load this html file like so:

    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);
        }
    }
    

    And inject it like so:

    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);
    

    Whew! When the WebView is ready, then the html and js go in, including the iframe with the Vimeo player. When the document is loaded, then we wait for the player to become ready. When the player is ready, we add some listeners. And 3 seconds later, we fire the api 'play' method.

    Those apple-polishers in the audience may be wondering, for completeness, how does one stop the video? Two bits. First, when it ends, I stop it by watching the console output for a message I display. Thus:

    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('');" +
                "});");
        }
    

    Which can be inserted like so:

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

    The second bit is where the video completes its little self. Thus, in the vimeo_frame.html above, just after the 'play' callback, I put:

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

    And in the Activity, I put a bit to watch for this -- see above in the onConsoleMessage override.

    HOWEVER -- as of this writing, I still have not sorted one nagging problem. The MediaPlayer lives on after the WebView and all its progeny are gone. I'm sure this creates some problems, but I haven't identified them yet.

    0 讨论(0)
  • 2020-12-03 09:42

    I had the same issue, I think that you could use this one to make it happen:

    public abstract void setMediaPlaybackRequiresUserGesture (boolean require)

    Added in API level 17 Sets whether the WebView requires a user gesture to play media. The default is true.

    Parameters require whether the WebView requires a user gesture to play media

    Hope to help you at least a little!

    0 讨论(0)
  • 2020-12-03 09:43

    Here is the Simple Solution

    Step1- Ensure you have minSdkVersion 17

    Step2- mWebView.getSettings().setMediaPlaybackRequiresUserGesture(false); Paste this line on the Vimeo Class.

    0 讨论(0)
  • 2020-12-03 09:51

    We've come across the same issue and it seems that Android WebView's (as well as those on iOS) are not programmed to allow auto-start of videos since it's possible that it would eat into someones data plan. You have to actually tap on it unless you want to take Google's WebView as a starting point and roll your own. It's not as easy as it sounds, we tried!

    0 讨论(0)
提交回复
热议问题