前言:
有這樣的一個需求,要求客戶端展示的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彈框,超鏈接點擊也跳轉不了。沒有使用剪切板