利用postMessage解决webview中iframe数据交互问题

最近在项目中遇到了一个在客户端中的webview中嵌入iframe页面的问题,但是嵌入的iframe无法自己撑开,所以需要webview中给iframe一个高度。

webview的Bug

这就比较尴尬了,因为webview肯定不知道iframe的高度,所以需要iframe给传一个高度出来。

经过一番查找之后,知道了一种很方便的方法-postMessage方法。

先来看看他的语法:

otherWindow.postMessage(data, origin, [transfer]);

otherWindow

  • 其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。这里即可以是父窗口,也可以子窗口,两者是可以相互传递数据的。

data

  • 将要发送到其他window的数据。它将会被结构化克隆算法序列化(这个不懂是什么意思)。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。基本是什么参数都可以,字符串、数字、对象、数组,都OK。

origin

  • 字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

transfer(可选)

  • 是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。(不懂是什么意思,一般没有什么用吧,望大神指点)

父页面获取iframe页面信息:

demo我放在github上的:
demo地址:父页面获取iframe页面信息

父页面:

<body>
    <p>我是父页面</p>
    <p>接收到的iframe信息是:<span id="content"></span></p>
    <iframe src="/btoa/b.html" frameborder="0" marginheight="0" marginwidth="0"></iframe>
    <script>
        // event 参数中有 data 属性,就是iframe页面发送过来的数据
         window.addEventListener("message", function(event) {
             // 把iframe页面发送过来的数据显示在父页面中
           document.getElementById("content").innerHTML= event.data;
         }, false);
    </script>
</body>

iframe页面

<body>
    <p>我是iframe页面</p>
    <div>发送的信息是:<input id="iframe" type="text"><input id="sendBtn" type="button" value="发送"></div>
    <script>
        // 点击按钮后向父页面发送数据
        document.getElementById('sendBtn').onclick = function() {
            // window.parent代表父页面
            window.parent.postMessage(document.getElementById("iframe").value, '*');
        }
    </script>
</body>


iframe页面获取父页面信息:

demo我放在github上的:
demo地址:iframe页面获取父页面信息

父页面:

<body>
    <p>我是父页面</p>
    <div>发送的信息是:<input id="iframe" type="text"><input id="sendBtn" type="button" value="发送"></div>
    <iframe src="/atob/b.html" frameborder="0" marginheight="0" marginwidth="0"></iframe>
    <script>
        // 点击按钮后向iframe页面发送数据
        document.getElementById('sendBtn').onclick = function() {
            // window.frames[0]代表第一个iframe页面
            window.frames[0].postMessage(document.getElementById("iframe").value, '*');
        }
    </script>
</body>

iframe页面

<body>
    <p>我是iframe页面</p>
    <p>接收到的父页面信息是:<span id="content"></span></p>
    <script>
        // event 参数中有 data 属性,就是父页面发送过来的数据
         window.addEventListener("message", function(event) {
             // 把父页面发送过来的数据显示在父页面中
           document.getElementById("content").innerHTML= event.data;
         }, false);
    </script>
</body>

通过这两个简单的例子我们会发现postMessage的强大之处,有了postMessage,我们甚至可以在两个iframe之间传送数据,只需要一个共同的父元素做中间页。


需要注意的地方:

兼容性:

caniuse

通过图上可以看出,基本大部分的都能兼容的,但是需要注意一下这句话。

Internet Explorer 8 and 9, and Firefox versions 6.0 and below only support strings as postMessage's message.(ie 8和9,和Firefox 6.0及以下版本只支持字符串作为postMessage的消息。)

所以如果需要支持这些版本的需要注意data只能是字符串。

安全性:

在线上进行交互时,最好做好安全措施,对于postMessage,最好采用“双向安全机制”。发送方发送数据的时候,确认接受方的源(所以最好不要用*),而接受方监听到message事件后,也可以用event.origin判断是否来自于正确可靠的发送方。并且最好做一下传递数据的数据类型校验。如以下代码:

function checkMessage(event) {
    // 只获取需要的域,并非所有都可以跨域
    if (event.origin != "need domain") {
        return false;
    }
    
    var data = event.data;
    // 传输数据类型校验
    if (typeof(data) !== 'object') {
        return false;
    }

    // data 的type中包含xxx则为xxx需要字段。
    return data.type === "xxx";
};

并且通过不同的type可以处理不同的数据,如以下代码:

switch (checkMessage(event)) {
    case 'height':
        $("#bet_"+e.data.id).css("height", (e.data.height+1) + "px");
        break;
    case 'jumpDown':
        window.location.href = downUrl;
        break;
    default:
        break;
}

顺便贴一下本人的博客:yellowlemon的博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,302评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,563评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,433评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,628评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,467评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,354评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,777评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,419评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,725评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,768评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,543评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,387评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,794评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,032评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,305评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,741评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,946评论 2 336

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,144评论 25 707
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    他在发呆阅读 820评论 0 0
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    w_zhuan阅读 505评论 0 0
  • 秋风潇潇寒霜起,欲诉衷肠,锦书难寄。浆声杳杳雁无迹,一弯新月,数首旧词。仔细思量未趁意,花未爽约,人误佳期。菊瘦花...
    简书作者木瓜阅读 419评论 9 8
  • 这篇文章适合大部分像我这种需要做PPT、有点基础而且懒不想加班的职场人,以及需要自己做图片的苦逼新媒体工作从业者。...
    肉肉_Jade阅读 458评论 0 9