You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何MonkeyPatch(Swizzle)CGContext绘图方法及监听绘图调用?

监听CGContext绘图操作的实现方案

直接监听CGContext的beginPath、addRect等绘图方法并捕获参数,系统没有提供原生支持,但可以通过动态符号替换的方式实现;如果你的核心需求是捕获UI变化时的画面,还有更稳妥的替代方案,以下是具体说明:

一、通过动态符号替换监听CGContext方法

Core Graphics的绘图API是基于C语言实现的动态链接符号,我们可以利用符号绑定机制替换目标函数,在自定义实现中捕获参数后再调用原函数。

实现步骤

  1. 定义原函数指针和自定义hook函数
    以CGContextBeginPath和CGContextAddRect为例:
#import <CoreGraphics/CoreGraphics.h>
#import <dispatch/dispatch.h>

// 声明原函数指针
typedef void (*CGContextBeginPathPtr)(CGContextRef);
CGContextBeginPathPtr originalBeginPath;

typedef void (*CGContextAddRectPtr)(CGContextRef, CGRect);
CGContextAddRectPtr originalAddRect;

// 自定义hook函数 - 捕获CGContextBeginPath调用
void hookedCGContextBeginPath(CGContextRef ctx) {
    // 在这里捕获上下文参数,做日志记录或其他处理
    NSLog(@"CGContextBeginPath 被调用,上下文地址:%p", ctx);
    // 调用原函数保证绘图流程正常执行
    originalBeginPath(ctx);
}

// 自定义hook函数 - 捕获CGContextAddRect调用
void hookedCGContextAddRect(CGContextRef ctx, CGRect rect) {
    // 捕获矩形参数
    NSLog(@"CGContextAddRect 被调用,矩形区域:%@", NSStringFromCGRect(rect));
    // 调用原函数
    originalAddRect(ctx, rect);
}
  1. 执行符号替换
    借助符号重绑定逻辑(基于dyld公开API实现),在程序启动时替换目标符号:
#import <dlfcn.h>
#import <mach-o/dyld.h>

static void rebindSymbol(const char* symbolName, void* newFunc, void** originalFunc) {
    struct rebinding rebind = {symbolName, newFunc, originalFunc};
    rebind_symbols(&rebind, 1);
}

static void setupCGContextHooks() {
    rebindSymbol("CGContextBeginPath", hookedCGContextBeginPath, (void**)&originalBeginPath);
    rebindSymbol("CGContextAddRect", hookedCGContextAddRect, (void**)&originalAddRect);
}

@implementation HookSetup
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        setupCGContextHooks();
    });
}
@end

注意事项

  • 这种方式属于修改系统函数行为,App Store审核存在风险,仅适合调试或非上架场景。
  • 需保证线程安全,绘图操作可能在多线程执行,处理参数时要避免竞态问题。
  • 部分系统私有绘图方法可能无法通过这种方式捕获。

二、更稳妥的UI画面捕获方案

如果你的核心需求是捕获UI变化时的画面,无需监听底层绘图指令,推荐使用视图快照的方式,简单且符合App Store规则:

实现代码

- (UIImage *)captureViewSnapshot:(UIView *)targetView {
    UIGraphicsBeginImageContextWithOptions(targetView.bounds.size, targetView.opaque, [UIScreen mainScreen].scale);
    [targetView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return snapshotImage;
}

使用场景

  • 在UI变化的回调中调用,比如viewDidLayoutSubviews、属性的didSet观察者、动画完成回调等,确保在UI更新后执行快照。
  • 如需捕获整个屏幕,将targetView替换为[UIApplication sharedApplication].keyWindow即可。

内容的提问来源于stack exchange,提问作者Georgis Andonis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:36:24