UIWebView: когда страница действительно заканчивала загрузку?
Мне нужно знать, когда веб-страница полностью загружена UIWebView. Я имею в виду, действительно, полностью, когда все переадресации завершены, и динамически загруженный контент готов.
Я попытался ввести javascript (запрос для document.readyState == 'complete'
), но это не кажется очень надежным.
Есть ли, возможно, событие из частного api, которое принесет мне результат?
Ответы
Ответ 1
Я искал ответ для этого, и я получил эту идею от вопроса Себастьяна. Как-то это работает для меня, возможно, это будет для тех, кто сталкивается с этой проблемой.
Я установил делегат в UIWebView и в webViewDidFinishLoad, я обнаружил, что веб-просмотр действительно завершил загрузку, выполнив Javascript.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
// UIWebView object has fully loaded.
}
}
Ответ 2
Мое решение:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!webView.isLoading) {
// Tada
}
}
Ответ 3
Возможность UIWebView выполнять Javascript не зависит от того, загружена ли страница или нет. Его возможное использование stringByEvaluatingJavaScriptFromString: выполнить Javascript, прежде чем вы даже сделаете вызов для загрузки страницы в UIWebView в первую очередь или без загрузки страницы вообще.
Поэтому я не могу понять, как принимается ответ в этой ссылке: webViewDidFinishLoad: стрельба слишком скоро?
потому что вызов любого Javascript вообще не говорит вам (если они называют какой-то интересный Javascript, который контролирует dom, например, они не упоминают об этом, и если бы они были, это было бы потому, что это важно).
Вы можете вызвать некоторый Javascript, который, например, проверяет состояние dom или состояние загруженной страницы и сообщает, что обратно к вызывающему коду, однако, если он сообщает, что страница еще не загружена, то что вы делаете делать? - вам придется называть это снова немного позже, но сколько позже, когда, где, как, как часто...
Опрос обычно никогда не является хорошим решением для чего-либо.
Единственный способ узнать, когда страница полностью загружена, быть точным и контролировать то, что именно она делает, - подключить прослушиватели событий JavaScript на загружаемую страницу и заставить их вызвать ваш shouldStartLoadWithRequest: с некоторым проприетарным URL. Например, вы можете создать JS-функцию для прослушивания загрузки окна или события, подготовленного dom, и т.д. В зависимости от того, нужно ли вам знать, когда загружена страница, или только что загрузили дом и т.д. В зависимости от ваших потребностей.
Если веб-страница не принадлежит вам, вы можете поместить этот javascript в файл и ввести его на каждую загружаемую страницу.
Как создать javascript-прослушиватели событий является стандартным javascript, ничего особенного для iOS, например, здесь JavaScript, чтобы определить, когда dom загрузился в форму, которая может быть введена на страницу загрузки из UIWebView и затем вызывается вызов toStartLoadWithRequest: (это вызовет shouldStartLoadWithRequestwhen: dom завершил загрузку, которая до отображения полного содержимого страницы, чтобы обнаружить это, просто измените прослушиватель событий).
var script = document.createElement('script');
script.type = 'text/javascript';
script.text = function DOMReady() {
document.location.href = "mydomain://DOMIsReady";
}
function addScript()
{
document.getElementsByTagName('head')[0].appendChild(script);
document.addEventListener('DOMContentLoaded', DOMReady, false);
}
addScript();
Ответ 4
Ответ Мартина H на правильном пути, но он все равно может срабатывать несколько раз.
Что вам нужно сделать, это добавить слушателя Javascript onLoad на страницу и следить за тем, добавили ли вы слушателя:
#define kPageLoadedFunction @"page_loaded"
#define kPageLoadedStatusVar @"page_status"
#define kPageLoadedScheme @"pageloaded"
- (NSString*) javascriptOnLoadCompletionHandler {
return [NSString stringWithFormat:@"var %[email protected] = function() {window.location.href = '%[email protected]:' + window.location.href; window.%[email protected] = 'loaded'}; \
\
if (window.attachEvent) {window.attachEvent('onload', %[email protected]);} \
else if (window.addEventListener) {window.addEventListener('load', %[email protected], false);} \
else {document.addEventListener('load', %[email protected], false);}",kPageLoadedFunction,kPageLoadedScheme,kPageLoadedStatusVar];
}
- (BOOL) javascriptPageLoaded:(UIWebView*)browser {
NSString* page_status = [browser stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.%@",kPageLoadedStatusVar]];
return [page_status isEqualToString:@"loaded"];
}
- (void)webViewDidFinishLoad:(UIWebView *)browser {
if(!_js_load_indicator_inserted && ![self javascriptPageLoaded:browser]) {
_js_load_indicator_inserted = YES;
[browser stringByEvaluatingJavaScriptFromString:[self javascriptOnLoadCompletionHandler]];
} else
_js_load_indicator_inserted = NO;
}
Когда страница будет завершена, слушатель Javascript будет запускать новую загрузку страницы URL pageloaded:<URL that actually finished>
. Затем вам просто нужно обновить shouldStartLoadWithRequest
, чтобы найти эту схему URL:
- (BOOL)webView:(UIWebView *)browser shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if([request.URL.scheme isEqualToString:kPageLoadedScheme]){
_js_load_indicator_inserted = NO;
NSString* loaded_url = [request.URL absoluteString];
loaded_url = [loaded_url substringFromIndex:[loaded_url rangeOfString:@":"].location+1];
<DO STUFF THAT SHOULD HAPPEN WHEN THE PAGE LOAD FINISHES.>
return NO;
}
}
Ответ 5
Вы также можете использовать принятый ответ здесь: UIWebView - как идентифицировать "last" Сообщение webViewDidFinishLoad?...
В принципе, используйте свойство valuProgress, и когда это достигает 100, страница закончила загрузку... Обратитесь это руководство для справки.
Хотя он использует частную структуру, в соответствии с руководство, в App Store есть несколько приложений...
Ответ 6
Сделайте свой контроллер просмотра делегатом UIWebView. (Вы можете сделать это в Interface Builder или с помощью этого кода в методе viewDidLoad:
[self.myWebView setDelegate:self];
Затем используйте метод, описанный в принятом ответе здесь: webViewDidFinishLoad: слишком скоро стрелять?.
Код:
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
NSString *javaScript = @"function myFunction(){return 1+1;}";
[webView stringByEvaluatingJavaScriptFromString:javaScript];
//Has fully loaded, do whatever you want here
}
Ответ 7
WKWebView вызывает делегат didFinish
, когда DOM readyState interactive
, что слишком рано для веб-страниц, загруженных javascripts. Нам нужно подождать состояния complete
. Я создал такой код:
func waitUntilFullyLoaded(_ completionHandler: @escaping () -> Void) {
webView.evaluateJavaScript("document.readyState === 'complete'") { (evaluation, _) in
if let fullyLoaded = evaluation as? Bool {
if !fullyLoaded {
DDLogInfo("Webview not fully loaded yet...")
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
self.waitUntilFullyLoaded(completionHandler)
})
} else {
DDLogInfo("Webview fully loaded!")
completionHandler()
}
}
}
}
а затем:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
DDLogInfo("Webview claims that is fully loaded")
waitUntilFullyLoaded { [weak self] in
guard let unwrappedSelf = self else { return }
unwrappedSelf.activityIndicator?.stopAnimating()
unwrappedSelf.isFullLoaded = true
}
}
Ответ 8
Здесь приведена упрощенная версия @jasonjwwilliams.
#define JAVASCRIPT_TEST_VARIBLE @"window.IOSVariable"
#define JAVASCRIPT_TEST_FUNCTION @"IOSFunction"
#define LOAD_COMPLETED @"loaded"
// Put this in your init method
// In Javascript, first define the function, then attach it as a listener.
_javascriptListener = [NSString stringWithFormat:
@"function %@() {\
%@ = '%@';\
};\
window.addEventListener(\"load\", %@, false);",
JAVASCRIPT_TEST_FUNCTION, JAVASCRIPT_TEST_VARIBLE, LOAD_COMPLETED, JAVASCRIPT_TEST_FUNCTION];
// Then use this:
- (void)webViewDidFinishLoad:(UIWebView *)webView;
{
// Only want to attach the listener and function once.
if (_javascriptListener) {
[_webView stringByEvaluatingJavaScriptFromString:_javascriptListener];
_javascriptListener = nil;
}
if ([[webView stringByEvaluatingJavaScriptFromString:JAVASCRIPT_TEST_VARIBLE] isEqualToString:LOAD_COMPLETED]) {
NSLog(@"UIWebView object has fully loaded.");
}
}
Ответ 9
Благодаря JavaScript новые ресурсы и новая графика могут быть загружены навсегда - определение того, когда загрузка "сделана", для страницы с достаточной степенью извращения, будет означать решение проблема с остановкой. Вы действительно не можете знать, когда страница загружена.
Если вы можете, просто отобразите страницу или ее изображение и используйте webViewDidLoad для обновления изображения и дайте пользователю возможность отключить или отключить.
Ответ 10
Поскольку все эти ответы webViewDidFinishLoad
а webViewDidFinishLoad
, а многие головные боли позже позвольте мне объяснить, как точно узнать, когда страница закончила загрузку в веб-комплекте (webview) с помощью swift 4.2.
class ViewController: UIViewController, WKNavigationDelegate {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
webView.navigationDelegate = self
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// it is done loading, do something!
}
}
Конечно, мне не хватает другого кода по умолчанию, поэтому вы добавляете в свои существующие функции.
Ответ 11
попробуй что-нибудь вроде этого
https://github.com/Buza/uiwebview-load-completion-tracker
это помогло мне загрузить Google Street View