在android webview中手动触发剪切/复制/粘贴

gr8qqesn  于 2022-12-21  发布在  Android
关注(0)|答案(4)|浏览(458)

我正在用android webview开发一个小的浏览器应用程序,我已经在javascript中使用了window.getSelection()来获取用户选择的任何文本的性质,并根据选择的类型显示一个自定义的上下文菜单,例如,它是否是一个范围,一克拉,是否在一个contenteditable中等等。
除非选择是在iframe中,否则这种方法可以正常工作,然后浏览器安全措施会启动,阻止我使用window.getSelection()嗅探所选内容。
理想情况下,我需要一种方法来获得关于从webview中选择了什么的更好的信息,或者如果这不可能,我需要一种方法来嗅探选择是否发生在iframe中,这样我就可以禁用我的自定义上下文菜单逻辑,并退回到默认的android上下文菜单。

更新/进一步澄清2019年5月7日:

我最初的描述似乎不够清楚...
我的目标是有一个视觉和功能 * 自定义 * 菜单时,选择内容的网页视图,可以剪切/复制/粘贴作为标准的上下文菜单在任何部分的网页/iframes等。

我意识到我最初使用javascript来检测选择类型并执行剪切/复制/粘贴的方法是错误的,因为它会被iframes中的跨源安全阻止。
我需要的是一个原生的基于android/webview的方法。我发现我可以通过在onActionModeStarted上查看mode.getMenu()中的项目来嗅探webview中的选择类型。这将允许我在自定义菜单UI中显示正确的按钮,但我无法手动触发点击剪切/复制/粘贴时调用的相同逻辑。我以为我找到了webView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_CUT, null);的解决方案,但由于某种原因,它不起作用,所以我想我的问题真的是我如何在不使用javascript的情况下手动触发对webview中选定文本的剪切/复制/粘贴?或者任何其他方法,将允许我有一个自定义的选择菜单与大量的选项的基础上选择了什么,而不会击中浏览器的安全限制?

a7qyws3x

a7qyws3x1#

好了,我大概知道怎么做了.
步骤1)在Activity中,覆盖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)
xkrw2x1b

xkrw2x1b2#

只有当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>
rqqzpn5f

rqqzpn5f3#

这个问题因浏览器而异,如果它与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;
}
};

希望它运行良好

xfb7svmp

xfb7svmp4#

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

相关问题