web-dev-qa-db-ja.com

WkWebKit-ロードされたページのJavaScriptがwindow.webkitが未定義であることを検出します

私はWkWebKitでアプリとページの間を行ったり来たりして実験しています。 WkWebView evaluateJavascriptメソッドを使用してjavaScriptを正常に実行できますが、JavaScriptページでwindow.webkit.messageHandlers.myHandler.postMessage( 'hello world!')を実行しようとすると、window.webkitが定義されていません。

奇妙なことに、iOS 8.4を搭載したiPadのシミュレータで実行しています。これはオリジナルバージョン8で利用できると思いました。

私はこれについて他に投稿している人を見つけることができないので、おそらく何か間違ったことをしたのでしょうか?

私はSafari開発者をシミュレーターのブラウザーに接続し、コンソールでwindow.webkitが何であるかを確認しようとしましたが、確かに、それは存在しません。

ページが読み込まれたときに実行する初期スクリプトを追加していることに注意してください(これはJavaScriptエディターで確認できます-メッセージがログに記録されます)。スクリプトメッセージハンドラーも追加します...

[編集:ここにコードの詳細を追加する]これが私のコードです:

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
  NSLog(@"main view Controller viewDidLoad called...");

// if we are running on an OLD ios (pre v8) WKWebView will not exist.  So don't create it if it doesn't exist...
if (NSClassFromString(@"WKWebView")) {
    // WKWebView cannot be dragged onto storyboard, so have to create it manually here.
    // We have a "ContainerView" called _webContainer that this browser view will live inside
    // First we create a web view configuration object...
    WKWebViewConfiguration *wbConfig = [WKWebViewConfiguration alloc];
    wbConfig.mediaPlaybackAllowsAirPlay = true;
    wbConfig.mediaPlaybackRequiresUserAction = false; 
    // inject some Javascript into our page before it even loads...
    NSString *scriptSource = @"console.log('Hi from the iOS app hosting this page...'); window.hostedByWkWebView=true;";
    WKUserScript *userScript = [[WKUserScript alloc]
                                initWithSource:scriptSource
                                injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                forMainFrameOnly:YES];

    [wbConfig.userContentController addUserScript:userScript];
    [wbConfig.userContentController addScriptMessageHandler:self name:@"myHandler"]; // javascript to use this would be: window.webkit.messageHandlers.myHandler.postMessage


    // Ok, the config is created, now create the WkWebView instance, passing in this config...
    _webView = [[WKWebView alloc] initWithFrame: [_webContainer bounds] configuration:wbConfig];
    _webView.autoresizesSubviews = true;
    _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    _webView.navigationDelegate = self;

    // Add the web view to the container view, and tell the container to automatically resize its subviews, height and width.
    [_webContainer addSubview:_webView];
    _webContainer.autoresizesSubviews = true;
    _webContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

    // Set the URL for the webview and navigate there...
    NSString *fullURL = @"https://myurlgoeshere.com";

    NSURL *url = [NSURL URLWithString:fullURL];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

    [_webView loadRequest:requestObj];
}
else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Cannot create Web View" message:@"The web view used requires iOS 8 or higher.  Sorry." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"", nil];
    [alert show];
}

//...
10
Brian B

Window.webkit名前空間は、スクリプトメッセージハンドラーを備えたwebviewにのみ表示されます。 WKUserContentControllerの addScriptMessageHandler メソッドが呼び出されていることを確認してください。

7
soflare

私はそれを解決し、問題はuserContentControllerを新しいオブジェクトに設定した場合、そのuserContentControllerWKScriptMessageHandlersがAppleの内部コードに正しく登録されないことでした:

WKUserContentController *userContentController = [WKUserContentController new];
userContentController.addScriptMessageHandler(self, name: "jockey")
userContentController.addScriptMessageHandler(self, name: "observe")
webView.configuration.userContentController = userContentController

appleによってすでにインスタンス化されたuserContentControllerを使用することで修正:

webView.configuration.userContentController.addScriptMessageHandler(self, name: "jockey")
webView.configuration.userContentController.addScriptMessageHandler(self, name: "observe")
25
Pascal Kaufmann

私はこれに遭遇しましたSO同じ問題が発生していたため、カスタムCustomContentControllerWKUserContentControllerのサブクラス)インスタンスを使用してこれを解決しました。

_let userContentController = CustomContentController()
let webViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.userContentController = userContentController
webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
_

私の場合、CustomContentControllerWKUserContentControllerのサブクラスであり、ここでadd(_ scriptMessageHandler: WKScriptMessageHandler, name: String)メソッドが呼び出されますが、それが重要であるとは思いません。

WKUserContentControllerをインスタンス化してWKWebViewConfigurationに適用する必要があると思いますbefore WKWebViewはWKWebView(frame: .zero, configuration: webViewConfiguration)を介して初期化されます

WKWebViewが作成されていてthenを変更しようとすると、WKWebViewConfigurationを変更しようとすると、JSContextで_window.webkit_を使用できないことが発生します。

3
David Anderson

同じ問題に遭遇しました。そして、2時間を無駄にした後、私はこれがうまく機能することを以下に見つけました。しかし、理由はわかりません。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    WKUserContentController *userCctrl = [[WKUserContentController alloc] init];
    [userCctrl addScriptMessageHandler:self name:@"jscall"];
    WKWebViewConfiguration *wbConfiger = [[WKWebViewConfiguration alloc] init];
    wbConfiger.userContentController = userCctrl;
    CGSize size = [UIScreen mainScreen].bounds.size;
    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 20, size.width, size.height - 20)  configuration:wbConfiger];
    [self.view addSubview:webView];
    webView.UIDelegate = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [webView evaluateJavaScript:@"if (window.webkit === undefined) { alert('未注册的 window.webkit'); } else { window.webkit.messageHandlers.jscall.postMessage({title:'标题'}); }" completionHandler:^(id obj, NSError *error) {
            NSLog(@"run js completion with error = %@", error);
    }];
    });
}
#pragma mark -
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"run js alert panel message = %@", message);
    completionHandler();
}
#pragma mark -
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSLog(@"wkwebview run javascript name = %@, body = %@", message.name, message.body);
}
0
shaojunx