Saturday, March 31, 2012

Hi,

I've never imagined that playing a HTML5 Youtube video inside a WebView would be such a tedious task. I even didn't think of it as a separate task.

The problem is that the video doesn't play. YES, it's as simple as that.

Any way, I found a work around solution that causes the video to run inside the media player instead of the WebView and of-course instead of launching the browser.

First, you'll need to add the next piece of code to your activity.

 private class MyChromeClient extends WebChromeClient implements OnCompletionListener, OnErrorListener{  
   
        FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER = new FrameLayout.LayoutParams(  
            ViewGroup.LayoutParams.WRAP_CONTENT,  
            ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);  
   
        @Override  
        public void onShowCustomView(View view, CustomViewCallback callback) {  
          if (view instanceof FrameLayout) {  

            // mainWebView is the view that the video should've played inside.
            wv = (WebView)findViewById(R.id.mainWebView);  
                 
            mCustomViewContainer = (FrameLayout) view;  
            mCustomViewCallback = callback;  

            // mainLayout is the root layout that (ex. the layout that contains the webview)
            mContentView = (RelativeLayout)findViewById(R.id.mainLayout);  
            if (mCustomViewContainer.getFocusedChild() instanceof VideoView) {  
              mVideoView = (VideoView) mCustomViewContainer.getFocusedChild();  
              // frame.removeView(video);  
              mContentView.setVisibility(View.GONE);  
              mCustomViewContainer.setVisibility(View.VISIBLE);  
              setContentView(mCustomViewContainer);  
              mVideoView.setOnCompletionListener(this);  
              mVideoView.setOnErrorListener(this);  
              mVideoView.start();  
   
            }  
          }  
        }  
   
        public void onHideCustomView() {  
          if (mVideoView == null){  
            return;  
          }else{  
          // Hide the custom view.  
          mVideoView.setVisibility(View.GONE);  
          // Remove the custom view from its container.  
          mCustomViewContainer.removeView(mVideoView);  
          mVideoView = null;  
          mCustomViewContainer.setVisibility(View.GONE);  
          mCustomViewCallback.onCustomViewHidden();  
          // Show the content view.  
          mContentView.setVisibility(View.VISIBLE);  
          }  
        }  
   
        public void onCompletion(MediaPlayer mp) {  
          mp.stop();  
          mCustomViewContainer.setVisibility(View.GONE);  
          onHideCustomView();  
          setContentView(mContentView);  
        }  
   
        public boolean onError(MediaPlayer arg0, int arg1, int arg2) {  
          setContentView(mContentView);  
          return true;  
        }  
      }  

Then, you need (of-course) to use the back button to close the video and to go back. And this is how I managed to do this.

 @Override  
      public void onBackPressed() {  
            if(mCustomViewContainer != null){ 
                 
                 mVideoView.stopPlayback();  
                 mCustomViewContainer.setVisibility(View.GONE);  
            
                 if (mVideoView == null){  
              
                      return;  
                 }else{  
                      
                      // Hide the custom view.  
                      mVideoView.setVisibility(View.GONE);  
                      // Remove the custom view from its container.  
                      mCustomViewContainer.removeView(mVideoView);  
                      mVideoView = null;  
                      mCustomViewContainer.setVisibility(View.GONE);  
                      mCustomViewCallback.onCustomViewHidden();  
                      // Show the content view.  
                      mContentView.setVisibility(View.VISIBLE);  
                      setContentView(mContentView);  
                      mCustomViewContainer = null; 
                 }  
            }else if(mainWebView.canGoBack()){
   
                 mainWebView.goBack();
          
            }else{
 
                 super.onBackPressed(); 
            }
      }

You'll need is to add your member variables 

 private VideoView mVideoView;  
 private RelativeLayout mContentView;  
 private FrameLayout mCustomViewContainer;  
 private WebChromeClient.CustomViewCallback mCustomViewCallback;  

One last thing, and actually it's the most important step, is to add the next line.

 webView.setWebChromeClient(new MyChromeClient());  

That's it, don't hesitate to comment, to share your knowledge and to correct me. 

63 comments:

  1. Hi Polaris,

    Very useful guide from you. Thanks. It seems yours is the only solution available for playing HTML5 videos through WebView.

    According to your code, playing videos works fine but when the video is paused and if we move to home screen or we use any other application and if we return back to our video app, the video view is not retained. The video is played from beginning.

    The Log cat says,

    "couldn't save which view has focus because the focused view android.widget.VideoView@4057df18 has no id "

    What am I missing ? can you throw me some light ?

    ReplyDelete
    Replies
    1. Hi indiandragon,

      you can do something like the following:

      private int vidPosition;

      @Override
      protected void onPause() {

      if(mCustomViewContainer != null){

      vidPosition = mVideoView.getCurrentPosition();
      }

      super.onPause();
      }

      @Override
      protected void onResume() {

      if(mCustomViewContainer != null){

      mVideoView.seekTo(vidPosition);
      }
      super.onResume();
      }

      I hope this helps.

      Delete
    2. Thanks, I will try this and post the result.

      By the way, I tried before to set id manually to avoid 'no id' warning

      mCustomVideoView.setId(111);
      mCustomVideoView.canPause();

      I did not get the no id error, but at the same time the video did not start from the paused position.

      Delete
    3. Hi polaris,

      Your solution works great !! But the issue is it works when the application is moved to background for a small amount of time or if less memory is used during the paused state.

      I added,

      mCustomViewContainer.setId(110);
      mCustomVideoView.setId(111);
      mCustomVideoView.canPause();

      Which seem to help in pausing and restoring the video.

      I think pausing and restoring a Custom video view has much to do with Phone Hardware (i.e its memory), Since the phone Iam using has very less memory I cannot restore the video all the time. I think Android shuts my activity down due to less memory.

      If you have a better solution let me know, anyways thanks for your work :)

      Delete
    4. Also can the the onShowCustomView be included as a AsyncTask so the we wont get a ANR when the video takes long to play ? Just a thought, is it possible ?

      Delete
    5. Thanks very much....this is amazing......

      Delete
  2. hello ,

    i have made exactly like you said , and the video is not playing .. can you help me...

    this is my code .


    package com.lamobileapps.onlinecinema;

    import android.app.Activity;
    import android.media.MediaPlayer;
    import android.media.MediaPlayer.OnCompletionListener;
    import android.media.MediaPlayer.OnErrorListener;
    import android.os.Bundle;
    import android.view.Gravity;
    import android.view.Menu;
    import android.view.View;
    import android.view.ViewGroup;
    import android.webkit.WebChromeClient;
    import android.webkit.WebView;
    import android.widget.FrameLayout;
    import android.widget.RelativeLayout;
    import android.widget.VideoView;



    public class MainActivity extends Activity {

    private VideoView mVideoView;
    private RelativeLayout mContentView;
    private FrameLayout mCustomViewContainer;
    private WebChromeClient.CustomViewCallback mCustomViewCallback;
    private WebView wv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView wv1 = (WebView)findViewById(R.id.webView1);
    wv1.setWebChromeClient(new MyChromeClient());
    wv1.loadUrl("http://www.youtube.com/embed/g6csOdF0LF8");



    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
    }


    private class MyChromeClient extends WebChromeClient implements OnCompletionListener, OnErrorListener{

    FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER = new FrameLayout.LayoutParams(
    ViewGroup.LayoutParams.WRAP_CONTENT,
    ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);

    @Override
    public void onShowCustomView(View view, CustomViewCallback callback) {
    if (view instanceof FrameLayout) {

    // mainWebView is the view that the video should've played inside.
    wv = (WebView)findViewById(R.id.webView1);



    mCustomViewContainer = (FrameLayout) view;
    mCustomViewCallback = callback;

    // mainLayout is the root layout that (ex. the layout that contains the webview)
    mContentView = (RelativeLayout)findViewById(R.id.buttonlayout);
    if (mCustomViewContainer.getFocusedChild() instanceof VideoView) {
    mVideoView = (VideoView) mCustomViewContainer.getFocusedChild();
    // frame.removeView(video);
    mContentView.setVisibility(View.GONE);
    mCustomViewContainer.setVisibility(View.VISIBLE);
    setContentView(mCustomViewContainer);
    mVideoView.setOnCompletionListener(this);
    mVideoView.setOnErrorListener(this);
    mVideoView.start();

    }
    }
    }

    public void onHideCustomView() {
    if (mVideoView == null){
    return;
    }else{
    // Hide the custom view.
    mVideoView.setVisibility(View.GONE);
    // Remove the custom view from its container.
    mCustomViewContainer.removeView(mVideoView);
    mVideoView = null;
    mCustomViewContainer.setVisibility(View.GONE);
    mCustomViewCallback.onCustomViewHidden();
    // Show the content view.
    mContentView.setVisibility(View.VISIBLE);
    }
    }

    public void onCompletion(MediaPlayer mp) {
    mp.stop();
    mCustomViewContainer.setVisibility(View.GONE);
    onHideCustomView();
    setContentView(mContentView);
    }

    ReplyDelete
    Replies
    1. public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
      setContentView(mContentView);
      return true;
      }
      }

      @Override
      public void onBackPressed() {
      if(mCustomViewContainer != null){

      mVideoView.stopPlayback();
      mCustomViewContainer.setVisibility(View.GONE);

      if (mVideoView == null){

      return;
      }else{

      // Hide the custom view.
      mVideoView.setVisibility(View.GONE);
      // Remove the custom view from its container.
      mCustomViewContainer.removeView(mVideoView);
      mVideoView = null;
      mCustomViewContainer.setVisibility(View.GONE);
      mCustomViewCallback.onCustomViewHidden();
      // Show the content view.
      mContentView.setVisibility(View.VISIBLE);
      setContentView(mContentView);
      mCustomViewContainer = null;
      }
      }else if(wv.canGoBack()){

      wv.goBack();

      }else{

      super.onBackPressed();
      }
      }


      }

      Delete
  3. Nice tutorial.
    Its working for me.

    But I have a problem with "View getVideoLoadingProgressView();"
    -> How we use this method for showing progress dialog before play video.

    ReplyDelete
  4. queria preguntar, me funciono perfectamente tu aporte, pero cuando la url de youtube no es una fija si no q tengo una lista de videos y al seleccionar se abre el video muy bien, el unico problema que cuando abro otro video y presiono atras me vuelve a abrir el primer video. como se solucionaria este problema q tengo???, gracias

    ReplyDelete
  5. Can I use this code in some way for show the video in the same view (little, without changing the view). Or is impossible play a video of youtube without fullscreen?

    Thank You.

    ReplyDelete
  6. When i implemented the code the video was playing correctly. But YouTube videos full screen button click pauses the video and the whole screen goes black. Is there any way out????
    Thanks in advance:)

    ReplyDelete
  7. Hello, I have been trying to get your example to work but no luck so far.
    Could you please explain to me what the 'wv = (WebView)findViewById(R.id.mainWebView);'should be?
    Could you please post your layout file so I can see how the views are connected?

    ReplyDelete
  8. Hi Polarais, Your code works fine. But in my case, I want to put this inside a View, so the code
    setContentView(mContentView); is throwing a error. Can you help me to fix this? Thanks in advance.

    ReplyDelete
  9. This information is impressive; I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.Android Training in chennai with placement | Android Training in velachery

    ReplyDelete
  10. Appreciation for really being thoughtful and also for deciding on certain marvelous guides most people really want to be aware of.
    Click here:
    angularjs training in sholinganallur
    Click here:
    angularjs training in btm
    Click here:
    angularjs training in rajajinagar
    Click here:
    angularjs training in marathahalli
    Click here:
    angularjs training in bangalore

    ReplyDelete
  11. Thanks for your informative article, Your post helped me to understand the future and career prospects & Keep on updating your blog with such awesome article.Click here:
    Microsoft azure training in velarchery
    Click here:
    Microsoft azure training in sollinganallur
    Click here:
    Microsoft azure training in btm
    Click here:
    Microsoft azure training in rajajinagar



    ReplyDelete
  12. Really great post, I simply unearthed your site and needed to say that I have truly appreciated perusing your blog entries. I want to say thanks for great sharing.
    python training in pune
    python online training
    python training in OMR

    ReplyDelete
  13. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
    Devops training in velachery
    Devops training in annanagar
    Devops training in sholinganallur
    Devops training in tambaram
    DevOps online Training
    DevOps Training in USA

    ReplyDelete
  14. I think you have a long story to share and i am glad after long time finally you cam and shared your experience.
    Blueprism training in marathahalli

    Blueprism training in btm

    Blueprism online training

    ReplyDelete
  15. You made such an interesting piece to read, giving every subject enlightenment for us to gain knowledge. Thanks for sharing the such information with us

    angularjs Training in bangalore

    angularjs Training in btm

    angularjs Training in electronic-city

    angularjs online Training

    angularjs Training in marathahalli

    ReplyDelete
  16. Really very nice blog information for this one and more technical skills are improve,i like that kind of post.
    java training in annanagar | java training in chennai

    java training in chennai | java training in electronic city

    ReplyDelete
  17. Hmm, it seems like your site ate my first comment (it was extremely long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog. I as well as an aspiring blog writer, but I’m still new to the whole thing. Do you have any recommendations for newbie blog writers? I’d appreciate it.

    AWS Interview Questions And Answers

    AWS Training in Bangalore | Amazon Web Services Training in Bangalore

    AWS Training in Pune | Best Amazon Web Services Training in Pune

    Amazon Web Services Training in Pune | Best AWS Training in Pune

    AWS Online Training | Online AWS Certification Course - Gangboard

    ReplyDelete
  18. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging.
    angularjs Training in chennai
    angularjs-Training in pune

    angularjs-Training in chennai

    angularjs Training in chennai

    angularjs-Training in tambaram

    ReplyDelete
  19. Really great post, Thank you for sharing This knowledge.Excellently written article, if only all bloggers offered the same level of content as you, the internet would be a much better place. Please keep it up!
    informatica mdm online training

    apache spark online training

    angularjs online training

    devops online training

    aws online training

    ReplyDelete
  20. This information is impressive; I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.
    lg mobile service center in velachery
    lg mobile service center in porur
    lg mobile service center in vadapalani

    ReplyDelete
  21. Thanks For sharing Your Information The Information shared Is Very Valuable Please Keep Updating Us Python Online Course Hadoop Online Course Data Science Online Course Aws Online Course

    ReplyDelete
  22. Your info is really amazing with impressive content..Excellent blog with informative concept. Really I feel happy to see this useful blog, Thanks for sharing such a nice blog..
    If you are looking for any python Related information please visit our website python training institutes in Bangalore page!

    ReplyDelete
  23. Your info is really amazing with impressive content..Excellent blog with informative concept. Really I feel happy to see this useful blog, Thanks for sharing such a nice blog..
    If you are looking for any Data science Related information please visit our website Data science courses in Pune page!

    ReplyDelete
  24. I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.

    oracle apex tutorial

    ReplyDelete
  25. I am really happy to say it’s an interesting post to read. I learn new information from your article, you are doing a great job. Keep it up...

    Bangalore Training Academy is a Best Institute of Salesforce Admin Training in Bangalore . We Offer Quality Salesforce Admin with 100% Placement Assistance on affordable training course fees in Bangalore. We also provide advanced classroom and lab facility.

    ReplyDelete
  26. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    angular js online training
    top angular js online training
    best angular js online training

    ReplyDelete
  27. I really like looking through an blog article that can make people think. Also, many thanks for allowing for me to comment!

    ReplyDelete
  28. This is so elegant and logical and clearly explained. Brilliantly goes through what could be a complex process and makes it obvious.

    data science training online

    ReplyDelete
  29. microsoft azure training Whatever we gathered information from the blogs, we should implement that in practically then only we can understand that exact thing clearly, but it’s no need to do it, because you have explained the concepts very well. It was crystal clear, keep sharing..

    ReplyDelete
  30. Amazing article. Your blog helped me to improve myself in many ways thanks for sharing this kind of wonderful informative blogs in live.leave some more details.
    Ai & Artificial Intelligence Course in Chennai
    PHP Training in Chennai
    Ethical Hacking Course in Chennai Blue Prism Training in Chennai
    UiPath Training in Chennai

    ReplyDelete
  31. Title:
    Best Software Training Center in Chennai | Infycle Technologies

    Description:
    Want to set your career towards the software field? Then join hands with Infycle Technologies to make this into reality. Infycle Technologies, the best software training institute in Chennai, gives the combined and best software training in Chennai, with various stages of multiple courses such as Big Data, Python, Data Science, Oracle, etc., which will be guided by professional tutors in the field. The Hands-on practical training and the mock interview sessions will be given to the candidates to face the interviews with full confidence. Apart from all, the candidates will be placed in the top MNC's with the highest salary package in the market. To get it all, call 7502633633 and make this happen for your happy life.Best training in Chennai

    ReplyDelete
  32. Infycle Technologies, the best software training institute in Chennai offers the No.1 Data Science training in Chennai for Students, tech professionals, and freshers. In addition to the Data Science Training Course, Infycle also offers other professional courses such as Cyber Security, Python, Oracle, Java, Power BI, Digital Marketing, Big Data, etc., which will be trained with 100% practical classes. After the completion of training, the trainees will be sent for placement interviews in the top MNC's. Call 7502633633 to get more info and a free demo.

    ReplyDelete
  33. Took me time to read all the comments, but I really enjoyed the article. It proved to be Very helpful to me and I am sure to all the commenters here! It’s always nice when you can not only be informed, but also entertained! Best Coding Android Wallpapers

    ReplyDelete
  34. No control professor find. New church society anyone foreign man. Example operation what century.top 10 news today

    ReplyDelete