我們知道,在iOS開發過程中,有時候會用webview加載一張網頁,網頁上有一些按鈕或者其他的一些鏈接,要使這些按鈕有實際的作用,1??要麼就是網頁部分在HTML文件內部自己實現方法,2??要麼就是通過OC和網頁的交互,在本app內OC實現點擊網頁的按鈕,可以觸發自己OC寫的方法。
下面我講兩種常用的方法。
第一種是遵守webview的協議,通過實現協議方法截取網絡請求,通過這個截取到的網絡請求進行解析,然後實現自己的方法。
第二種方法是用了一個叫WebViewJavascriptBridge 的第三方庫進行橋接,這個方法就比較強大了,它既可以在oc部分寫實現代碼,也可以在網頁JS部分寫實現代碼。
這個庫的下載地址為:(裡面有demo,可以學著看看)
github上的下載地址
好了現在先上圖,說明一下,現在的網頁上的按鈕和我本app內部,需要做哪些交互。
此頁面為webview加載的圖片,要做的便是分別點擊這5個按鈕(Facebook分享、QQ分享、微信分享、短信分享、郵件分享)在app內部得到響應。分享集成部分再次就不多說了,謝謝。
方法一:webview協議截取網絡請求
app部分(OC部分)
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView * webview = [[UIWebView alloc]initWithFrame:self.view.bounds];
webview.delegate = self;
//http://127.0.0.1/WEB/initHtml.html 是我放在自己服務器的網頁文件
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/WEB/initHtml.html"]]];
[self.view addSubview:webview];
}
#pragma mark ---webview協議方法
#pragma mark ---攔截web網絡請求
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//獲取自己的網絡請求的網址字符串
NSString *url = request.URL.absoluteString;
//自己定義的協議前綴 網頁部分一會兒也是要設置成這個協議!
NSString *scheme = @"xmg://";
//打印出自己獲取的網絡請求的網址是什麼
NSLog(@"~~~~~ %@",url);
//解析網址前綴是否為@"xmg://"
if ([url hasPrefix:scheme])
{
//截出方法名
NSString *actionName = [url substringFromIndex:scheme.length];、
//動態方法選擇器 比如我獲取的網址是xmg://mailShare 則會執行mailShare這個方法
[self performSelector:NSSelectorFromString(actionName) withObject:nil];
//不加載這個網絡請求的頁面
return NO;
}
//YES:加載這個網絡請求的頁面
return YES;
}
-(void)mailShare{
NSLog(@"1shareMail");
}
-(void)facebookShare{
NSLog(@"facebookShare");
}
網頁部分#import "ViewController.h"
#import "WebViewJavascriptBridge.h"
@interface ViewController ()
//聲明`WebViewJavascriptBridge`對象為屬性
@property (nonatomic,strong) WebViewJavascriptBridge * bridge;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
if (_bridge) { return; }
//用UIWebView加載web網頁
UIWebView * webview = [[UIWebView alloc]initWithFrame:self.view.bounds];
webview.delegate = self;
[self.view addSubview:webview];
//設置能夠進行橋接
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webview];
[_bridge registerHandler:@"facebookObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======FacebookObjcCallback ========= %@", data);
//傳話給網頁說已經接收到
responseCallback(@"facebookObjcCallback回復網頁,已經收到消息");
//
}];
[_bridge registerHandler:@"QQShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======QQShareObjcCallback ========= %@", data);
//傳話給網頁說已經接收到
responseCallback(@"QQShareObjcCallback回復網頁,已經收到消息");
}];
[_bridge registerHandler:@"WXShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======WXShareObjcCallback ========= %@", data);
//傳話給網頁說已經接收到
responseCallback(@"WXShareObjcCallback回復網頁,已經收到消息");
//
}];
[_bridge registerHandler:@"MessageShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MessageShareObjcCallback ========= %@", data);
//傳話給網頁說已經接收到
responseCallback(@"MessageShareObjcCallback回復網頁,已經收到消息");
//
}];
[_bridge registerHandler:@"MailShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MailShareObjcCallback ========= %@", data);
//傳話給網頁說已經接收到
responseCallback(@"MailShareObjcCallback回復網頁,已經收到消息");
//
}];
// oc傳話給JS(網頁執行) 網頁部分會執行以下代碼:
/*
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
接收
*/
//網頁接收OC的方法句柄名叫testJavascriptHandler 此時OC給JS傳的數據是@{ @"foo":@"before ready" }
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
// 自定義按鈕 此處沒用,需要的可以自己打開使用
// [self renderButtons:webView];
//當你沒有把網頁放入服務器的話,可以把網頁放在本地工程,這個時候就要執行以下的方法,用NSBoundle加載本地文件
// [self loadExamplePage:webview];
}
//自定義按鈕
- (void)renderButtons:(UIWebView*)webView {
UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[callbackButton setTitle:@"呼叫JS的Handle" forState:UIControlStateNormal];
[callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:callbackButton aboveSubview:webView];
callbackButton.frame = CGRectMake(10, 400, 100, 35);
callbackButton.titleLabel.font = font;
}
//可以通過自定義按鈕實現方法,動態和JS進行交互
//注:本代碼中沒有寫按鈕去實現此方法,需要的同學可以自己去定義按鈕實現此方法
- (void)callHandler:(id)sender {
id data = @{ @"OC第一次發信息給JS": @"Hi there, JS,I am OC !" };
// testJavascriptHandler是JS部分接收OC傳送消息的方法句柄
// data 是OC給JS傳的數據
// response是JS接收到消息後給OC傳的數據
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
NSLog(@"JS收到消息後,回復給OC的消息為: %@", response);
}];
}
//加載本地網頁
//本代碼中的網頁是從服務器獲取,不是放在本地,放在本地的同學,可以用以下的方法加載
- (void)loadExamplePage:(UIWebView*)webView {
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"codetest" ofType:@"html"];
NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
[webView loadHTMLString:appHtml baseURL:baseURL];
}
2.網頁部分(JS部分)
①在script標簽內寫橋接方法
②在a標簽內記得表面id唯一標示,以便script能夠獲取此標簽元素
<script>
window.onerror = function(err) {
log('window.onerror: ' + err)
}
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)
}
setupWebViewJavascriptBridge(function(bridge) {
// JS注冊接收消息的部分 名字叫testJavascriptHandler
// function是接收消息後做的處理
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
var responseData = { 'Javascript Says':'Right back atcha!'};
//給OC的消息回執
responseCallback(responseData);
});
document.body.appendChild(document.createElement('br'));
//facebook連接出發方法
var facebookButton = document.getElementById('Facebook');
facebookButton.onclick = function(e) {
e.preventDefault();
//橋接呼叫OC句柄:facebookObjcCallback
//並傳送數據{'foo': 'bar'}過去
bridge.callHandler('facebookObjcCallback', {'foo': 'bar'}, function(response) {
//JS接收到OC的消息回執
});
};
var QQShareBtn = document.getElementById('QQShare')
QQShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('QQShareObjcCallback',{'QQ':'share'},function(response){
});
};
var wxShareBtn = document.getElementById('WXShare')
wxShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('WXShareObjcCallback',{'WX':'share'},function(response){
});
};
var messageShareBtn = document.getElementById('MessageShare')
messageShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('MessageShareObjcCallback',{'Message':'share'},function(response){
});
};
var mailShareBtn = document.getElementById('MailShare')
mailShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('MailShareObjcCallback',{'Mail':'share'},function(response){
});
};
});
</script>
來分享給好友!
總結:
1??利用橋接的話,就可以進行雙方的通信,JS部分可以做回執處理,OC部分也可以做回執處理。
注意點就是JS的Handle要命名好,OC部分的Handle也要命名好,不要搞混淆。
2??而利用webview的協議方法的話,好處是只要雙方規定了某一個協議,比如xmg://或其他,
單方面在OC處的webview協議方法解決,解析截取到的網絡請求,這種方法實現起來比較快捷,
壞處就是,JS得不到回執啦(但好像也不是什麼壞處)~
大家根據自己的需求選擇自己適合的方法吧,謝謝大家能夠看完!