最近项目里用到了web界面与js交互,项目使用的是UIWebView,但是会出现数据丢失的情况比较麻烦,使用WKWebView可以避免这种情况,下面就写一些web的基本使用,可能有些使用不当的地方,请指教。
* UIWebView
创建一个类文件,可以定义交互时的函数名,然后定义一个代理,在web界面调用进行相应的操作。
“`
//类的.h文件
# import
//类的.m文件
#import "KQJSModel.h"
#import "KQPayTypeViewController.h"
@implementation KQJSModel
-(void)startPay:(int)amount Action:(NSString *)action Teamid:(NSString *)teamid
{
NSLog(@"--------amount:%d---------action:%@------teamid:%@",amount,action,teamid);
if (self.delegate && [self.delegate respondsToSelector:@selector(goToPayVC:action:teamid:)]) {
[self.delegate goToPayVC:amount action:[NSString stringWithFormat:@"%@",action] teamid:[NSString stringWithFormat:@"%@",teamid]];
}
}
@end
//web界面,在代理方法里注入方法名,
-(void)webViewDidStartLoad:(UIWebView *)webView
{
//首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//第二种情况,js是通过对象调用的,我们假设js里面有一个对象 testobject 在调用方法
//首先创建我们新建类的对象,将他赋值给js的对象
KQJSModel *testJO=[[KQJSModel alloc] init];
testJO.delegate = self; //类的协议代理
context[@"IOSApp"]=testJO;
// 同样我们也用刚才的方式模拟一下js调用方法
// NSString *jsStr1=@"IOSApp.getBaseUrl()";
// [context evaluateScript:jsStr1];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//获取网页标题
NSString * htmlTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];;
NSLog(@"-----网页标题---%@",htmlTitle);
self.title = [NSString stringWithFormat:@"%@",htmlTitle];
//首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//第二种情况,js是通过对象调用的,我们假设js里面有一个对象 testobject 在调用方法
//首先创建我们新建类的对象,将他赋值给js的对象
KQJSModel *testJO=[[KQJSModel alloc] init];
testJO.delegate = self; //类的协议代理
context[@"IOSApp"]=testJO;
}
//再调用KQJSModel类的代理方法,在代理方法里实现想要的进行的操作。
#pragma mark -- KQJSModelDelegate
-(void)goToPayVC:(int)amount action:(NSString *)action teamid:(NSString *)teamid
{
//进行界面跳转,刷新,一定要在主线程里,不然会崩溃
dispatch_async(dispatch_get_main_queue(), ^{
KQPayTypeViewController *pay = [[KQPayTypeViewController alloc] init];
pay.money = [NSString stringWithFormat:@"%d",amount];
pay.action = [NSString stringWithFormat:@"%@",action];
pay.teamid = [NSString stringWithFormat:@"%@",teamid];
if (![action isEqualToString:@""] && action != nil) {
pay.vip = @"vip";
}
KQCommonNavController *nav = [[KQCommonNavController alloc]initWithRootViewController:pay];
[self presentViewController:nav animated:YES completion:nil];
});
}
以上就是UIWebView与js的交互,运行就可以进行相应的操作了。
- WKWebView
最近才看了WKWebView的使用,就感觉比UIWebView流畅写,然后自带的导航进度条,这个感觉很方便,下面是与js的简单的交互,有不正确的,请留言,谢谢~
#import "ViewController.h"
#import <WebKit/WebKit.h>
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()<WKUIDelegate,WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
@property (nonatomic, strong) WKWebView *wkWebView;
@property (nonatomic, strong) WKWebViewConfiguration *wkConfig;
/*
*1.添加UIProgressView属性
*/
@property (nonatomic, strong) UIProgressView *progressView;
@end
@implementation ViewController
#pragma mark - 初始化wkWebView
- (WKWebViewConfiguration *)wkConfig {
if (!_wkConfig) {
_wkConfig = [[WKWebViewConfiguration alloc] init];
_wkConfig.allowsInlineMediaPlayback = YES;
_wkConfig.allowsPictureInPictureMediaPlayback = YES;
_wkConfig.processPool = [[WKProcessPool alloc] init];
[_wkConfig.userContentController addScriptMessageHandler:self name:@"AppModel"]; //注入的js函数名,
}
return _wkConfig;
}
- (WKWebView *)wkWebView {
if (!_wkWebView) {
_wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight) configuration:self.wkConfig];
// 导航代理
_wkWebView.navigationDelegate = self;
// 与webview UI交互代理
_wkWebView.UIDelegate = self;
[self.view addSubview:_wkWebView];
}
return _wkWebView;
}
/*
*6.在dealloc中取消监听
*/
- (void)dealloc {
[self.wkWebView removeObserver:self forKeyPath:@"estimatedProgress"];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self startLoad];
/*
*2.初始化progressView
*/
self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 64, [[UIScreen mainScreen] bounds].size.width, 2)];
self.progressView.backgroundColor = [UIColor blueColor];
//设置进度条的高度,下面这句代码表示进度条的宽度变为原来的1倍,高度变为原来的1.5倍.
self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
[self.view addSubview:self.progressView];
/*
*3.添加KVO,WKWebView有一个属性estimatedProgress,就是当前网页加载的进度,所以监听这个属性。
*/
[self.wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
UIButton *bavkBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 16, 20)];
[bavkBtn setImage:[UIImage imageNamed:@"navback"] forState:UIControlStateNormal];
[bavkBtn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithCustomView:bavkBtn];
self.navigationItem.leftBarButtonItem = left;
}
- (void)back{
if ([self.wkWebView canGoBack]) {
[self.wkWebView goBack];
}
}
#pragma mark - start load web
- (void)startLoad {
NSString *urlString = @"http://www.baidu.com";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
request.timeoutInterval = 15.0f;
[self.wkWebView loadRequest:request];
}
#pragma mark - 监听
/*
*4.在监听方法中获取网页加载的进度,并将进度赋给progressView.progress
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"estimatedProgress"]) {
self.progressView.progress = self.wkWebView.estimatedProgress;
if (self.progressView.progress == 1) {
/*
*添加一个简单的动画,将progressView的Height变为1.4倍
*动画时长0.25s,延时0.3s后开始动画
*动画结束后将progressView隐藏
*/
__weak typeof (self)weakSelf = self;
[UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.4f);
} completion:^(BOOL finished) {
weakSelf.progressView.hidden = YES;
}];
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - WKWKNavigationDelegate Methods
/*
*5.在WKWebViewd的代理中展示进度条,加载完成后隐藏进度条
*/
//开始加载
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
NSLog(@"开始加载网页");
//开始加载网页时展示出progressView
self.progressView.hidden = NO;
//开始加载网页的时候将progressView的Height恢复为1.5倍
self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
//防止progressView被网页挡住
[self.view bringSubviewToFront:self.progressView];
}
//加载完成
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
NSLog(@"加载完成");
}
//加载失败
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
NSLog(@"加载失败");
//加载失败同样需要隐藏progressView
self.progressView.hidden = YES;
}
//页面跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
//允许页面跳转
NSLog(@"%@",navigationAction.request.URL);
decisionHandler(WKNavigationActionPolicyAllow);
}
#pragma mark - WKUIDelegate
- (void)webViewDidClose:(WKWebView *)webView {
NSLog(@"%s", __FUNCTION__);
}
// 在JS端调用alert函数时,会触发此代理方法。
// JS端调用alert时所传的数据可以通过message拿到
// 在原生得到结果后,需要回调JS,是通过completionHandler回调
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
// JS端调用confirm函数时,会触发此方法
// 通过message可以拿到JS端所传的数据
// 在iOS端显示原生alert得到YES/NO后
// 通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
NSLog(@"%s", __FUNCTION__);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
}
// JS端调用prompt函数时,会触发此方法
// 要求输入一段文本
// 在原生输入得到文本内容后,通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
NSLog(@"%s", __FUNCTION__);
NSLog(@"%@", prompt);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.textColor = [UIColor redColor];
}];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
}