【问题标题】:Manually trigger cut/copy/paste in android webview在android webview中手动触发剪切/复制/粘贴
【发布时间】:2019-04-26 12:51:50
【问题描述】:

我正在使用 android webview 构建一个小浏览器应用程序,我一直在 javascript 中使用window.getSelection() 来获取用户选择的任何文本的性质,并根据选择的类型显示自定义上下文菜单,即无论是范围、克拉、是否在 contenteditable 中等等。

除非选择在 iframe 中,否则这工作正常,然后浏览器安全措施启动并阻止我嗅探使用 window.getSelection() 选择的内容。我该如何解决这个问题?

理想情况下,我需要一种方法来获取有关从 web 视图中选择的内容的更好信息,或者如果这不可能,我需要一种方法来嗅探选择是否发生在 iframe 中,以便我可以禁用我的自定义上下文菜单逻辑并回退到默认的 android 上下文菜单。

更新/进一步澄清 07/05/2019:

似乎我最初的描述不够清楚......

我的目标是在 web 视图中选择内容时具有视觉和功能上的 自定义 菜单,该菜单可以像标准上下文菜单在页面/iframe 等的任何部分中所做的那样剪切/复制/粘贴。例如

我意识到我最初使用 javascript 检测选择类型并执行剪切/复制/粘贴的方法是错误的,因为它会被 iframe 中的跨源安全性阻止。

我需要的是基于原生 android/webview 的方法。我发现我可以通过查看onActionModeStarted 上的mode.getMenu() 中的项目来嗅探webview 中的选择类型。这将允许我在我的自定义菜单 UI 中显示正确的按钮,但我无法手动触发在单击剪切/复制/粘贴时调用的相同逻辑。我以为我找到了webView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_CUT, null); 的解决方案,但这由于某种原因不起作用,所以我想我的问题真的是如何在不使用 JavaScript 的情况下从 webview 手动触发所选文本的剪切/复制/粘贴?或任何其他方法可以让我拥有一个自定义选择菜单,其中包含许多基于所选内容的选项而不会影响浏览器安全限制?

【问题讨论】:

    标签: android webview menu selection


    【解决方案1】:

    好的,我大致知道如何做到这一点。

    步骤 1) 在您的活动中,覆盖 onActionModeStarted 并检查默认上下文菜单中可用的菜单项。这为您提供了关于选择类型是什么以及您需要在自定义菜单中显示哪些按钮的线索。它还为您提供了对项目 ID 的引用,您可以稍后使用它来触发操作,例如

    systemSelectionMenu = mode.getMenu(); // keep a reference to the menu
    MenuItem copyItem = systemSelectionMenu.getItem(0); // fetch any menu items you want
    copyActionId = copyItem.getItemId(); // store reference to each item you want to manually trigger
    

    第 2 步)不要清除菜单,而是使用 setVisible() 隐藏您想要自定义按钮的每个菜单项,例如

    copyItem.setVisible(false); 
    

    第 3 步)在您的自定义按钮 onclick 事件中,您可以使用以下方法触发复制操作:

    myActivity.systemSelectionMenu.performIdentifierAction(myActivity.copyActionId, 0)
    

    【讨论】:

    • 注意:我从来没有找到一种方法来获取实际选定的文本而不是复制它,所以你必须依靠 javascript window.getSelection() 你需要了解更多关于正在发生的事情选择
    【解决方案2】:

    您只能检索iframe 的选择,前提是它具有相同的来源。否则,您将没有机会跟踪任何iframe 的事件(点击、触摸、按键等)。

    const getSelectedText = (win, doc) => {    
      const isWindowSelectionAvailable = win && typeof win.getSelection != "undefined";
      if (isWindowSelectionAvailable) {
        return win.getSelection().toString();
      }
    
      const hasDocumentSelection = doc && typeof doc.selection != "undefined" && doc.selection.type == "Text";
      if (hasDocumentSelection) {
        return doc.selection.createRange().text;
      }
    
      return '';
    }
    
    const doIfTextSelected = (win, doc, cb) => () => {
      const selectedText = getSelectedText(win, doc);
      if (selectedText) {
          cb(selectedText);
      }
    }
    
    const setupSelectionListener = (win, doc, cb) => {
      doc.onmouseup = doIfTextSelected(win, doc, cb);
      doc.onkeyup = doIfTextSelected(win, doc, cb);
    }
    
    const getIframeWinAndDoc = (iframe) => {
      try {
        const doc = iframe.contentDocument || iframe.contentWindow.document;
        const win = iframe.contentWindow || iframe.contentDocument.defaultView;
    
        return { win, doc };
      } catch (e) {
        console.error(`${e}`);
        
        return {};
      }
    }
    
    const callback = console.log;
    
    setupSelectionListener(window, document, callback);
    
    document.querySelectorAll('iframe').forEach(iframe => {
      const { win, doc } = getIframeWinAndDoc(iframe, console.log);
      
      // Only for same origin iframes due to https://en.wikipedia.org/wiki/Same-origin_policy
      if (win && doc) {
        setupSelectionListener(win, doc, callback);
      }
    })
    <h3>Select me</h3>
    
    <div class="container">
      <iframe src="https://teimurjan.github.io"></iframe>
    </div>

    【讨论】:

    • 抱歉,这对我没有帮助。我已经更新了我原来的帖子,以进一步澄清我所追求的
    【解决方案3】:

    如果它与 Internet Explorer 一起使用,则此问题因浏览器而异,因此它可能与 chrome 一起出现 试试这个

    App.util.getSelectedText = function(frameId) {
    var frame = Ext.getDom(frameId);
    var frameWindow = frame.contentWindow;
    var frameDocument = frameWindow.document;
    
    if (frameDocument.getSelection) {
        return frameDocument.getSelection();
    }
    else if (frameDocument.selection) {
        return frameDocument.selection.createRange().text;
    }
    };
    

    希望一切顺利

    【讨论】:

    • 抱歉,这对我没有帮助。我已经更新了我原来的帖子,以进一步阐明我所追求的
    【解决方案4】:

    主要问题是window.getSelection() 将只返回主上下文/窗口的选择。由于 iframe 是另一个窗口和其他上下文,您应该从“当前”的 iframe 调用 getSelection()

    【讨论】:

    • 抱歉,这对我没有帮助。我已经更新了我原来的帖子,以进一步阐明我所追求的
    • @MeatPopsicle 没问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 2012-05-07
    • 1970-01-01
    • 2010-12-10
    • 2013-05-13
    • 1970-01-01
    相关资源
    最近更新 更多