// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_WEB_JS_MESSAGING_SCOPED_WK_SCRIPT_MESSAGE_HANDLER_H_
#define IOS_WEB_JS_MESSAGING_SCOPED_WK_SCRIPT_MESSAGE_HANDLER_H_
#import <WebKit/WebKit.h>
#include "base/functional/callback.h"
namespace base {
class Value;
} // namespace base
@class CRWScriptMessageHandler;
@class CRWScriptMessageHandlerWithReply;
// Callback to receive messages from JavaScript running in a webpage.
using ScriptMessageCallback =
base::RepeatingCallback<void(WKScriptMessage* message)>;
// A block to be called with the result of processing the message from
// JavaScript.
// 1. Passing a non-nil NSString value to the `error_message` signals an error.
// No matter what value you pass to the `reply`. the Promise will be rejected
// with a JavaScript error object whose message property is set to that
// `error_message` string.
// 2. If the `error_message` is nil, the `reply` will be converted to its
// JavaScript equivalent and the Promise will be fulfilled with the resulting
// value.
// a. If `reply` is nullptr, then the JavaScript resulting value is
// `undefined`.
// b. If `reply` is none type base::Value, then the JavaScript resulting
// value is `null`.
using ScriptMessageReplyHandler = void (^)(const base::Value* reply,
NSString* error_message);
// Callback to receive messages from JavaScript running in a webpage and
// replying to them asynchronously. The `reply_handler` can be called at most
// once. If the `reply_handler` is deallocated before it is called, the Promise
// will be rejected with a JavaScript Error object with an appropriate message
// indicating the handler was never called.
using ScriptMessageWithReplyCallback =
base::RepeatingCallback<void(WKScriptMessage* message,
ScriptMessageReplyHandler reply_handler)>;
// Instances of this class register and unregister itself as a
// WKUserContentController script message handler upon construction and
// deconstruction respectively.
class ScopedWKScriptMessageHandler {
public:
// Registers `script_handler_name` with `user_content_controller`. `callback`
// will be called whenever JavaScript sends a post message to
// `script_handler_name` within the page content world.
// Ex: window.webkit.messageHandlers['script_handler_name'].postMessage(10);
ScopedWKScriptMessageHandler(WKUserContentController* user_content_controller,
NSString* script_handler_name,
ScriptMessageCallback callback);
// Registers `script_handler_name` with `user_content_controller` within
// `content_world`. `callback` will be called whenever JavaScript
// sends a post message to `script_handler_name` within `content_world`
// Ex: window.webkit.messageHandlers['script_handler_name'].postMessage(10);
ScopedWKScriptMessageHandler(WKUserContentController* user_content_controller,
NSString* script_handler_name,
WKContentWorld* content_world,
ScriptMessageCallback callback);
// Registers `script_handler_name` with `user_content_controller` within
// `content_world`. `callback` will be called whenever JavaScript
// sends a post message to `script_handler_name` within `content_world`, and
// it allows native to reply to JavaScript via `reply_handler` which is passed
// to `callback`.
//
// Ex: let result = await
// window.webkit.messageHandlers['script_handler_name'].postMessage("42");
ScopedWKScriptMessageHandler(WKUserContentController* user_content_controller,
NSString* script_handler_name,
WKContentWorld* content_world,
ScriptMessageWithReplyCallback callback);
~ScopedWKScriptMessageHandler();
private:
// The content world associated with this feature. May be null which
// represents the main world that the page content itself uses. (May also be
// [WKContentWorld pageWorld] on iOS 14 and later.)
WKContentWorld* content_world_ = nullptr;
__weak WKUserContentController* user_content_controller_;
NSString* script_handler_name_;
// Called with messages sent from JavaScript if the constructor accepting a
// `ScriptMessageCallback` was used, null otherwise.
CRWScriptMessageHandler* script_message_handler_;
// Called with messages sent from JavaScript if the constructor accepting a
// `ScriptMessageWithReplyCallback` was used, null otherwise.
CRWScriptMessageHandlerWithReply* script_message_handler_with_reply_;
ScopedWKScriptMessageHandler(const ScopedWKScriptMessageHandler&) = delete;
ScopedWKScriptMessageHandler& operator=(const ScopedWKScriptMessageHandler&) =
delete;
};
#endif // IOS_WEB_JS_MESSAGING_SCOPED_WK_SCRIPT_MESSAGE_HANDLER_H_