从注入的页面执行主机脚本

4
我正在编写一个Safari扩展程序,为一些我没有所有权的网页添加一些功能。我希望我的注入JavaScript页面能够触发主机页面使用的一些JavaScript函数,但它不起作用。在控制台中,我得到了消息ReferenceError: Can't find variable: function_name
我的脚本被指定为“结束脚本”,因此整个页面应该加载完毕。该函数也是从页面上的onclick()处理程序调用的,代码如下:
onclick="function_name($(this).up());"

我可以获取到该页面元素的引用,但是当我调用element.onclick()时,我会得到另一个错误:TypeError: 'undefined' is not a function (evaluating '$(this).up()')

奇怪的是,当我从AppleScript中调用JavaScript函数(do JavaScript "function_name()" in page)时,它可以正常工作。如何触发这些函数呢?

2个回答

2
我可以从canisbos的回答中进行扩展。您可以使用PostMessage函数与插入的脚本进行通信。
注入的脚本:
//insert script to page
var myScriptElement = document.createElement('script'); 
myScriptElement.innerHTML =
  'window.addEventListener("message", function(e) {' +
  '  if (e.data.msg == "do") {' +
  '    foo(e.data.info);' +
  '    postMessage({msg: "done", info: "answer"}, "*");' +
  '  };' +
  '}, false);'
document.querySelector('head').appendChild(myScriptElement);

//add answers listener
window.addEventListener('message', function(e) {
  if (e.data.msg == 'done') {
    console.log(e.data.info);
  };
}, false);

//add the testing function on the body click
document.addEventListener('click', function (e) {
  //call inserted script
  postMessage({msg: 'do', info: 'from inject'}, '*');
}, false);

测试 HTML 页面:

<html>
<script>
  function foo(text) {
    console.log(text);
  };
</script>
<body>
  <button id='button' onclick='foo("from page")'>test</button>
</body>
</html>

2

这个功能无法正常工作是因为插件注入的脚本被沙盒化了,它只能看到页面的DOM对象(反之亦然),而无法访问页面的全局对象。解决这个安全限制的方法是让插件注入的脚本创建一个包含所需语句的<script>元素,并将其插入文档中。例如:

var myScriptElement = document.createElement('script');
myScriptElement.innerHTML = 'alert("Page is using jQuery " + $.fn.jquery)';
document.querySelector('head').appendChild(myScriptElement);

然而,插入的脚本也无法访问被注入脚本的对象。因此,例如,如果您尝试从插入的脚本中访问扩展的safari对象,您将会收到一个引用错误。


我有没有办法与插入的脚本进行通信?那是有用的信息并解释了正在发生的事情,但我真的想找到一些绕过它的方法。 - Dov
你可以使用DOM来实现注入脚本(扩展程序)和插入脚本之间的通信。如果你想要从插入脚本传递一个值到注入脚本,或者反过来,第一个脚本可以使用element.setAttribute()在文档中设置一个元素的属性,然后在稍后的时间里,第二个脚本可以使用element.getAttribute()读取它。例如,你可以使用:document.documentElement.setAttribute('my_attr', '999')然后检索该值:document.documentElement.getAttribute('my_attr') - chulster
但它必须以一定的间隔轮询吗? - Dov
根据你的目标,那可能是一种方式。还有可能有其他的方法。 - chulster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接