I will adapt another answer of mine for your case.
The canPerformAction:
is actually called on the internal UIWebDocumentView
instead of the UIWebView
, which you cannot normally subclass. With some runtime magic, it's possible.
We create a class which has one method:
@interface _SwizzleHelper : UIView @end
@implementation _SwizzleHelper
-(BOOL)canPerformAction:(SEL)action
{
//Your logic here
return NO;
}
@end
Once you have a web view which you want to control the actions of, you iterate its scroll view's subviews and take the UIWebDocumentView
class. We then dynamically make the superclass of the class we created above to be the subview's class (UIWebDocumentView - but we cannot say that upfront because this is private API), and replace the subview's class to our class.
#import "objc/runtime.h"
-(void)__subclassDocumentView
{
UIView* subview;
for (UIView* view in self.scrollView.subviews) {
if([[view.class description] hasPrefix:@"UIWeb"])
subview = view;
}
if(subview == nil) return; //Should not stop here
NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelper", subview.class.superclass];
Class newClass = NSClassFromString(name);
if(newClass == nil)
{
newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
if(!newClass) return;
Method method = class_getInstanceMethod([_SwizzleHelper class], @selector(canPerformAction:));
class_addMethod(newClass, @selector(canPerformAction:), method_getImplementation(method), method_getTypeEncoding(method));
objc_registerClassPair(newClass);
}
object_setClass(subview, newClass);
}