Web ページが UIWebView によって完全に読み込まれたときを知る必要があります。つまり、すべてのリダイレクトが完了し、動的にロードされるコンテンツの準備が整ったときです。javascript を注入してみました ( のクエリdocument.readyState == 'complete'
) が、あまり信頼性がないようです。
おそらく、結果をもたらすプライベートAPIからのイベントはありますか?
Javascript を実行する UIWebView の機能は、ページが読み込まれたかどうかに関係ありません。stringByEvaluatingJavaScriptFromString: を使用して、最初に UIWebView でページをロードする呼び出しを行う前に、またはページをまったくロードせずに Javascript を実行することができます。
したがって、このリンクの回答がどのように受け入れられているのか理解できません: webViewDidFinishLoad: Firing too soon? Javascriptを呼び出しても何 もわからないためです(たとえば、domを監視している興味深いJavascriptを呼び出している場合、彼らはそれについて言及していません。
たとえば、DOM の状態やロードされたページの状態を調べて、それを呼び出し元のコードに報告する Javascript を呼び出すこともできますが、ページがまだロードされていないと報告された場合はどうすればよいでしょうか? -少し後でもう一度呼び出す必要がありますが、どれくらい後、いつ、どこで、どのように、どのくらいの頻度で....ポーリングは通常、何に対しても優れたソリューションではありません。
ページがいつ完全にロードされたかを知る唯一の方法は、自分で何をするかを正確に把握することです。JavaScript イベントリスナーをロード中のページにアタッチし、独自の shouldStartLoadWithRequest: を呼び出すようにします。 URL。たとえば、ページがいつ読み込まれたかを知る必要があるかどうか、または dom だけが読み込まれたかどうかなどに応じて、ウィンドウの読み込みや dom の準備完了イベントなどをリッスンする JS 関数を作成できます。
Web ページが自分のものでない場合は、この JavaScript をファイルに入れて、ロードするすべてのページに挿入できます。
JavaScript イベント リスナーの作成方法は標準の JavaScript であり、iOS とは特に関係ありません。 shouldStartLoadWithRequest: への呼び出し (これは、ページ コンテンツ全体が表示される前に dom の読み込みが完了したときに shouldStartLoadWithRequest を呼び出します。これを検出するには、イベント リスナーを変更するだけです)。
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();
WKWebView はdidFinish
、DOM の readyState が のときにデリゲートを呼び出しますinteractive
。これは、JavaScript が読み込まれた Web ページには早すぎます。状態を待つ必要があり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
}
}
Martin H の答えは正しい軌道に乗っていますが、それでも何度も解雇される可能性があります。
必要なことは、Javascript onLoad リスナーをページに追加し、リスナーを既に挿入しているかどうかを追跡することです。
#define kPageLoadedFunction @"page_loaded"
#define kPageLoadedStatusVar @"page_status"
#define kPageLoadedScheme @"pageloaded"
- (NSString*) javascriptOnLoadCompletionHandler {
return [NSString stringWithFormat:@"var %1$@ = function() {window.location.href = '%2$@:' + window.location.href; window.%3$@ = 'loaded'}; \
\
if (window.attachEvent) {window.attachEvent('onload', %1$@);} \
else if (window.addEventListener) {window.addEventListener('load', %1$@, false);} \
else {document.addEventListener('load', %1$@, 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;
}
}
ここで受け入れられた回答を使用することもできます: UIWebView - 「最後の」webViewDidFinishLoad メッセージを識別する方法は? ...
基本的に、 EstimatedProgress プロパティを使用し、それが 100 に達すると、ページの読み込みが完了します...ヘルプについては、このガイドを参照してください。
プライベート フレームワークを使用していますが、ガイドによると、それを使用するアプリが App Store にいくつかあります...
View Controller を UIWebView のデリゲートにします。(これは、Interface Builder で行うか、viewDidLoad メソッドで次のコードを使用して行うことができます。
[self.myWebView setDelegate:self];
次に、受け入れられた回答で説明されている方法を使用します: webViewDidFinishLoad: Firing too soon? .
コード:
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
NSString *javaScript = @"function myFunction(){return 1+1;}";
[webView stringByEvaluatingJavaScriptFromString:javaScript];
//Has fully loaded, do whatever you want here
}
これは@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.");
}
}
これらの回答はすべて古く、webViewDidFinishLoad
減価償却されており、後で多くの頭痛の種になるため、Swift 4.2 を使用して Webkit (webview) でページの読み込みがいつ完了したかを正確に知る方法を説明します。
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!
}
}
もちろん、既存の関数に追加しているので、他のデフォルト コードの一部が欠けています。