chrome 45以上不自动播放"非必要"flash的一种可能解决方案 - acelan86/whatthefuck GitHub Wiki

问题

  1. chrome 45以上(包含45)版本默认不自动播放"非必要"flash,对于非自动播放的广告,chrome会在flash上悬浮一个播放按钮,点击后可播放
  2. 对于国内情况来说,flash目前还是很多中小客户的主力素材,展现效果好,且技术成熟。
  3. 目前flash广告大多数使用覆盖a链接来进行落地页和tracker的承载,无法点中chrome贴心提供的播放按钮,结构大概如下:
<div style="width:1000px;height:90px;position:relative;overflow:hidden;">
    <embed width="1000px" height="90px" wmode="opaque" flashvars="clickTAG=http%3A%2F%2Fsax.sina.com.cn%2Fmfp%2Fclick%3Ftype%3D3%26t%3DMjAxNS0xMS0xMCAxMzo1MzoxMgk2MS4xMzUuMTUyLjIwOAkxMC4yMDkuMTIuMjE0XzE0NDQwMzEwMTIuMjA4MDgzCWh0dHA6Ly93d3cuc2luYS5jb20uY24vCVBEUFMwMDAwMDAwNDU4MjUJY2E0YWNiMWEtYzQzZC00MGU2LWJkYWQtNGYyMjAzYjBlMGMyCUZCRDcxMkFFQ0E1OQlGQkQ3MTJBRUNBNTkJX3Zfem9uZTozMDIwMDAsMzAyMDAwfHVzZXJfZ2VuZGVyOjUwMXx2X3pvbmU6MzAyMDAwLDMwMjAwMHxtb2JpbGVfYnJhbmQ6MTIwMXxtb2JpbGVfYnJvd3Nlcjo4MTF8dl9pc3A6MTMwMXx3YXBfb3M6NzAyfHVzZXJfYWdlOjYwM3xwb3M6UERQUzAwMDAwMDA0NTgyNXx2ZXJzaW9uOndlaWJvOjEuMAktCTMwMjAwMHwzMDIwMDAJRkJENzEyQUVDQTU5CU5CMTUwNTAzODkJCUZCRDcxMkFFQ0E1OQlBRQkyMjMxNDQwOTU1CTEJLQktCS0JLQktCS0JLQktCTEJMTQJLQkwCTAJLQ%253D%253D%26url%3Dhttp%253A%252F%252Fju.mmstat.com%252F%253Furl%253Dhttps%253A%252F%252F1111.tmall.com%252F%253Fspm%253Da1z15.20.4415.17295%2526ad_id%253D100131967736897f1773%2526am_id%253D%2526cm_id%253D%2526pm_id%253D%2526campaign_id%253D543711%26captcha%3D7242067352302299025%26viewlog%3Dfalse" name="sinaadtk_swf_uid_0" align="middle" src="http://d1.sina.com.cn/201511/09/1394644_1000x90_30k.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer">
    <a style="position:absolute;background:#fff;opacity:0;filter:alpha(opacity=0);width:1000px;height:90px;left:0;top:0" href="http://sax.sina.com.cn/mfp/click?type=3&amp;t=MjAxNS0xMS0xMCAxMzo1MzoxMgk2MS4xMzUuMTUyLjIwOAkxMC4yMDkuMTIuMjE0XzE0NDQwMzEwMTIuMjA4MDgzCWh0dHA6Ly93d3cuc2luYS5jb20uY24vCVBEUFMwMDAwMDAwNDU4MjUJY2E0YWNiMWEtYzQzZC00MGU2LWJkYWQtNGYyMjAzYjBlMGMyCUZCRDcxMkFFQ0E1OQlGQkQ3MTJBRUNBNTkJX3Zfem9uZTozMDIwMDAsMzAyMDAwfHVzZXJfZ2VuZGVyOjUwMXx2X3pvbmU6MzAyMDAwLDMwMjAwMHxtb2JpbGVfYnJhbmQ6MTIwMXxtb2JpbGVfYnJvd3Nlcjo4MTF8dl9pc3A6MTMwMXx3YXBfb3M6NzAyfHVzZXJfYWdlOjYwM3xwb3M6UERQUzAwMDAwMDA0NTgyNXx2ZXJzaW9uOndlaWJvOjEuMAktCTMwMjAwMHwzMDIwMDAJRkJENzEyQUVDQTU5CU5CMTUwNTAzODkJCUZCRDcxMkFFQ0E1OQlBRQkyMjMxNDQwOTU1CTEJLQktCS0JLQktCS0JLQktCTEJMTQJLQkwCTAJLQ%3D%3D&amp;url=http%3A%2F%2Fju.mmstat.com%2F%3Furl%3Dhttps%3A%2F%2F1111.tmall.com%2F%3Fspm%3Da1z15.20.4415.17295%26ad_id%3D100131967736897f1773%26am_id%3D%26cm_id%3D%26pm_id%3D%26campaign_id%3D543711&amp;captcha=7242067352302299025&amp;viewlog=false" target="_blank"></a>
</div>

思路

对于chrome, 什么是"非必要"

非必要在chrome定义上大概包含以下两点:

  • 不在同域
  • 尺寸不够大(小于398*298,这个我做过测试,确实如此,也不知道这两个数字怎么拍脑门想出来的,不贴demo了)

参考文件:https://news.ycombinator.com/item?id=10133771 文章内有两个chrome源码的连接,也可以到下面去查看

尝试一种解决思路

在广告中,由于各种情况限制,要求广告主的素材同域肯定是不方便的,所以只能从尺寸上解决 通过尝试,可以在flash渲染的时候暂时把尺寸设置成大于398*298,在实际展现的时候在设置回来,这里需要createFlash的方法动下小手脚

** 这里的尺寸有几个注意点: 1、不只是flash自己的尺寸而是真正展现的尺寸,有可能flash设置了足够大,但是它外面包含的容器overflow了,导致flash实际尺寸没有这么大,这样也是无法自动播放的 2、经过尝试,opacity:0 的flash只要尺寸足够大,也是可以自动播放的

直接看代码

改造过的swf.createHTML

        /**
         * 创建flash的html
         * @param  {Object} options 选项
         * @return {String}         flash的html
         * http://www.w3help.org/zh-cn/causes/HO8001  修改成仅用embed标签渲染flash
         */
        sinaadToolkit.swf.createHTML = function (options) {
            options = options || {};
            var item,
                k,
                tmpOpt = {},
                encodeHTML = sinaadToolkit.string.encodeHTML;
            
            // 复制options,避免修改原对象
            for (k in options) {
                tmpOpt[k] = options[k];
            }
            options = tmpOpt;
            
            var vars = options.vars;
            
            // 初始化flashvars参数的值
            if ('string' === typeof vars) {
                options.flashvars = vars;
            } else {
                var fvars = [];
                for (k in vars) {
                    item = vars[k];
                    fvars.push(k + "=" + encodeURIComponent(item));
                }
                options.flashvars = fvars.join('&');
            }

             var str = [];

            // 使用embed时,flash地址的属性名是src,并且要指定embed的type和pluginspage属性
            options.name = options.id || 'sinaadtk_swf_uid_' + (sinaadToolkit.swf.uid++);
            options.align = options.align || 'middle';
            options.src  = options.url || '';
            options.type = 'application/x-shockwave-flash';
            options.pluginspage = 'http://www.macromedia.com/go/getflashplayer';

            //这里是hack的关键处
            //因为尺寸小于398*298,在chrome的45以上版本会自动暂停播放flash
            //所以这里只针对这两个条件进行增加逻辑处理
            //在生成的swfHTML的前面增加注释节点,用来保存当前flash的name,实际宽度和实际高度,格式如下
            //<!--fakesize:name|width|height-->
            //在后面配套使用的过程中判断是否有这个注释来决定是否需要恢复flash的尺寸
            //@link: https://news.ycombinator.com/item?id=10133771
            if (sinaadToolkit.browser.chrome > 44 && !(options.width >= 398 && options.height >= 298)) {
                str.push('<!--fakesize:' + options.name + '|' + parseInt(options.width, 10) + '|' + parseInt(options.height, 10) + '-->');
                options.width = '398px';
                options.height = '298px';
            }

            delete options.id;
            delete options.url;
            delete options.vars;

            str.push('<embed');
            
            // 在firefox、opera、safari下,salign属性必须在scale属性之后,否则会失效
            // 经过讨论,决定采用BT方法,把scale属性的值先保存下来,最后输出
            var salign;
            for (k in options) {
                item = options[k];
                if (item || item === false || item === 0) {
                    if ((new RegExp("^salign\x24", "i")).test(k)) {
                        salign = item;
                        continue;
                    }
                    
                    str.push(' ', k, '="', encodeHTML(item), '"');
                }
            }
            
            if (salign) {
                str.push(' salign="', encodeHTML(salign), '"');
            }
            str.push('/>');
            
            return str.join('');
        };

解析并将生成的flashhtml填充进节点,根据条件决定是否恢复尺寸

        sinaadToolkit.swf.fill(element, html) {
             var fake, flash, cachePosition;
             //如果匹配中<!--fakesize:name|width|height-->开头的
             if ((fake = html.match(/<\!--\s*fakesize\:([0-9a-zA-Z_]+)\|(\d+)\|(\d+)\s*-->/))) {
                  //防止抖动
                  cachePosition = element.style.position;
                  cacheOpacity = element.style.opacity;
                  element.style.position = 'absolute';
                  element.style.opacity = 0;
                  element.innerHTML = html;

                  //稍微延迟并恢复尺寸,这里的延迟没有经过考证
                  setTimeout(function () {
                      flash = core.swf.getMovie(fake[1]);
                      flash.width = fake[2];
                      flash.height = fake[3];

                      //恢复原来状态
                      element.style.position = cachePosition || 'relative';
                      element.style.opacity = cacheOpacity || 1;
                   }, 100);
               } else {
                   //否则直接填充就是了
                   element.innerHTML = html;
               }
        };

对于重排的性能肯定会有影响,等后续做测试和优化,先当一种想法

PS

当然你也可以在浏览器上面加个提示条:请您开启chrome的flash自动播放, 具体方法请百度。。

⚠️ **GitHub.com Fallback** ⚠️