草庐IT

android - 在 Android webview 中自动播放 vimeo 视频

coder 2023-11-28 原文

我已经设法使用以下方法加载和播放 vimeo 视频。但是,如 vimeo oembed doc 中所示,autoplay=1 s 不会在加载时自动播放。任何人都找到了自动播放的方法(还需要在视频结束时捕捉事件)

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

最佳答案

此答案仅针对 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 步。如果您希望视频在 WebView 上工作,则需要 WebChromeClient。此处记录: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);" +
  "});");
}

快速解释。 . .我在我的 JS 中使用 jQuery,它在下面。那只是为了方便,如果你想减轻负担,你可以直接做JS。请注意,在其他一切准备就绪之后,脚本会再等待 3 秒才能真正触发。在我软弱的时候,我想象 Vimeo 的好心人有一个 splinter 的“准备好”回调。 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);
    }
}

然后像这样注入(inject):

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 就会进入,包括带有 Vimeo 播放器的 iframe。加载文档后,我们等待播放器准备就绪。当播放器准备就绪时,我们添加一些监听器。 3 秒后,我们触发 api“播放”方法。

观众中那些爱吹毛求疵的人可能想知道,为了完整起见,如何停止视频?两位。首先,当它结束时,我通过观察控制台输出中显示的消息来停止它。因此:

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

第二部分是视频完成它的小 self 的地方。因此,在上面的 vimeo_frame.html 中,就在“播放”回调之后,我输入:

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

在 Activity 中,我做了一些观察 - 请参阅上面的 onConsoleMessage 覆盖。

但是——在撰写本文时,我仍然没有解决一个棘手的问题。 MediaPlayer 在 WebView 及其所有后代消失后继续存在。我确信这会产生一些问题,但我还没有发现它们。

关于android - 在 Android webview 中自动播放 vimeo 视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9030524/

有关android - 在 Android webview 中自动播放 vimeo 视频的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  3. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

  4. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

  5. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  6. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  7. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  8. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

  9. ruby - 在 ruby​​ 中使用自动创建插入数组 - 2

    我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?

  10. ruby - 如何更改此正则表达式以从未指定 v 参数的 Youtube URL 获取 Youtube 视频 ID? - 2

    目前我正在使用这个正则表达式从YoutubeURL中提取视频ID:url.match(/v=([^&]*)/)[1]我怎样才能改变它,以便它也可以从这个没有v参数的YoutubeURL获取视频ID:http://www.youtube.com/user/SHAYTARDS#p/u/9/Xc81AajGUMU感谢阅读。编辑:我正在使用ruby​​1.8.7 最佳答案 对于Ruby1.8.7,这就可以了。url_1='http://www.youtube.com/watch?v=8WVTOUh53QY&feature=feedf'url

随机推荐