Метод делегата UIWebView долженStartLoadWithRequest: эквивалент в WKWebView?
У меня есть модуль внутри моего приложения iOS 7+, которое является UIWebView. На странице html загружается javascript, который создает пользовательские кнопки (используя библиотеку Raphaeljs). С помощью UIWebView я устанавливаю делегат самостоятельно. Метод делегата webView: shouldStartLoadWithRequest: navigationType:
вызывается каждый раз при нажатии одной из моих пользовательских кнопок. Запросы не должны обрабатываться html, а скорее кодом iOS. Поэтому я использовал соглашение о запросе (читал где-то здесь в stackoverflow), используя "inapp" в качестве схемы моих запросов. Затем я проверяю хост и выполняю соответствующие действия.
Этот код отлично работает на iOS 7. Но веб-представления отображаются на iOS 8 (ошибка?), поэтому я решил использовать WKWebView для iOS 8 устройств. Теперь веб-представления отображают прекрасный (и удивительно быстрый!), Но мои кнопки не действуют.
Я пытался использовать - (WKNaviation *)loadRequest:(NSURLRequest *)request
, но он не вызывался.
Я не могу найти прямой эквивалент метода делегата UIWebView webView: shouldStartLoadWithRequest: navigationType:
. Каков наилучший способ обработки этих запросов с помощью WKWebView?
Ответы
Ответ 1
Повторное чтение вашего описания похоже на то, что вам нужно знать о том, как переопределить мост Javascript/ Objective-C с помощью WKWebView.
Я только что сделал это сам, следуя учебному пособию http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ и информации на http://nshipster.com/wkwebkit/
WKWebView имеет встроенный способ связи между Javascript и Objective-C/Swift: WKScriptMessageHandler
.
Во-первых, включите заголовки WebKit и WKScriptMessageHandler
в свой заголовок контроллера просмотра:
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@interface ViewController : UIViewController <WKScriptMessageHandler>
@end
При инициализации вашего WKWebView
вам необходимо настроить его с помощью обработчика сообщения script. Назовите его, как хотите, но для меня это похоже на то, что его имя для вашего приложения имеет смысл.
WKWebViewConfiguration *theConfiguration =
[[WKWebViewConfiguration alloc] init];
[theConfiguration.userContentController
addScriptMessageHandler:self name:@"myApp"];
_theWebView = [[WKWebView alloc] initWithFrame:self.view.frame
configuration:theConfiguration];
[_theWebView loadRequest:request];
[self.view addSubview:_theWebView];
Теперь реализуем userContentController:didReceiveScriptMessage:
. Это срабатывает, когда ваш веб-просмотр получает сообщение, поэтому он выполняет работу, которую вы ранее делали с помощью webView:shouldStartLoadWithRequest:navigationType:
.
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
NSDictionary *sentData = (NSDictionary *)message.body;
NSString *messageString = sentData[@"message"];
NSLog(@"Message received: %@", messageString);
}
Теперь вы готовы получать сообщения от Javascript. Вызов функции, которую вы должны добавить в свой Javascript, таков:
window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"});
Ответ 2
Чтобы ответить на исходный вопрос, эквивалент webView:shouldStartLoadWithRequest:navigationType:
в UIWebView webView:decidePolicyForNavigationAction:decisionHandler:
в WKWebView. Эти методы вызывается перед каждым запросом (включая исходный запрос) и предоставляют возможность разрешить/запретить его.
Ответ 3
Я сам искал хорошее объяснение, но не нашел его. Я использовал следующее в своем приложении, и все, кажется, работает (Изменить: обновлено на основе комментария ccoroom):
UIWebViewDelegate - webView:shouldStartLoadWithRequest:navigationType:
WKNavigationDelegate - webView:decidePolicyForNavigationAction:decisionHandler:
Здесь другие методы UIWebViewDelegate
:
UIWebViewDelegate - webViewDidStartLoad:
WKNavigationDelegate - webView:didCommitNavigation:
UIWebViewDelegate - webViewDidFinishLoad:
WKNavigationDelegate - webView:didFinishNavigation:
UIWebViewDelegate - webView:didFailLoadWithError:
WKNavigationDelegate - webView:didFailNavigation:withError:
- webView:didFailProvisionalNavigation:withError:
Мне бы хотелось, чтобы кто-то подтвердил это для меня, хотя.
Изменить: Собственно, я ответил на вопрос, который у вас был в названии (хотя я больше не уверен, что webView:didCommitNavigation:
вызывается в той же точке жизненного цикла), но повторное чтение вашего описания выглядит так, как вам нужно знать о том, как переопределить мост Javascript/Objective-C с помощью WKWebView. Так что посмотрите на мой другой ответ.
Ответ 4
Просто используйте следующий метод, это часть WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSString *url = [[request URL]absoluteString];
decisionHandler(WKNavigationActionPolicyAllow);
}
Ответ 5
В Swift вы можете сделать что-то вроде этого:
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
switch navigationAction.request.URLString {
case "http://action.is.needed/some-action":
self.someFunc()
decisionHandler(.Cancel)
break
default:
decisionHandler(.Allow)
break
}
}
И это ссылка на веб-странице:
<a href="http://action.is.needed/some-action">Hello world!</a>
Ответ 6
Вы можете добавить Observer для своего WKWebView
static void* keyValueObservingContext = &keyValueObservingContext;
[webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"URL"]){
// do something
}
}
Не забудьте удалить его в viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[webView removeObserver:self forKeyPath:@"URL"];
}