IOS UIWebview/WKWebView 禁用複製粘貼、超鏈接

前言:
有這樣的一個需求,要求客戶端展示的html內容,用戶不可複製粘帖、點擊裏面的超鏈接。本來這個功能就是h5嵌入原生功能的,裏面有查看附件的功能,而且這個附件不是以url的鏈接方式給的,是以流的形式,客戶端先下載下來再展示出來的。

(一)UIWebview如何操作

一、拷貝粘貼問題

1、於是一直搜索UIWebview禁用複製粘貼、超鏈接,結果搜索出來的解決方法如下:

方法一:

if (@available(iOS 8.0, *))
  {
   if (@available(iOS 11.0, *)){
        for (UIView* subview in wkWebView.scrollView.subviews) {
            if ([subview isKindOfClass:NSClassFromString(@"WKContentView")])
            {
                for (UIGestureRecognizer* longPress in subview.gestureRecognizers) {
                    if ([longPress isKindOfClass:UILongPressGestureRecognizer.class]) {
                        [subview removeGestureRecognizer:longPress];
                        return;
                    }
                }
            }
        }
    }

      for (UIView* subview in wkWebView.scrollView.subviews) {
        if ([subview isKindOfClass:NSClassFromString(@"WKContentViewMinusAccessoryView")])
        {
            for (UIGestureRecognizer* longPress in subview.gestureRecognizers) {
                if ([longPress isKindOfClass:UILongPressGestureRecognizer.class]) {
                    [subview removeGestureRecognizer:longPress];
                }
            }
        }
    }
}

方法二:

// 控制器實現此方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(copy:) ||
        action == @selector(paste:)||
        action == @selector(cut:))
    {
        return NO;
    }
    return [super canPerformAction:action withSender:sender];
}```

方法三:

```objectivec
- (void)webViewDidFinishLoad:(UIWebView *)webView {

// 禁止用戶複製粘貼

[self.webView stringByEvaluatingJavaScriptFromString:@”document.documentElement.style.webkitUserSelect=’none’;];

// 禁止用戶撥打電話

[self.webView stringByEvaluatingJavaScriptFromString:@”document.documentElement.style.webkitTouchCallout=’none’;];

}

不好意思,上面的方法對於iOS 8.0以前是可以,可是現在我們都13.X都無效

又找到了方法四:在webview上添加長按事件

///1、在viewdidload或適當的地方創建一個自定義的長按手勢

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:nil];
    longPress.delegate = self; //記得在.h文件里加上委託
    longPress.minimumPressDuration = 0.4; //這裏爲什麼要設置0.4,因爲只要大於0.5就無效,我像大概是因爲默認的跳出放大鏡的手勢的長按時間是0.5秒,
    //如果我們自定義的手勢大於或小於0.5秒的話就來不及替換他的默認手勢了,這是隻是我的猜測。但是最好大於0.2秒,因爲有的pdf有一些書籤跳轉功能,這個值太小的話可能會使這些功能失效。
 
    [self.webView addGestureRecognizer:longPress];

///2、接下來就是實現一個委託了

#pragma mark - GestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return NO; //這裏一定要return NO,至於爲什麼大家去看看這個方法的文檔吧。
    //還有就是這個委託在你長按的時候會被多次調用,大家可以用nslog輸出gestureRecognizer和otherGestureRecognizer
    //看看都是些什麼東西。
 
}

在用戶非正常操作下這種方式還是會出現複製的彈框

最後在stack overflow其實一開始的那些方法,這裏面都有,然後看到下面
在這裏插入圖片描述

針對我這個需求的解決方案,在要展示的附件的頁面,添加app要進入後臺的通知,然後在該通知裏將粘貼板的數據清空,這樣不會影響到整個app,其實也可以在AppDelegate中清空,不過這個就對整個app起作用了。

- (void)applicationDidEnterBackground:(UIApplication *)application {
 [UIPasteboard generalPasteboard].string = @"";
}
///通知的方式來清空
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];


///在app進入後臺時將粘貼板數據清空,就不會被複制
- (void)appDidEnterBackground {
    ///將粘貼板上的數據清掉,這樣html中的其他數據就不會被複制了
    [UIPasteboard generalPasteboard].string = @"";
}

這樣即使有拷貝的操作,但是粘貼過去的信息是空的字符串,至此解決拷貝問題

二、超鏈接問題

#pragma mark - 超鏈接禁止點擊
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *requestURL =[request URL];
    if (([[requestURL scheme] isEqualToString: @"http"] || [[requestURL scheme] isEqualToString:@"https"] || [[requestURL scheme] isEqualToString: @"mailto"])
        && (navigationType == UIWebViewNavigationTypeLinkClicked)) {
        return NO;
    }
    return YES;
}

(二)WKWebView如何操作

一、拷貝粘貼問題
這個是針對直接給的一個url來操作的

@interface ViewController ()

@property (nonatomic,strong) WKWebView *webView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //WKWebview 禁止長按(超鏈接、圖片、文本...)彈出效果
    [self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
    [self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];
    
    NSURL *url = [NSURL URLWithString:@"http://www.mingyizhi.cn/test/mingyizhishare/caseDetails.html?caseId=72df6b2036b740b985e478946002fecc"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
    // Do any additional setup after loading the view, typically from a nib.
    
    
    if (@available(iOS 8.0, *))
      {
       if (@available(iOS 11.0, *)){
           for (UIView* subview in self.webView.scrollView.subviews) {
               NSLog(@"subview-->%@",subview);
                if ([subview isKindOfClass:NSClassFromString(@"WKContentView")])
                {
                    for (UIGestureRecognizer* longPress in subview.gestureRecognizers) {
                        if ([longPress isKindOfClass:UILongPressGestureRecognizer.class]) {
                            [subview removeGestureRecognizer:longPress];
                            return;
                        }
                    }
                }
            }
        }

          for (UIView* subview in self.webView.scrollView.subviews) {
              NSLog(@"~~~~subview-->%@",subview);
            if ([subview isKindOfClass:NSClassFromString(@"WKContentViewMinusAccessoryView")])
            {
                for (UIGestureRecognizer* longPress in subview.gestureRecognizers) {
                    if ([longPress isKindOfClass:UILongPressGestureRecognizer.class]) {
                        [subview removeGestureRecognizer:longPress];
                    }
                }
            }
        }
    }
}

- (WKWebView *)webView {
    if (!_webView) {
        //禁止長按彈出 UIMenuController
        NSString*css = @"body{-webkit-user-select:none;-webkit-user-drag:none;}";
        NSMutableString*javascript = [NSMutableString string];
        [javascript appendString:@"var style = document.createElement('style');"];
        [javascript appendString:@"style.type = 'text/css';"];
        [javascript appendFormat:@"var cssContent = document.createTextNode('%@');", css];
        [javascript appendString:@"style.appendChild(cssContent);"];
        [javascript appendString:@"document.body.appendChild(style);"];
        [javascript appendString:@"document.documentElement.style.webkitUserSelect='none';"];
        [javascript appendString:@"document.documentElement.style.webkitTouchCallout='none';"];
        // javascript注入
        WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript
                                          
                                                                injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
                                          
                                                             forMainFrameOnly:YES];
        
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [userContentController addUserScript:noneSelectScript];
        
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        configuration.userContentController = userContentController;
        
        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
        
        [_webView.configuration.userContentController addUserScript:noneSelectScript];
        
        _webView.backgroundColor = [UIColor whiteColor];
        [self.view addSubview:_webView];
    }
    return _webView;
}

@end

二、超鏈接

// 根據WebView對於即將跳轉的HTTP請求頭信息和相關信息來決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

	NSString *urlStr = navigationAction.request.URL.absoluteString;
    NSString *hostUrl = [[navigationAction.request URL] host];

///其實若是單個url,web應該可以限制的不讓拷貝的
///因爲我的這個需求本來就是嵌套h5的頁面,在裏面有交互,以流的形式展示,其實這個url還不好排除,若是裏面的鏈接就是某個相同的鏈接,那麼你還是可以打開的
 	if ([urlStr containsString:@"xxx"]) {
        decisionHandler(WKNavigationActionPolicyAllow);
    } else {
        decisionHandler(WKNavigationActionPolicyCancel);
    }
}

1、我使用的是UIWebview,因爲是以前的老代碼了,就在原有的基礎上優化了下。後續改成WKWebview
2、在之前一直在糾結webview的,其實換個思路就輕鬆解決的拷貝問題😢

抽空將項目中的UIWebview 換成了WKWebView


- (void)viewDidLoad {
    [super viewDidLoad];
   
    [self.view addSubview:self.wkWebView];
    [_wkWebView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.top.trailing.bottom.equalTo(self.view);
    }];
  
    [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
    [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];
    [self.wkWebView loadFileURL:self.fileURL allowingReadAccessToURL:self.fileURL];
}

- (WKWebView *)wkWebView {
    if (!_wkWebView) {
        NSString*css = @"body{-webkit-user-select:none;-webkit-user-drag:none;}";
        NSMutableString*javascript = [NSMutableString string];
        [javascript appendString:@"var style = document.createElement('style');"];
        [javascript appendString:@"style.type = 'text/css';"];
        [javascript appendFormat:@"var cssContent = document.createTextNode('%@');", css];
        [javascript appendString:@"style.appendChild(cssContent);"];
        [javascript appendString:@"document.body.appendChild(style);"];
        [javascript appendString:@"document.documentElement.style.webkitUserSelect='none';"];
        [javascript appendString:@"document.documentElement.style.webkitTouchCallout='none';"];
       // javascript注入
        WKUserScript *noneSelectScript = [[WKUserScript alloc] initWithSource:javascript
                                         
                                                               injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
                                         
                                                            forMainFrameOnly:YES];
       
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [userContentController addUserScript:noneSelectScript];
       
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        configuration.userContentController = userContentController;
       
        _wkWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
       
        [_wkWebView.configuration.userContentController addUserScript:noneSelectScript];
        _wkWebView.navigationDelegate = self;
        _wkWebView.backgroundColor = [UIColor clearColor];
    }
    return _wkWebView;
}

#pragma mark - WKNavigationDelegate
/// 根據WebView對於即將跳轉的HTTP請求頭信息和相關信息來決定是否跳轉
/// 點擊超鏈接不跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
    NSString * urlStr = navigationAction.request.URL.absoluteString;
    AppLog(@"發送跳轉請求:%@",urlStr);
    
    if ([urlStr hasPrefix:@"http"] || [urlStr hasPrefix:@"mailto"]) {
        decisionHandler(WKNavigationActionPolicyCancel);
    }else {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}

WKWebView這種就不會出現UIMenuController的那種copy彈框,超鏈接點擊也跳轉不了。沒有使用剪切板

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章