博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UIWebView 操作
阅读量:4508 次
发布时间:2019-06-08

本文共 20846 字,大约阅读时间需要 69 分钟。

网络开发中,当公司已经使用 HTML5 技术实现同时适应 Android 和 iOS 等多个平台的网页时,这时往往需要我们 iOS 平台能够嵌入网页并进行各种交互,那我们应该怎么做来实现这种需求呢?

这里我们考虑的方案就是:使用 UIWebView 网页控件

 

然而考虑使用 UIWebView 进行混合编程的场景特点有:

(1)排版复杂:通常包括图片和文字的混排,还有可能包括链接需要支持点击操作。如果自己用原生控件拼装实现,由于界面元素过多,做起来会很困难。就算是使用 CoreText 来实现,也需要自己实现相当多的复杂排版逻辑。

(2)界面的变动需求频繁:例如淘宝 App 的彩票页面,可能常常需要更新界面以推出不同的活动。采用 UIWebView 嵌套页面实现后,这类页面不需要向 App Store 提交新的版本就可以动态地更新,而原生控件实现的界面很难达到如此高的灵活性。

(3)界面对用户的交互需求不复杂:因为 UIWebView 实现的交互效果与原生效果相比还是会大打折扣,所以这类界面通常都没有复杂的交互效果。这也是主流 App 大多采用混合 UIWebView 来实现界面而不是使用纯 UIWebView 来实现界面的原因之一,另外的原因是纯 UIWebView 实现的性能也没原生的好,而且纯 UIWebView 实现的话根本无法通过 App Store 的审核,他会建议您搞 Web App。

 

本随笔简单介绍如何使用 UIWebView 网页控件:

(1)简单浏览器

  •  读取本地资源文件

  •  读取网站内容

  • KenmuHuang 读取百度搜索网站相关查询内容

(2)页面交互;可以考虑使用模版引擎库 GRMustache:,方便阅读和更改渲染内容

(3)页面调用 OC 方法;可以考虑使用 JS 与 OC 交互库「WebViewJavascriptBridge」:,方便 JS 与 OC 之间发送消息进行交互

 

效果如下:

 

 

ViewController.h

1 #import 
2 3 @interface ViewController : UITableViewController4 @property (copy, nonatomic) NSArray *arrSampleName;5 6 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName;7 8 @end 

ViewController.m

1 #import "ViewController.h" 2 #import "SimpleBrowserViewController.h" 3 #import "PageInteractionViewController.h" 4 #import "PageCallOCFunctionViewController.h" 5  6 @interface ViewController () 7 - (void)layoutUI; 8 @end 9 10 @implementation ViewController11 - (void)viewDidLoad {12     [super viewDidLoad];13     14     [self layoutUI];15 }16 17 - (void)didReceiveMemoryWarning {18     [super didReceiveMemoryWarning];19     // Dispose of any resources that can be recreated.20 }21 22 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName {23     if (self = [super initWithStyle:UITableViewStyleGrouped]) {24         self.navigationItem.title = @"UIWebView 操作";25         self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];26         27         _arrSampleName = arrSampleName;28     }29     return self;30 }31 32 - (void)layoutUI {33     34 }35 36 #pragma mark - UITableViewController相关方法重写37 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {38     return 0.1;39 }40 41 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {42     return 1;43 }44 45 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {46     return [_arrSampleName count];47 }48 49 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {50     static NSString *cellIdentifier = @"cell";51     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];52     if (!cell) {53         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];54     }55     cell.textLabel.text = _arrSampleName[indexPath.row];56     return cell;57 }58 59 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {60     switch (indexPath.row) {61         case 0: {62             SimpleBrowserViewController *simpleBrowserVC = [SimpleBrowserViewController new];63             [self.navigationController pushViewController:simpleBrowserVC animated:YES];64             break;65         }66         case 1: {67             PageInteractionViewController *pageInteractionVC = [PageInteractionViewController new];68             [self.navigationController pushViewController:pageInteractionVC animated:YES];69             break;70         }71         case 2: {72             PageCallOCFunctionViewController *pageCallOCFunctionVC = [PageCallOCFunctionViewController new];73             [self.navigationController pushViewController:pageCallOCFunctionVC animated:YES];74             break;75         }76         default:77             break;78     }79 }80 81 @end 

PrefixHeader.pch

1 #define kTitleOfSimpleBrowser @"简单浏览器"2 #define kTitleOfPageInteraction @"页面交互"3 #define kTitleOfPageCallOCFunction @"页面调用 OC 方法"4 5 #define kApplication [UIApplication sharedApplication] 

SimpleBrowserViewController.h

1 #import 
2 3 @interface SimpleBrowserViewController : UIViewController
4 @property (strong, nonatomic) UISearchBar *searchBar; 5 @property (strong, nonatomic) UIWebView *webView; 6 @property (strong, nonatomic) UIToolbar *toolbar; 7 @property (strong, nonatomic) UIBarButtonItem *barBtnBack; 8 @property (strong, nonatomic) UIBarButtonItem *barBtnForward; 9 10 @end 

SimpleBrowserViewController.m

1 #import "SimpleBrowserViewController.h"  2   3 @interface SimpleBrowserViewController ()  4 - (void)webViewBack;  5 - (void)webViewForward;  6 - (void)layoutUI;  7 - (void)sendRequest:(NSString *)requestURLStr;  8 - (void)changeBarButtonStatus;  9 @end 10  11 @implementation SimpleBrowserViewController 12  13 - (void)viewDidLoad { 14     [super viewDidLoad]; 15      16     [self layoutUI]; 17 } 18  19 - (void)didReceiveMemoryWarning { 20     [super didReceiveMemoryWarning]; 21     // Dispose of any resources that can be recreated. 22 } 23  24 - (void)webViewBack { 25     [_webView goBack]; 26 } 27  28 - (void)webViewForward { 29     [_webView goForward]; 30 } 31  32 - (void)layoutUI { 33     self.navigationItem.title = kTitleOfSimpleBrowser; 34     self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移 35      36     CGRect rect = [[UIScreen mainScreen] bounds]; 37     static const CGFloat heightOfStatusBarAndNavigationBar = 64.0; 38     CGFloat widthOfScreen = rect.size.width; 39     CGFloat heightOfScreen  = rect.size.height; 40      41     //添加搜索栏 42     _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar, widthOfScreen, 44.0)]; 43     _searchBar.delegate = self; 44     _searchBar.placeholder = @"请输入以file://或http开头的地址"; 45     [self.view addSubview:_searchBar]; 46      47     //添加工具栏和左右按钮(回退和前进) 48     _toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, heightOfScreen - 44.0, 49                                                            widthOfScreen, 44.0)]; 50     rect = CGRectMake(0.0, 0.0, 32.0, 32.0); 51     UIButton *btnBack = [UIButton buttonWithType:UIButtonTypeCustom]; 52     btnBack.frame = rect; 53     [btnBack setImage:[UIImage imageNamed:@"LastPageNormal"] forState:UIControlStateNormal]; 54     [btnBack setImage:[UIImage imageNamed:@"LastPageDisabled"] forState:UIControlStateDisabled]; 55     [btnBack addTarget:self 56                 action:@selector(webViewBack) 57       forControlEvents:UIControlEventTouchUpInside]; 58     _barBtnBack = [[UIBarButtonItem alloc] initWithCustomView:btnBack]; 59     _barBtnBack.enabled = NO; 60      61     UIBarButtonItem *barBtnSpacing=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 62      63     UIButton *btnForward = [UIButton buttonWithType:UIButtonTypeCustom]; 64     btnForward.frame = rect; 65     [btnForward setImage:[UIImage imageNamed:@"NextPageNormal"] forState:UIControlStateNormal]; 66     [btnForward setImage:[UIImage imageNamed:@"NextPageDisabled"] forState:UIControlStateDisabled]; 67     [btnForward addTarget:self 68                    action:@selector(webViewForward) 69          forControlEvents:UIControlEventTouchUpInside]; 70     _barBtnForward = [[UIBarButtonItem alloc] initWithCustomView:btnForward]; 71     _barBtnForward.enabled = NO; 72      73     _toolbar.items = @[ _barBtnBack, barBtnSpacing, _barBtnForward ]; 74     [self.view addSubview:_toolbar]; 75      76     //添加网页控件 77     CGFloat heightOfWebView = heightOfScreen - _searchBar.frame.origin.y - _searchBar.frame.size.height - _toolbar.frame.size.height; 78     _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar + _searchBar.frame.size.height, 79                                                            widthOfScreen, heightOfWebView)]; 80     _webView.dataDetectorTypes = UIDataDetectorTypeAll; 81     _webView.delegate = self; 82     [self.view addSubview:_webView]; 83 } 84  85 - (void)sendRequest:(NSString *)requestURLStr { 86     if (requestURLStr.length > 0) { 87         NSURL *requestURL; 88          89         //加载bundle中的文件;网页控件打开本地pdf、word文件依靠的并不是他自身解析,而是依靠MIME Type识别文件类型并调用对应应用打开 90         if ([requestURLStr hasPrefix:@"file://"]) { 91             NSRange range = [requestURLStr rangeOfString:@"file://"]; 92             NSString *fileName = [requestURLStr substringFromIndex:range.length]; 93             requestURL = [[NSBundle mainBundle] URLForResource:fileName 94                                                  withExtension:nil]; 95         } else { 96             //加载百度搜索网站的内容 97             if (![requestURLStr hasPrefix:@"http"]) { 98                 requestURLStr = [NSString stringWithFormat:@"https://www.baidu.com/s?wd=%@", requestURLStr]; 99             }100             //最终加载的还是HTTP或者HTTPS协议的网站内容,进行编码操作101             requestURLStr = [requestURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];102             requestURL = [NSURL URLWithString:requestURLStr];103         }104         105         //加载请求地址内容106         [_webView loadRequest:[NSURLRequest requestWithURL:requestURL]];107     }108 }109 110 - (void)changeBarButtonStatus {111     _barBtnBack.enabled = _webView.canGoBack;112     _barBtnForward.enabled = _webView.canGoForward;113 }114 115 #pragma mark - UIWebViewDelegate116 - (void)webViewDidStartLoad:(UIWebView *)webView {117     kApplication.networkActivityIndicatorVisible = YES;118 }119 120 - (void)webViewDidFinishLoad:(UIWebView *)webView {121     kApplication.networkActivityIndicatorVisible = NO;122     [self changeBarButtonStatus];123 }124 125 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {126     NSLog(@"Error: %@", error);127     kApplication.networkActivityIndicatorVisible = NO;128     UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"129                                                            message:@"网络连接错误"130                                                           delegate:nil131                                                  cancelButtonTitle:@"确定"132                                                  otherButtonTitles:nil, nil];133     [alertVCustom show];134 }135 136 #pragma mark - UISearchBarDelegate137 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {138     [self sendRequest:searchBar.text];139     [_searchBar resignFirstResponder];140 }141 142 @end 

PageInteractionViewController.h

1 #import 
2 3 @interface PageInteractionViewController : UIViewController
4 @property (strong, nonatomic) UIWebView *webView;5 6 @end 

PageInteractionViewController.m

1 #import "PageInteractionViewController.h" 2  3 @interface PageInteractionViewController () 4 - (void)layoutUI; 5 - (void)sendRequest; 6 @end 7  8 @implementation PageInteractionViewController 9 10 - (void)viewDidLoad {11     [super viewDidLoad];12     13     [self layoutUI];14     15     [self sendRequest];16 }17 18 - (void)didReceiveMemoryWarning {19     [super didReceiveMemoryWarning];20     // Dispose of any resources that can be recreated.21 }22 23 - (void)layoutUI {24     self.navigationItem.title = kTitleOfPageInteraction;25     self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移26     27     CGRect rect = [[UIScreen mainScreen] bounds];28     static const CGFloat heightOfStatusBarAndNavigationBar = 64.0;29     //添加网页控件30     _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar,31                                                            rect.size.width, rect.size.height - heightOfStatusBarAndNavigationBar)];32     _webView.dataDetectorTypes = UIDataDetectorTypeAll;33     _webView.delegate = self;34     self.automaticallyAdjustsScrollViewInsets = NO;35     [self.view addSubview:_webView];36 }37 38 - (void)sendRequest {39     NSString *htmlStr=@"\40                             KenmuHuang's Blog\41                             \42                                 

I'm KenmuHuang

\43

More coding, more thinking. Stay hungry, stay foolish.

\44 http://www.cnblogs.com/huangjianwu/\45 \46 ";47 [_webView loadHTMLString:htmlStr baseURL:nil];48 }49 50 #pragma mark - UIWebViewDelegate51 - (void)webViewDidStartLoad:(UIWebView *)webView {52 kApplication.networkActivityIndicatorVisible = YES;53 }54 55 - (void)webViewDidFinishLoad:(UIWebView *)webView {56 kApplication.networkActivityIndicatorVisible = NO;57 NSLog(@"%@",[_webView stringByEvaluatingJavaScriptFromString:@"document.title"]); //打印内容为html的title标签内容:KenmuHuang's Blog58 NSLog(@"%@",[_webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('header').innerHTML='KenmuHuang\\'s Blog';"]); //必须使用双反斜杆来转译单引号59 }60 61 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {62 NSLog(@"Error: %@", error);63 kApplication.networkActivityIndicatorVisible = NO;64 UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"65 message:@"网络连接错误"66 delegate:nil67 cancelButtonTitle:@"确定"68 otherButtonTitles:nil, nil];69 [alertVCustom show];70 }71 72 @end 

RedirectURL.js

1 function showSheet(title, cancelButtonTitle, destructiveButtonTitle, otherButtonTitle) { 2     var url = 'KMActionSheet://?'; 3     var paramas = title + '&' + cancelButtonTitle + '&' + destructiveButtonTitle; 4     if(otherButtonTitle) { 5         paramas += '&' + otherButtonTitle; 6     } 7     window.location.href = url + encodeURIComponent(paramas); 8 } 9 10 var header = document.getElementById('header');11 if(header) {12     header.onclick = function(){13         showSheet('系统提示', '取消', '确定', null);14     };15 } 

PageCallOCFunctionViewController.h

1 #import 
2 3 @interface PageCallOCFunctionViewController : UIViewController
4 @property (strong, nonatomic) UIWebView *webView;5 6 @end 

PageCallOCFunctionViewController.m

1 #import "PageCallOCFunctionViewController.h"  2   3 @interface PageCallOCFunctionViewController ()  4 - (void)layoutUI;  5 - (void)sendRequest;  6 - (void)showActionSheetWithTitle:(NSString *)title cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitle:(NSString *)otherButtonTitle;  7 @end  8   9 @implementation PageCallOCFunctionViewController 10  11 - (void)viewDidLoad { 12     [super viewDidLoad]; 13      14     [self layoutUI]; 15      16     [self sendRequest]; 17 } 18  19 - (void)didReceiveMemoryWarning { 20     [super didReceiveMemoryWarning]; 21     // Dispose of any resources that can be recreated. 22 } 23  24 - (void)layoutUI { 25     self.navigationItem.title = kTitleOfPageCallOCFunction; 26     self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移 27      28     CGRect rect = [[UIScreen mainScreen] bounds]; 29     static const CGFloat heightOfStatusBarAndNavigationBar = 64.0; 30     //添加网页控件 31     _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar, 32                                                            rect.size.width, rect.size.height - heightOfStatusBarAndNavigationBar)]; 33     _webView.dataDetectorTypes = UIDataDetectorTypeAll; 34     _webView.delegate = self; 35     self.automaticallyAdjustsScrollViewInsets = NO; 36     [self.view addSubview:_webView]; 37 } 38  39 - (void)sendRequest { 40     NSString *htmlStr=@"\ 41     KenmuHuang's Blog\ 42     \ 43     

I'm KenmuHuang, click me to show action sheet.

\ 44

More coding, more thinking. Stay hungry, stay foolish.

\ 45 http://www.cnblogs.com/huangjianwu/\ 46 \ 47 "; 48 [_webView loadHTMLString:htmlStr baseURL:nil]; 49 } 50 51 - (void)showActionSheetWithTitle:(NSString *)title cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitle:(NSString *)otherButtonTitle{ 52 UIActionSheet *actionSheet=[[UIActionSheet alloc] initWithTitle:title 53 delegate:nil 54 cancelButtonTitle:cancelButtonTitle 55 destructiveButtonTitle:destructiveButtonTitle 56 otherButtonTitles:otherButtonTitle, nil]; 57 [actionSheet showInView:self.view]; 58 } 59 60 #pragma mark - UIWebViewDelegate 61 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { 62 BOOL isStartLoad = YES; 63 if ([request.URL.scheme isEqualToString:@"kmactionsheet"]) { //request.URL.scheme 返回全小写的内容 64 NSString *paramContent = request.URL.query; 65 NSArray *arrParam = [[paramContent stringByRemovingPercentEncoding] componentsSeparatedByString:@"&"]; 66 NSString *otherButtonTitle = nil; 67 if (arrParam.count > 3) { 68 otherButtonTitle = arrParam[3]; 69 } 70 71 [self showActionSheetWithTitle:arrParam[0] 72 cancelButtonTitle:arrParam[1] 73 destructiveButtonTitle:arrParam[2] 74 otherButtonTitle:otherButtonTitle]; 75 isStartLoad = NO; 76 } 77 return isStartLoad; 78 } 79 80 - (void)webViewDidStartLoad:(UIWebView *)webView { 81 kApplication.networkActivityIndicatorVisible = YES; 82 } 83 84 - (void)webViewDidFinishLoad:(UIWebView *)webView { 85 kApplication.networkActivityIndicatorVisible = NO; 86 87 //加载用于重定向地址的JavaScript内容 88 NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"RedirectURL.js" ofType:nil]; 89 NSString *jsContent = [NSString stringWithContentsOfFile:jsPath 90 encoding:NSUTF8StringEncoding 91 error:nil]; 92 [_webView stringByEvaluatingJavaScriptFromString:jsContent]; 93 } 94 95 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 96 NSLog(@"Error: %@", error); 97 kApplication.networkActivityIndicatorVisible = NO; 98 UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息" 99 message:@"网络连接错误"100 delegate:nil101 cancelButtonTitle:@"确定"102 otherButtonTitles:nil, nil];103 [alertVCustom show];104 }105 106 @end 

AppDelegate.h

1 #import 
2 3 @interface AppDelegate : UIResponder
4 5 @property (strong, nonatomic) UIWindow *window;6 @property (strong, nonatomic) UINavigationController *navigationController;7 8 @end 

AppDelegate.m

1 #import "AppDelegate.h" 2 #import "ViewController.h" 3  4 @interface AppDelegate () 5  6 @end 7  8 @implementation AppDelegate 9 10 11 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {12     _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];13     ViewController *viewController = [[ViewController alloc]14                                       initWithSampleNameArray:@[ kTitleOfSimpleBrowser,15                                                                  kTitleOfPageInteraction,16                                                                  kTitleOfPageCallOCFunction ]];17     _navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];18     _window.rootViewController = _navigationController;19     //[_window addSubview:_navigationController.view]; //当_window.rootViewController关联时,这一句可有可无20     [_window makeKeyAndVisible];21     return YES;22 }23 24 - (void)applicationWillResignActive:(UIApplication *)application {25 }26 27 - (void)applicationDidEnterBackground:(UIApplication *)application {28 }29 30 - (void)applicationWillEnterForeground:(UIApplication *)application {31 }32 33 - (void)applicationDidBecomeActive:(UIApplication *)application {34 }35 36 - (void)applicationWillTerminate:(UIApplication *)application {37 }38 39 @end

  

转载于:https://www.cnblogs.com/huangjianwu/p/4847132.html

你可能感兴趣的文章
Linux下vim上编辑实现进度条
查看>>
ubuntu 设置plank开机自启之后关机键失效变为注销键
查看>>
JS--我发现,原来你是这样的JS(三)(基础概念--灵魂篇)
查看>>
手指滑动切换手机图片
查看>>
解决Oracle EM无法启动
查看>>
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
查看>>
PHP 跨域资源共享 CORS 设定
查看>>
男神鹏:使用Redis 的一些 问题解决方案。
查看>>
创建空间参考
查看>>
TestFlight下载app 初使用
查看>>
promise学习
查看>>
在vagrant官网下载各种最新.box资源
查看>>
selenium+python自动化95-弹出框死活定位不到
查看>>
关于防止用户表单多次提交方案的思考
查看>>
MAC终端显示tree命令
查看>>
Dissecting the First C# Program "HelloWorld"
查看>>
多线程--生产者消费者--简单例子
查看>>
Mac 安装tensorflow
查看>>
jsoup html解析器 实现对博客园博文标题链接抓取
查看>>
数据库面试题
查看>>