首页 > 解决方案 > 一些书签不在 iOS 上执行:如何调试?

问题描述

更新 2:显然,只要 2410 个字符的小书签毕竟可以完全正常工作,我使用表单的脚本对其进行了测试javascript: var a=0; a++; a++; ... window.alert(a);。在 9424 个字符处,小书签的 Chrome 同步失败,但通过从电子邮件复制/粘贴书签,我仍然能够执行它。目前尚不清楚,为什么某些脚本在作为脚本标记时工作(参见更新 1),但在javscript:直接从 URL 执行时会失败。

更新 1:<script/>通过生成指向托管在 Dropbox 上的脚本的标签,看起来相同的小书签可以工作。这只是作为解释,iOS 上的浏览​​器引擎对javascript:URL 的硬编码限制少于 1024 个字符。

原帖

我试图弄清楚为什么一些书签在 iOS 上什么都不做——甚至没有触发错误——无法访问 Mac OS 设备。

作为参考,请考虑以下两个书签(下面的格式化源):

// DebugSimple.js
javascript:/* DebugSimple.js - 10:02:50 2019-12-23 */(function(){ document.body.innerHTML='';document.body.style.all='initial';function putString(string){document.body.innerText+=string;}const oldConsoleLog=console.log;console.log=function(...args){putString('(log) '+args.map(e=>e.toString()).join(' '));return oldConsoleLog(...args);};window.addEventListener('error',event=>{var msg='\n(err) ';msg+=!event ?'!!event = '+event :!event.error ?'!!event.error = '+event.error :!event.error.stack ?'!!event.error.stack = '+event.error.stack : event.error.stack;if(event&&event.error)for(const key in event.error){msg+='\nevent.error.'+key+'='+event.error[key];}putString(msg);});console.log("Log test.");setTimeout(backtraceTest,10);function backtraceTest(){backtraceTest2();}function backtraceTest2(){noSuchFunctionShouldExist();}})();undefined;

// DebugOverlay.js
javascript:/* DebugOverlay.js - 10:07:25 2019-12-23 */(function(){ const highestZIndex=Math.max(...Array.from(document.getElementsByTagName('*')).map(e=>window.getComputedStyle(e).zIndex).map(parseInt).filter(e=>!isNaN(e)));console.log(highestZIndex);function append(parent,html,callback=undefined){var e=document.createElement('DIV');parent.appendChild(e);e.outerHTML=html;e=parent.lastElementChild;if(callback)callback(e);return e;}const ifr=document.createElement('IFRAME');document.body.prepend(ifr);ifr.id='debugOverlay.js';ifr.style.all='initial';ifr.style.zIndex=highestZIndex+1;ifr.style.position='fixed';ifr.style.left='5%';ifr.style.right='5%';ifr.style.width='90%';ifr.style.height='90%';ifr.style.opacity='90%';ifr.style.backgroundColor='#ddd';ifr.style.border='1pt solid #888';ifr.contentDocument;ifr.contentDocument.open();ifr.contentDocument.close();const header=append(ifr.contentDocument.body,"<DIV id='header'/>",e=>{e.style.position='static';});const closeButton=append(header,"<A href='#' id='closeButton'>[CLOSE]</A>",e=>{e.addEventListener('click',()=>ifr.parentElement.removeChild(ifr));});const clearButton=append(header,"<A href='#' id='clearButton'>[CLEAR]</A>",e=>{e.addEventListener('click',()=>{output.innerHTML='';});});const output=append(ifr.contentDocument.body,"<DIV id='outputPane'/>",e=>{e.style.fontFamily='Sans';});append(ifr.contentDocument.body,"<DIV id='overScroll' style='height:30vh'/>");var fontSizeScale=0.8;function setOutputFontSize(scale){output.style.fontSize=(fontSizeScale*100)+'%';}setOutputFontSize(fontSizeScale);const fontSizePlus=append(header,"<A href='#' id='fontSizePlus'>[LGR]</A>",e=>{e.addEventListener('click',()=>{setOutputFontSize(fontSizeScale*=1.2);});});const fontSizeMinus=append(header,"<A href='#' id='fontSizePlus'>[SML]</A>",e=>{e.addEventListener('click',()=>{setOutputFontSize(fontSizeScale/=1.2);});});const toggleLog=append(header,"<A href='#' id='toggleLog'>[log(on)]</a>",e=>{var logVisibility=true;e.addEventListener('click',()=>{setLogVisibility(logVisibility=!logVisibility);});function setLogVisibility(bool){Array.from(output.getElementsByClassName('log')).forEach(ee=>{ee.style.display=bool ?'block':'none';e.innerText=bool ?'[log(on)]':'[log(off)]';});}setLogVisibility(logVisibility);});window.addEventListener('error',(evt)=>(addEntry(evt.error.stack)));function addEntry(string,category='error'){append(output,"<DIV class='entry "+category+"'/>",e=>{e.style.marginTop='0.5em';e.style.borderTop='1px solid #888';e.style.fontWeight=category=='error'?'bold':'';append(e,'<CODE/>',e=>{e.innerText=string;});});};const oldConsoleLog=console.log;console.log=function(...args){oldConsoleLog(...args);addEntry(args.join(' '),'log');};function testingIfErrorLogWorks_a(){testingIfErrorLogWorks_b();}function testingIfErrorLogWorks_b(){noSuchFunction();}setTimeout(testingIfErrorLogWorks_a,10);setTimeout(()=>console.log('LogTest'),20);setTimeout(testingIfErrorLogWorks_b,30);})();undefined;

我已将这些作为书签添加到 Google Chrome (Windows 10) 上,并同步到 iOS 和 Android。

在 Android 和 Windows 上,这两个脚本都按预期工作:

在 iOS 上,更简单的脚本DebugSimple.js将按预期执行并记录错误,因此我知道错误正在 iOS 上被捕获,尽管输出的有用性不如 Android 和 Windows 10。这包括语法错误,例如javascript:};在 URL 栏中输入 (语法错误)。

但是,如果我调用DebugOverlay.js脚本,即使我从书签中手动复制粘贴它,也不会发生任何事情;DebugSimple.js也不报告任何类型的错误。

我怀疑这可能与小书签的长度有关,因为这种行为似乎主要发生在大型小书签上;但无论如何,似乎很奇怪,根本没有任何东西可以表明原因。

在这一点上,我不知道如何进行;请记住,我没有任何 Mac 设备。

格式化的来源DebugSimple.js

document.body.innerHTML = '';
document.body.style.all = 'initial';

function putString(string) {
    document.body.innerText += string;
}


const oldConsoleLog = console.log;
console.log = function(...args) {
    putString('(log) ' + args.map(e => e.toString()).join(' '));
    return oldConsoleLog(...args);
};

window.addEventListener('error', event => {
    var msg = '\n(err) ';
    msg += 
        !event ? '!!event = ' + event :
        !event.error ? '!!event.error = ' + event.error :
        !event.error.stack ? '!!event.error.stack = ' + event.error.stack :
        event.error.stack;
    if(event && event.error) for(const key in event.error) {
        msg += '\nevent.error.' + key + '=' + event.error[key];
    }
    putString(msg);
});

// Test error.

console.log("Log test.");
setTimeout(backtraceTest,10);
function backtraceTest(){ backtraceTest2(); }
function backtraceTest2(){ noSuchFunctionShouldExist(); }

格式化的来源DebugOverlay.js

// DOES NOT WORK IN CHROME WHEN PASTED TO THE CONSOLE.
// The console messes somehow with error events.
// Should work when executed as bookmarklet or 'javascript:' URI.

const highestZIndex = Math.max(
    ...Array.from(document.getElementsByTagName('*'))
        .map(e=>window.getComputedStyle(e).zIndex)
        .map(parseInt)
        .filter(e => !isNaN(e)));
console.log(highestZIndex);

function append(parent, html, callback = undefined) {
    var e = document.createElement('DIV');
    parent.appendChild(e);
    e.outerHTML = html;
    e = parent.lastElementChild;
    if(callback) callback(e);
    return e;
}

const ifr = document.createElement('IFRAME');
document.body.prepend(ifr);
ifr.id = 'debugOverlay.js';
ifr.style.all = 'initial';
ifr.style.zIndex = highestZIndex + 1;
ifr.style.position = 'fixed';
ifr.style.left = '5%';
ifr.style.right = '5%';
ifr.style.width = '90%';
ifr.style.height = '90%';
ifr.style.opacity = '90%';
ifr.style.backgroundColor = '#ddd';
ifr.style.border = '1pt solid #888';

// Firefox requires content to be initialized.
ifr.contentDocument;
ifr.contentDocument.open();
ifr.contentDocument.close();

const header = append(ifr.contentDocument.body, "<DIV id='header'/>", e => {
    e.style.position = 'static';
});
const closeButton = append(header, "<A href='#' id='closeButton'>[CLOSE]</A>", e => {
    e.addEventListener('click', () => ifr.parentElement.removeChild(ifr));
});
const clearButton = append(header, "<A href='#' id='clearButton'>[CLEAR]</A>", e => {
    e.addEventListener('click', () => {
        output.innerHTML = '';
    });
});

const output = append(ifr.contentDocument.body, "<DIV id='outputPane'/>", e => {
    e.style.fontFamily = 'Sans';
});

append(ifr.contentDocument.body, "<DIV id='overScroll' style='height:30vh'/>");

var fontSizeScale = 0.8;
function setOutputFontSize(scale) {
    output.style.fontSize = (fontSizeScale * 100) + '%';
}
setOutputFontSize(fontSizeScale);
const fontSizePlus = append(header, "<A href='#' id='fontSizePlus'>[LGR]</A>", e => {
    e.addEventListener('click', () => {
        setOutputFontSize(fontSizeScale *= 1.2);
    });
});
const fontSizeMinus = append(header, "<A href='#' id='fontSizePlus'>[SML]</A>", e => {
    e.addEventListener('click', () => {
        setOutputFontSize(fontSizeScale /= 1.2);
    });
});

const toggleLog = append(header, "<A href='#' id='toggleLog'>[log(on)]</a>", e => {
    var logVisibility = true;
    e.addEventListener('click', () => {
        setLogVisibility(logVisibility = !logVisibility);
    });
    function setLogVisibility(bool) {
        Array.from(output.getElementsByClassName('log')).forEach(ee => {
            ee.style.display = bool ? 'block' : 'none';
            e.innerText = bool ? '[log(on)]' : '[log(off)]';
        });
    }
    setLogVisibility(logVisibility);
});



window.addEventListener('error', (evt) => (addEntry(evt.error.stack)));

function addEntry(string, category='error') {
    append(output, "<DIV class='entry "+category+"'/>", e => {
        e.style.marginTop = '0.5em';
        e.style.borderTop = '1px solid #888';
        e.style.fontWeight = category == 'error' ? 'bold' : '';
        append(e, '<CODE/>', e => { e.innerText = string; });
    });
};

const oldConsoleLog = console.log;
console.log = function (...args) {
    oldConsoleLog(...args);
    addEntry(args.join(' '), 'log');
};


// For testing.
function testingIfErrorLogWorks_a() { testingIfErrorLogWorks_b(); }
function testingIfErrorLogWorks_b() { noSuchFunction(); }
setTimeout(testingIfErrorLogWorks_a,10);
setTimeout(()=>console.log('LogTest'), 20);
setTimeout(testingIfErrorLogWorks_b,30);

标签: javascriptiosbookmarklet

解决方案


推荐阅读