在 WKWebView 中操作粘贴内容

2023-12-01

我需要操作粘贴到 WKWebView(从任何源)中的文本,运行可能需要一些时间的异步操作。

我最初的想法是使用 Javascript 和 WKWebView 配置来获取onpaste event:

WKUserContentController *wkUController = [[WKUserContentController alloc] init];

NSString *pasteJSSource = @"document.addEventListener('onpaste', function(){ window.webkit.messageHandlers.ComposerListener.postMessage('onpaste happened!'); })";

WKUserScript *pasteScript = [[WKUserScript alloc] initWithSource:pasteJSSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly: NO];

[wkUController addScriptMessageHandler:self name:@"ComposerListener"];

[wkUController addUserScript:pasteScript];

webViewConfiguration.userContentController = wkUController;

然后我的班级实现了WKScriptMessageHandler

#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"message: %@", message.body);
}

(忽略Obj-c,swift也可以)

但我有两个问题:

  1. userContentController:didReceiveScriptMessage:从未被调用过
  2. 我不知道如何拦截粘贴的代码并将其替换为不同的代码

关于如何解决这个问题的任何想法(即使没有 JS,我显然不知道:P)? 谢谢。


为了后代:

我确信有一种使用 JS 的方法可以做到这一点并且更干净,但我设法使用方法 swizzling 实现了结果:

//Method Swizzling
UIView *webContentView = self.webView.contentView;
if(webContentView != nil)
{
    //Paste:
    NSError *error;
    [webContentView swizzleMethod:@selector(paste:) withSelector:@selector(my_paste:) error:&error];
    if(error != nil)
    {
        NSLog("Failed to swizzle 'paste:' into WKContentView: %@, error);
        NSAssert(false, error);
    }

    ...
}

其中 contentView 是:

- (UIView *)contentView
{
    return [self subviewWithClassName:@"WKContentView"];
}

方法my_paste:需要成为 UIResponder 的一部分(由私有 WKContentView 实现)

#pragma mark - Method Swizzling UIResponder

@interface UIResponder (WebComposerSwizzling)

- (void)my_paste:(id)sender;
#define original_paste my_paste

@end

@implementation UIResponder (WebComposerSwizzling)

- (void)my_paste:(id)sender
{
    MailComposerViewController* strongComposer = sCurrentComposer;
    if (strongComposer)
        [strongComposer manipulatePasteboard:nil];
    [self original_paste:sender];
}

@end

注意sCurrentComposer是我的 ViewController 中的静态变量

__weak MailComposerViewController* sCurrentComposer;

各种实用程序:

UIView+SubviewSearch

import UIKit

extension UIView {

    /// Find a subview corresponding to the className parameter, recursively.
    @objc public func subviewWithClassName(_ className: String) -> UIView? {
        if NSStringFromClass(type(of: self)) == className {
            return self
        } else {
            for subview in subviews {
                return subview.subviewWithClassName(className)
            }
        }
        return nil
    }
}

NSObject+Swizzling

import Foundation

extension NSObject {

    enum NSObjectSwizzlingError: Error {
        case originalSelectorNotFound
    }

    @objc public func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) throws {
        if let currentMethod = self.instanceMethod(for: currentSelector),
            let newMethod = self.instanceMethod(for:newSelector) {
            method_exchangeImplementations(currentMethod, newMethod)
        } else {
            throw NSObjectSwizzlingError.originalSelectorNotFound
        }
    }

    @objc public func instanceMethod(for selector: Selector) -> Method? {
        let classType: AnyClass! = object_getClass(self)
        return class_getInstanceMethod(classType, selector)
    }
}

(我对 Swift OBJ-C 混合感到抱歉)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 WKWebView 中操作粘贴内容 的相关文章

  • 在 NodeJs 中使用 Jest 模拟 Http Post 请求

    我有一个使用本机 https request 使用 Azure Function 内的 Node Js 构建的外部 POST API 一切正常 现在我正在尝试构建单元测试用例 并对模拟 Request 方法感到震惊 回调响应具有 on 功能
  • Karma Webpack - 错误:找不到模块“./test/utilities.js”

    我正在使用 Karma Webpack 进行项目的单元测试 当我跑步时karma start 我有这个错误 Error Cannot find module test utilities js at myproject test campa
  • 递归process.nextTick警告

    作为我的应用程序的一部分 我有以下代码行 process nextTick function pre populate cache with all users console log scanning users table in ord
  • Google 闭包编译器使用 WebStorm

    我喜欢用谷歌闭包编译器 https developers google com closure compiler in WebStorm https www jetbrains com webstorm 我已经通过 npm 下载了它 npm
  • Angularjs 使用 ng-init 为 ng-model 赋值

    您好 我有以下问题 看起来很简单并且应该有效 但事实并非如此 在我的代码中我输入了
  • 按周将对象数组拆分为组

    我有一个包含这样的数据的对象数组 date 01 01 2017 00 00 00 dataField1 dataField2 date 01 02 2017 00 00 00 dataField1 dataField2 date 01 1
  • 自定义 UIToolbar 距离 iPhone X 上的 home 指示器太近

    我有一个习惯UIToolbar当标签栏隐藏时我显示的 iPhone X 上的工具栏按钮距离主页指示器太近 let toolbar UIToolbar let height tabBarController tabBar frame heig
  • NSManagedObjectContext 的performBlockAndWait:不在接收者队列上执行

    我注意到有可能NSManagedObjectContext与NSMainQueueConcurrencyType to performBlockAndWait 并在接收者 主 队列以外的队列上执行该块 例如 以下代码会导致我的parentC
  • Django 管理中的自定义依赖下拉菜单

    我有一个按阶段模型的项目外键 我很难在 Django 管理页面中创建依赖的下拉列表 我想当用户从该项目的 项目下拉 阶段选择一个项目时 在第二个下拉菜单中显示 实现这一目标的最佳方法是什么 如果下拉列表根据其父级的值来过滤项目 那就太好了
  • 链接index.html client.js 和 server.js

    我从 Node js 开始 我的第一个程序已经遇到了问题 下面是我正在使用的代码 索引 html
  • 多个模板槽的相同槽内容

    在vuejs中 有没有一种方法可以为多个插槽设置相同的内容 而无需复制粘贴 So this
  • Backbone.View:delegateEvents 未将事件重新绑定到子视图

    我已将这个问题分解为尽可能小的示例 即 它只是为了演示问题 不一定代表现实世界的场景 假设我有一个父视图 此处为 MainView 其中包含一个子视图 此处为 SubView 如果在任何时候我需要重新渲染父视图 从而重新渲染子视图 我就会丢
  • 将变量从一个 jsp 发送到另一个 jsp

    我有一个 JSP 文件jsp 1 jsp和另一个 JSP 文件jsp 2 jsp 我已经包括了jsp 2 jsp in jsp 1 jsp using 现在我需要某个元素上的单击事件 在该事件中 我想将字符串变量传输到包含的 jsp 中 假
  • up() 和 down() 与 Ext.getCmp()

    我很困惑我需要在 up down 和 Ext getCmp ID 之间使用哪一个作为 grep 对象 对我来说 定义对象的 ID 并通过 Ext getCmp ID 检索对象更容易 而且代码看起来更干净 例如 console log thi
  • jQuery 分钟和秒倒计时器

    我想创建一个 jquery 倒计时器 我尝试了以下代码 但它不起作用 我该怎么办 DEMO https jsfiddle net tbosn210 https jsfiddle net tbosn210 var interval setIn
  • Javascript 或 Coffeescript 中的“Bucket Fill”算法

    我正在编写一个小coffeescript js应用程序 允许用户设计图标 16x16像素或32X32像素 该图标实际上是一个带有颜色单元的二维数组 单元格可以有颜色或为空 我希望用户能够使用 桶油漆 工具填充空白单元格 代表着 如果用户单击
  • 编译到模拟器时如何排除 Xcode 中的框架

    我在我的项目中包含了 TokBox 框架 这样我们就可以进行视频短信 问题是该框架以及它们所需的其他一些框架不允许您在模拟器中编译或运行该应用程序 他们不受支持 有没有办法设置编译器标志以在编译到模拟器时跳过 TokBox 和其他框架 原因
  • Xamarin - iOS 地图上的多个多边形

    我目前正在关注this https developer xamarin com guides xamarin forms application fundamentals custom renderer map polygon map ov
  • 如何将 JSLint 用于依赖于 JQuery 的代码段?

    我对 Javascript 比较陌生 我想通过 JSLint 运行我周末玩的那段代码 这样它就可以指出我在哪里是个十足的白痴 不幸的是 我收到了大量关于缺少函数声明的错误 这些函数声明是 JQuery javascript 库及其各种插件的
  • 将画布下载为 PNG 图像[重复]

    这个问题在这里已经有答案了 当我尝试将画布下载为 PNG 图像时 浏览器会在新页面中打开该图像 但不下载它 我的下载代码 btnScaricaEtichetta click function console log Download loc

随机推荐

  • 如何将变量转换为json?

    我想将json数据发送到ajax 但是如何将变量转换为json或将数组转换为json confirm order click function event event preventDefault var street street val
  • 如何跨线程共享包含 Sender 和 Receiver 字段的结构?

    我有一个结构 大致如下所示 struct Node id Arc
  • 程序从windows启动? C#

    So 我已经构建了一个只需打开一个新程序的winforms winform中的代码是这样的 如果有人需要 Process a Process a Process Start notepad exe BUT 我需要知道如何让程序随 Windo
  • 整数数组中具有最大总和的子序列[重复]

    这个问题在这里已经有答案了 给定一个整数数组 如何找到两个索引 i 和 j 使得子数组中从索引开始和结束的元素之和最大化 在线性时间内 简单的 假设你得到了数组a 首先 计算数组s where s i a 0 a 1 a i 您可以在线性时
  • 添加按钮到 QVideoWidget

    每个人 我尝试为 QMediaPlayer 元素设置点击属性 但我找不到制作它的模式 如果我尝试将按钮放在视频前面 该按钮会放在视频后面 即使使用 button gt raise videoWidget gt lower 如果我按下按钮全屏
  • 如何在没有 2^n if 语句的情况下启动具有许多布尔参数的函数模板

    我有一个 CUDA C 代码 专门出于性能原因而使用函数模板 这样该函数将只执行它需要执行的操作 而不是不断加载和读取布尔值来检查它是否需要执行操作 所有模板参数都是布尔值 在启动内核时 CPU 检查布尔值并启动适当的 我相信这称为内核模板
  • SQL Server 插入缺失行

    我有下表记录每天的值 问题是有时会缺少几天 我想编写一个 SQL 查询来 归还缺失的日子 使用线性插值计算缺失值 所以从下面的源表中可以看出 Date Value 2010 01 10 10 2010 01 11 15 2010 01 13
  • 将 C# 中的 CPU ID 代码转换为 C++ 中的 CPU ID 代码

    我有这个 C 代码来获取处理器 ID 但我无法将其传递给 C 我尝试了很多 但我真的不能 我刚刚开始使用 C 我希望能够通过以下方式获取 CPU ID C 就像我以前使用 C 一样 这是我在 C 中的代码 public static str
  • 嵌套列表理解以展平嵌套列表

    我对 Python 很陌生 想知道如何使用列表理解来展平以下嵌套列表 并使用条件逻辑 nested list 1 2 3 4 5 6 7 8 9 以下返回一个嵌套列表 但是当我尝试通过删除内部方括号来展平列表时 出现错误 odds even
  • Django 1.7 - makemigrations 未检测到更改

    正如标题所示 我似乎无法进行迁移 该应用程序最初低于 1 6 所以我知道迁移最初不会存在 事实上 如果我运行python manage py migrate I get Operations to perform Synchronize u
  • 如何从 Firefox 扩展程序访问网页数据?

    我已经成功地在 Firefox 中运行了一个自定义的非常基本的扩展 接下来我想做的是 检查用户是否位于所需的网页上 如果是 检查每个回发的页面是否包含包含string 如果找到 启动外部应用程序string范围 我对网页上的 javascr
  • pandas to_sql 方法给出日期列错误

    我有一个如下所示的数据框 df pd DataFrame index pd date range 2014 01 01 periods 10 df date df index map lambda x x strftime d m Y df
  • 预期为“struct Matrix_t *”,但参数类型为“struct Matrix_t *”?_?没有不同

    main c 78 25 erreur assignment from incompatible pointer type Werror main c 81 9 erreur passing argument 2 of matrix mul
  • .Net Socket 不响应远程断开连接?

    我正在编写一个小型 C 客户端应用程序 该应用程序使用 TCP IP 连接将数据发送到远程服务器 我正在使用标准 Net TcpClient 对象 并且希望在客户端保持连接打开状态 因为我定期向服务器提交数据包 但是 服务器可能会关闭连接
  • 数据源上的 save() 方法不会触发 querySave/postSave 事件

    我的保存按钮使用 SSJS 和一些逻辑 我想保存数据源 所以我使用 document1 save 脚本有效 但 querySave postSave 代码未执行 唯一的解决方法是使用简单操作并将按钮事件划分为 执行脚本 保存文档 简单操作
  • 存储过程不存在,是吗?

    我遇到一个问题 我有一个数据库连接 我在其中运行存储过程 这个相同的连接用于创建前面所说的存储过程 当我稍后尝试调用给定的存储过程时 我收到以下消息 找不到存储过程 dbo yaf prov upgrade 问题是它确实存在于数据库中 而且
  • 如何以管理员权限启动 Windows 服务

    我有自己的应用程序服务器 它是与 sql 服务器通信的 Windows 服务 在某些情况下 sql 服务器服务停止 所以我通过这段代码声明 ServiceController sc new ServiceController MSSQL S
  • C 代码的 x86 反汇编生成:orq $0x0, %(rsp)

    I have written the following C code 它只是分配一个包含 1000000 个整数和另一个整数的数组 并将数组的第一个整数设置为 0 我编译这个使用gcc g test c o test fno stack
  • 使用自定义 [required] 属性时使用客户端验证

    在这个项目中 我们不使用默认的数据注释属性System ComponentModel DataAnnotations命名空间 但构建了自定义属性 所以我们确实放置了一个 required 属性上的属性 但它是自定义构建的 对于服务器端验证
  • 在 WKWebView 中操作粘贴内容

    我需要操作粘贴到 WKWebView 从任何源 中的文本 运行可能需要一些时间的异步操作 我最初的想法是使用 Javascript 和 WKWebView 配置来获取onpaste event WKUserContentController