iOS之WKWebView、UIWebView、WebViewJavascriptBridge三方框架

目录
    1. WKWebView
    2. UIWebView(javascriptcore.framework)
    3. 三方WebViewJavascriptBridge框架
1. WKWebView
:UIView  

  iOS8后推出
  Safari浏览器(iPhone、mac)都是基于WKWebView 实现的。
  相比WebView更省内存。

1.1 使用详解

#import <WebKit/WebKit.h>    
<WKScriptMessageHandler,WKUIDelegate,WKNavigationDelegate>
    
/**
 初始化UI
 */
-(void)setupUI{
    [self.view addSubview:self.webView];
}
/**
 设置URL,并加载
 */
-(void)setUrlStr:(NSString *)urlStr{
    _urlStr=urlStr;
    
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]];
}


-(WKWebView *)webView{
    if(!_webView){
        // 创建WKWebView
        _webView=[[WKWebView alloc]initWithFrame:CGRectZero configuration:({
            // 创建配置类
            WKWebViewConfiguration *config=[WKWebViewConfiguration new];
            config;
        })];
        [_webView setFrame:CGRectMake(0, C_NavBarAndStatusBarHeight, C_ScreenWidth, C_ScreenHeight-C_NavBarAndStatusBarHeight)];
        // 设置dele <WKUIDelegate,WKNavigationDelegate>
        [_webView setUIDelegate:self];
        [_webView setNavigationDelegate:self];
        
        // 设置其他
        [_webView setBackgroundColor:[UIColor whiteColor]];
        [_webView.scrollView setShowsVerticalScrollIndicator:false];
        [_webView.scrollView setShowsHorizontalScrollIndicator:false];
    }
    return _webView;
}

常用属性/方法

获取常用信息

    // 标题(readOnly)
    NSString *title=webView.title;
    // url地址(readOnly)
    NSURL *URL=webView.URL;  
    // 是否正在加载(readOnly)
    BOOL loading=webView.isLoading 
    // 加载进度(readOnly)
    double estimatedProgress=webView.estimatedProgress;  
    // 是否加密(readOnly)
    BOOL hasOnlySecureContent=webView.hasOnlySecureContent; 
    // scrollView(readOnly)
    UIScrollView *scrollView=webView.scrollView;
加载请求

    // loadRequest
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];
    // 加载fileURL
    [webView loadFileURL:[NSURL URLWithString:@""] allowingReadAccessToURL:[NSURL URLWithString:@""]];
    // 加载data
    [webView loadData:[NSData data] MIMEType:@"" characterEncodingName:@"" baseURL:[NSURL URLWithString:@""]];
    // 加载本地html
    NSString *urlStr=[[NSBundle mainBundle]pathForResource:@"index.html" ofType:nil];
    [webView loadHTMLString:[NSString stringWithContentsOfFile:urlStr encoding:NSUTF8StringEncoding error:nil] baseURL:[NSURL URLWithString:urlStr]];
重新加载
    // 重新加载
    [webView reload];
    // 重新加载初始网址
    [webView reloadFromOrigin];
    // 停止加载
    [webView stopLoading];

预览
    // 设置 是否允许预览链接(默认:true)
    [webView setAllowsLinkPreview:true];
向前向后

    // 设置 是否支持手势前进后退(默认:false)
    [webView setAllowsBackForwardNavigationGestures:true];

    // 是否允许向后(readOnly)
    BOOL canGoBack=webView.canGoBack;
    // 是否允许向前(readOnly)
    BOOL canGoForward=webView.canGoForward;
    // 向后
    [webView goBack];
    // 向前
    [webView goForward];

    // 获取页面前进后退列表(readOnly)
    WKBackForwardList *list=webView.backForwardList;
    // 当前(readOnly)
    WKBackForwardListItem *item=list.currentItem;
    // 前一个(readOnly)
    WKBackForwardListItem *itemForward=list.forwardItem;
    // 后一个(readOnly)
    WKBackForwardListItem *itemBack=list.backItem;
    // 后列表(readOnly)
    NSArray *backList=list.backList;
    // 前列表(readOnly)
    NSArray *forwardList=list.forwardList;

    // 根据下标获取指定页
    WKBackForwardListItem *item=[list itemAtIndex:0];
    // 前进或后退到指定页
    [webView goToBackForwardListItem:item];

    // (readOnly)
    NSURL *URL=item.URL;
    NSURL *initialURL=item.initialURL;
    NSString *title=item.title;

dele

【OC调用js中的方法】
  [webView evaluateJavaScript:@"helloWorld" completionHandler:^(id _Nullable obj, NSError * _Nullable error) {}];


【js调用OC中的方法】
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // 首先设置交互(js调用OC),设置dele
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"helloWorld"];
}
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    // 最后移除交互
    [self.webView.configuration.userContentController removeAllUserScripts];
}

#pragma mark dele <WKScriptMessageHandler>        
// js调用OC方法后调用(required)
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    NSLog(@"js调用OC方法后调用");
    SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@:",message.name]);
    if ([self respondsToSelector:selector]) {
        [self performSelector:selector withObject:message.body];
    }
}
// js中这样调用 window.webkit.messageHandlers.helloWorld.postMessage({body: 'hello world!'});
-(void)helloWorld:(NSDictionary *)dic{
    NSLog(@"");
}
#pragma mark dele<WKUIDelegate>    都为可选方法

// =============== alert、confirm、prompt

// js中调用alert后调用
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
    NSLog(@"js中调用alert");
    /*
     message:alert中的内容
     */
    completionHandler();
}
// js中调用confirm后调用
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
    NSLog(@"js中调用confirm");
    /*
     message:confirm中的内容
     */
    // true确认,false取消
    completionHandler(true);
}
// js中调用prompt后调用
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
    NSLog(@"js中调用prompt");
    /*
     prompt:标题
     defaultText:默认文本
     */
    // 文本框中的填写内容
    completionHandler(@"你好");
}


// =============== 预览

// 是否允许预览(长安链接时触发预览)
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo{
    /*
     elementInfo.linkURL    预览的url
     */
    return true;
}
// 触发预览后调用,返回预览VC
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions{
    return [UIViewController new];
}
// 触发pop操作预览消失时调用
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController{
    NSLog(@"预览取消时调用");
}


// =============== 创建/关闭

// 创建新的webView后回调,调用window.open()创建新窗口后触发
-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
    
    // 必须使用configuration
    return [[WKWebView alloc]initWithFrame:CGRectZero configuration:configuration];
}
// 关闭当前webView后调用,调用window.close()触发
-(void)webViewDidClose:(WKWebView *)webView{
    NSLog(@"关闭webView");
}
#pragma mark dele<WKNavigationDelegate>      都为可选方法

// =============== 页面加载

// 页面开始加载时调用
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    NSLog(@"页面开始加载");
}
// 开始加载内容后调用
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    NSLog(@"页面开始加载内容");
}
// 页面加载完成后调用
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    NSLog(@"页面加载完成");
}
// 页面加载失败后调用
-(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    NSLog(@"页面加载失败");
}
// 页面加载内容中断时调用
-(void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
    NSLog(@"加载内容中断");
}


// =============== 跳转

// 是否允许跳转(发送request请求之前调用)
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    /*
     navigationAction.sourceFrame   原 WKFrameInfo(只读)
     navigationAction.targetFrame   目标 WKFrameInfo(只读)
     navigationAction.request       request(只读)
     navigationAction.navigationType    请求类型
        WKNavigationTypeLinkActivated,  // 链接href
        WKNavigationTypeFormSubmitted,  // 表单提交
        WKNavigationTypeBackForward,    // 返回
        WKNavigationTypeReload,         // 重新加载
        WKNavigationTypeFormResubmitted,// 表单重复提交
        WKNavigationTypeOther = -1,     // 其他
     
     WKNavigationActionPolicyAllow  允许
     WKNavigationActionPolicyCancel 拒绝
     */
    decisionHandler(WKNavigationActionPolicyAllow);
}
// 是否允许跳转(发送request请求并收到响应后)
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    /*
     navigationResponse.forMainFrame    是否是main frame(只读)
     navigationResponse.response        获取响应response(只读)

     
     WKNavigationResponsePolicyAllow    允许
     WKNavigationResponsePolicyCancel   拒绝
     */
    decisionHandler(WKNavigationResponsePolicyAllow);
}
// 重定向后调用(接收到服务器的跳转请求)
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
    NSLog(@"后端重定向");
}
// 跳转失败后调用
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    NSLog(@"跳转失败");
}
// https则调用
-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{
    /*
     NSURLSessionAuthChallengeUseCredential,                    使用(信任)证书
     NSURLSessionAuthChallengePerformDefaultHandling,           默认,忽略
     NSURLSessionAuthChallengeCancelAuthenticationChallenge,    取消
     NSURLSessionAuthChallengeRejectProtectionSpace,            这次取消,下载次还来问
     */
    // challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
    completionHandler(NSURLSessionAuthChallengeUseCredential,[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}

1.2 其他

WKWebViewConfiguration

    // 1.创建配置类
    WKWebViewConfiguration *config=[WKWebViewConfiguration new];
    // 1.1设置偏好设置
    config.preferences=({
        WKPreferences *pre=[WKPreferences new];
        [pre setMinimumFontSize:10];                            // 最小字体(默认:0)
        [pre setJavaScriptEnabled:true];                        // js是否可用(默认:true)
        [pre setJavaScriptCanOpenWindowsAutomatically:false];   // js是否能通过打开窗口 (默认:false)
        pre;
    });
    // 1.2设置内容处理池
    config.processPool=[WKProcessPool new];
    // 1.3设置交互(js调用OC)
    [config setUserContentController:({
        WKUserContentController *userC=[WKUserContentController new];
        // 添加交互,当收到js调用ssbb后 回调didReceiveScriptMessage <WKScriptMessageHandler>
        [userC addScriptMessageHandler:self name:@"ssbb"];
        
        userC;
    })];
    
    // ---------- 其他常用属性 start 可选----------
    // 设置 持久化
    // 一个WKWebsiteDataStore对象代表了被网页使用的各种类型的数据。包括cookies,磁盘文件,内存缓存以及持久化数据如WebSQL,IndexedDB数据库,local storage。
    [config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
    // 设置 在web全部加载到内存前是否阻止其显示
    [config setSuppressesIncrementalRendering:true];
    // 设置 UserAgent中的应用名称
    [config setApplicationNameForUserAgent:@""];
    // 设置 是否允许AirPlay播放媒体(默认:true)
    [config setAllowsInlineMediaPlayback:true];
    // 设置 是否忽略缩放属性(默认:false)覆盖网页中的user-scalable HTML属性
    [config setIgnoresViewportScaleLimits:true];
    // 设置 需要检测的数据类型(可对相应的类型做处理,如链接则可跳转)
    [config setDataDetectorTypes:WKDataDetectorTypeLink];
    /*
     WKDataDetectorTypeNone             不检测(默认)
     WKDataDetectorTypePhoneNumber      电话
     WKDataDetectorTypeLink             链接
     WKDataDetectorTypeAddress          地址
     WKDataDetectorTypeCalendarEvent    日历提醒事件
     WKDataDetectorTypeTrackingNumber   跟踪号码/查询号/运单号
     WKDataDetectorTypeFlightNumber     航班号
     WKDataDetectorTypeLookupSuggestion
     WKDataDetectorTypeAll              检测所有类型
     */
    // 设置 是否允许画中画播放?
    [config setAllowsPictureInPictureMediaPlayback:true];
    // 设置 选择内容的粒度级别
    [config setSelectionGranularity:WKSelectionGranularityDynamic];
    /*
     WKSelectionGranularityDynamic,     用户可自定义选择区域(默认)
     WKSelectionGranularityCharacter,   不可自定义选择区域
     */
    // 设置 是否使用在线的控制器(默认:false,使用本地的全屏控制器)
    [config setAllowsInlineMediaPlayback:true];
    // 设置 哪些视频需要用户手势才能自动播放
    [config setMediaTypesRequiringUserActionForPlayback:WKAudiovisualMediaTypeAll];
    /*
     WKAudiovisualMediaTypeNone     所有视频自动播放
     WKAudiovisualMediaTypeAudio    音频
     WKAudiovisualMediaTypeVideo    视频
     WKAudiovisualMediaTypeAll      所有都需要手势才能播放
     */
    //
    // ---------- 其他常用属性 end----------
2. UIWebView+原生框架(javascriptcore.framework)
  1. UIWebView 基础使用

UIWebView : UIView <NSCoding, UIScrollViewDelegate>

    // 创建
    UIWebView *webV=[UIWebView new];
    [self.view addSubview:webV];

加载url  
    // 方式一:加载 url
    [webV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@""]]];
    // 方式二:加载 htmlStr
    [webV loadHTMLString:@"<p>hello</p>" baseURL:nil];
    // 方式三:加载 nsdata 
    [webView loadData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1.docx" ofType:nil]] MIMEType:@"application/vnd.openxmlformats-officedocument.wordprocessingml.document" textEncodingName:@"UTF-8" baseURL:nil];
    /*
     1.docx
        application/vnd.openxmlformats-officedocument.wordprocessingml.document
     2.pdf
        application/pdf
     3.txt
        text/plain
     4.html
        text/html
     */


缓存
    // 注意:缓存只影响本地址,页面内其他链接地址不受影响。
    NSURLRequest *request=[[NSURLRequest requestWithURL:[NSURL URLWithString:@""] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10]];
    /*
     NSURLRequestUseProtocolCachePolicy = 0,        默认(使用缓存)
     
     NSURLRequestReloadIgnoringLocalCacheData = 1,  忽略本地缓存
     NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
     NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,    忽略本地缓存
     
     NSURLRequestReturnCacheDataElseLoad = 2,       返回缓存,缓存没有则请求网络
     NSURLRequestReturnCacheDataDontLoad = 3,       返回缓存,缓存没有则出错
     
     NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
     */
dele
    // dele<UIWebViewDelegate> 
    [webV setDelegate:self];

/**
  * 是否允许该request请求进行加载(加载前调用)
  *
  *  1、调用loadRequest等会调用
  *  2、调用goBack后会调用(request的缓存策略是NSURLRequestReturnCacheDataElseLoad)
  *  3、页面内点击其他链接会调用(request的缓存策略是NSURLRequestUseProtocolCachePolicy)
  *  4、重定向会调用
  */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ 

  return true;
/*
    UIWebViewNavigationTypeLinkClicked,      用户触击了一个链接
    UIWebViewNavigationTypeFormSubmitted,    用户提交了一个表单
    UIWebViewNavigationTypeBackForward,      用户触击前进或返回按钮
    UIWebViewNavigationTypeReload,           用户触击重新加载的按钮
    UIWebViewNavigationTypeFormResubmitted,  用户重复提交表单
    UIWebViewNavigationTypeOther             发生其它行为
*/
}
// 开始加载(网页内容)后调用
- (void)webViewDidStartLoad:(UIWebView *)webView{}
// (网页内容完全显示在控件上)加载完毕后调用
- (void)webViewDidFinishLoad:(UIWebView *)webView{

    // 获取web页面内容信息
    NSString *docStr=[webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
    /*
     JavaScript的执行时间被限定在10秒钟,如果执行时间超过10秒,那么页面就停止执行这个脚本。
     JavaScript的执行可能阻塞主线程,所以当脚本执行的时候不允许用户影响页面的加载。
     JavaScript的内存分配被限制在10M,如果超出这个限制那么页面会发生异常。
     */
}
// 加载失败后调用
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{}
前进后退
    // 获取 页面数量
    NSInteger pageCount=webV.pageCount;
    // 是否 可以回退
    BOOL isCanBack=[webV canGoBack];
    // 是否 可以前进
    BOOL isCanForward=[webV canGoForward];
    // 回退
    [webV goBack];
    // 前进
    [webV goForward];

重新加载
    // 是否 正在加载
    BOOL isLoading=[webV isLoading];
    // 重新加载(会重新调用shouldStartLoadWithRequest等)
    [webV reload];
    // 停止加载
    [webV stopLoading];


滚动条
    // 设置 是否显示纵向滚动条
    [webV.scrollView setShowsVerticalScrollIndicator:true];
    // 设置 是否显示横向滚动条
    [webV.scrollView setShowsHorizontalScrollIndicator:true];

显示
    // 是否网页内容下载完毕才开始渲染web视图,默认为NO
    @property (nonatomic) BOOL suppressesIncrementalRendering;
    // 是否允许长按链接预览(支持3D Touch的设备),default is NO
    @property (nonatomic) BOOL allowsLinkPreview;

    // 设置是否缩放到适合屏幕大小(默认:false)
    [webV setScalesPageToFit:true];


其他
    // 设置 是否允许media后台播放
    [webV setAllowsInlineMediaPlayback:true];
    // 获取scrollView(只读)
    UIScrollView *scrollView=webView.scrollView;
    // 获取NSURLRequest (只读)
    NSURLRequest *request=webView.request;


    // 翻页效果(当网页的大小超出view时,将网页以翻页的效果展示)
    @property (nonatomic) UIWebPaginationMode paginationMode;
    /*
     UIWebPaginationModeUnpaginated,    // 不使用翻页效果
     UIWebPaginationModeLeftToRight,    // 将网页超出部分分页,从左向右进行翻页
     UIWebPaginationModeTopToBottom,    // 将网页超出部分分页,从上向下进行翻页
     UIWebPaginationModeBottomToTop,    // 将网页超出部分分页,从下向上进行翻页
     UIWebPaginationModeRightToLeft     // 将网页超出部分分页,从右向左进行翻页
     */
    // 分页模式
    @property (nonatomic) UIWebPaginationBreakingMode paginationBreakingMode;
    /*
     UIWebPaginationBreakingModePage,
     UIWebPaginationBreakingModeColumn
     */
    // 每一页的长度
    @property (nonatomic) CGFloat pageLength;
    // 每一页的间距
    @property (nonatomic) CGFloat gapBetweenPages;
    // 是否在弹出键盘后允许用户交互,默认YES
    @property (nonatomic) BOOL keyboardDisplayRequiresUserAction;

音视频
    // 是否允许分屏播放
    @property (nonatomic) BOOL allowsPictureInPictureMediaPlayback;
    // 是否使用内嵌HTML5播放视频(还是用本地的全屏控制)。
    // 内嵌则HTML中的video元素必须包含webkit-playsinline属性。
    // iPhone Safari defaults to NO. iPad Safari defaults to YES
    @property (nonatomic) BOOL allowsInlineMediaPlayback;
    // 是否允许自动播放,默认为YES
    @property (nonatomic) BOOL mediaPlaybackRequiresUserAction;
    // 音频播放是否支持air play功能,默认为YES
    @property (nonatomic) BOOL mediaPlaybackAllowsAirPlay;
  1. UIWebView 原生交互
    OC中可以直接调用JS方法
    JS可通过拦截url间接调用OC
    #import <JavaScriptCore/JavaScriptCore.h>
    <UIWebViewDelegate>


        // 创建UIWebView
        UIWebView *webV=[UIWebView new];
        [self.view addSubview:webV];
        // 布局,,,
        // 
        [webV setScalesPageToFit:true];
        // 滚动速度:正常速,默认慢速
        [webV.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal];
        // loadRequest(加载网页)
        [webV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"url"]]];

dele

        // dele
        [webV setDelegate:self];

// 加载完成后调用
-(void)webViewDidFinishLoad:(UIWebView *)webView{

》》》》》OC调js
    // 初始化一些操作  (如:提交表单,插入内容,删除内容,修改内容,查询内容)
    [webView stringByEvaluatingJavaScriptFromString:@"js代码"];
    
举例:
    // 提交表单
    [webView stringByEvaluatingJavaScriptFromString:@"document.froms[0].submit();"];
    
    // 插入内容
    [webView stringByEvaluatingJavaScriptFromString:@" js 代码"];
    // 例:
    @"var script=document.createElement('script');"   // 可以是普通控件如img(.src .width .height)
    @"script.type='text/javascript';"
    @"script.text=\"function myFun(){"
    @"var f=document.getElementsByName(‘q’)[0];"
    @"f.value='11';"
    @"document.forms[0].submit();"
    @"}\";"
    @"document.getElementsByTagName('head')[0].appendChild(script);"
    
    // 删除内容
    [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('a').remove()"];
    
    // 修改内容值、显示值
    [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('a')[0].value='123'"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('a')[0].innerHTML='h123'"];
    
    // 查询内容
    // url
    NSString *urlStr=[webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
    // title : document.title


    // 禁用 页面元素选择
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];    
    // 禁用 长按弹出ActionSheet
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];





》》》》》 js调用OC    (方式一,原生JavaScriptCore.framework框架(iOS7))
    #import<JavaScriptCore/JavaScriptCore.h>  

    /* 2种方式:
        1、Block:暴露单个方法(不能直接使用JSValue、JSContext,造成循环引用)
        2、JSExport协议:暴露单个对象
     */

方式一(Block):
OC代码
     #import <JavaScriptCore/JavaScriptCore.h>
    // 获取 js代码的执行环境
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // Block (注册)
    context[@"js中的函数名"] = ^{
        NSArray *arg = [JSContext currentArguments];
    };
    context[@"js中的函数名"] = ^(NSDictionary *dic){
        NSLog(@"函数的实参值:%@", dic[@"color"]);
    };
js代码
    function testClick(){
        var str1=document.getElementById("text1").value;
        var str2=document.getElementById("text2").value;
        函数名(str1,str2);
    }
      
方式二(<JSExport>):
    实现协议遵守<JSExport>,JS中调用时(会将方法转为驼峰式,也可以使用宏JSExportAs(sbAdd,+(void)method:(int)a with:(int)b))此宏只对带参有效
    JS中调用:对象.属性 , 对象.方法   (不能在这增加成员变量)
}



// 是否允许加载网络请求
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{

》》》》》 js调用OC    (方式二,拦截url)
    //
    NSString *urlStr=request.URL.absoluteString;
    //
    NSRange range=[urlStr rangeOfString:@"ssbb://"];
    if(range.location!=NSNotFound){
    
        NSString *method=[urlStr substringFromIndex:range.location+range.length];
        [self performSelector:NSSelectorFromString(method)];
        return false;
    }
    
    return true;
}
// 开始加载后调用
-(void)webViewDidStartLoad:(UIWebView *)webView{}
// 加载失败后调用
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{}

注意事项

1.JS值的包装
        JS中的值拿到OC中是不能直接用的
        不能作为OC对象的属性

    JSValue *value=[context evalutateScript:@"2+2"];     [value toInt32];
    /*
     OC type            JS type
     
     nil                undefined
     NSNull             null
     NSString           string
     NSNumber           number,boolean
     NSDictionary       Object object
     NSArray            Array object
     NSDate             Date Object
     NSBlock            Function Object
     id                 Wrapper object
     Class              Constructor object
     */
3. WebViewJavascriptBridge框架(第三方框架)
    原理:拦截URL

         pod 'WebViewJavascriptBridge'
         #import "WebViewJavascriptBridge.h"
        // 基于WKWebView,则不用再设置WKWebView 的navigationDelegate(navDele为bridge)
        // 基于UIWebView,则不用再设置dele(dele为bridge)
        
        // 0.开启日志调试
        [WebViewJavascriptBridge enableLogging];
        // 1.创建WKWebView或UIWebView
        // 2.创建JavascriptBridge
        WebViewJavascriptBridge *_webViewBridge=[WebViewJavascriptBridge bridgeForWebView:webView];
        [_webViewBridge setWebViewDelegate:self];
        // 2.1配置
        // js调OC(注册多个handleName,用于js中调用)
        [_webViewBridge registerHandler:@"getUserIdFromOC" handler:^(id data, WVJBResponseCallback responseCallback) {
            // data
            // callBack
            if(responseCallback){
                responseCallback(@{@"userId":@"ssbb"});
            }
        }];
        // OC调js
        [_webViewBridge callHandler:@"getUserName" data:@{@"name":@"ssbb"} responseCallback:^(id responseData) {
            // responseData
        }];
~~~~~~~~JS

<script>    
      /*这段代码固定,必须要放到js中(第一次加载HTML时起作用,目的是加载一次wvjbscheme://__BRIDGE_LOADED__,注册JS方法)*/
      function setupWebViewJavascriptBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
      }
    
      /*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
      setupWebViewJavascriptBridge(function(bridge) {
       
       /*注册OC调JS*/
      bridge.registerHandler('openWebviewBridgeArticle', function() {
         log("openWebviewBridgeArticle was called with by ObjC")
      })
      /*注册OC调JS*/
      bridge.registerHandler('token', function(data, responseCallback) {
         log("G星爷: ", data)
         responseCallback({这里给我返回拼接后的地址})
      })

       /* 注册js调OC */
       document.getElementById('register').onclick = function () {
          bridge.callHandler('ww', {'blogdURL': 'weidsfdl'}, function(response) {
                          log('JS got response', response)
                          })
       }
     })
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351