// 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.
#import "ios/web/js_messaging/scoped_wk_script_message_handler.h"
#import "ios/web/js_messaging/web_view_js_utils.h"
@interface CRWScriptMessageHandler : NSObject <WKScriptMessageHandler>
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCallback:(ScriptMessageCallback)callback
NS_DESIGNATED_INITIALIZER;
@property(nonatomic) ScriptMessageCallback callback;
@end
@implementation CRWScriptMessageHandler
- (instancetype)initWithCallback:(ScriptMessageCallback)callback {
if ((self = [super init])) {
_callback = callback;
}
return self;
}
- (void)userContentController:(WKUserContentController*)userContentController
didReceiveScriptMessage:(WKScriptMessage*)message {
_callback.Run(message);
}
@end
@interface CRWScriptMessageHandlerWithReply
: NSObject <WKScriptMessageHandlerWithReply>
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCallback:(ScriptMessageWithReplyCallback)callback
NS_DESIGNATED_INITIALIZER;
@property(nonatomic) ScriptMessageWithReplyCallback callback;
@end
@implementation CRWScriptMessageHandlerWithReply
- (instancetype)initWithCallback:(ScriptMessageWithReplyCallback)callback {
if ((self = [super init])) {
_callback = callback;
}
return self;
}
- (void)userContentController:(WKUserContentController*)userContentController
didReceiveScriptMessage:(WKScriptMessage*)message
replyHandler:(void (^)(id, NSString*))replyHandler {
ScriptMessageReplyHandler replyValueHandler =
^(const base::Value* reply, NSString* error_message) {
// Per the API documentation, specify the result as nil if an error
// occurred.
id wkResult = error_message ? nil : web::NSObjectFromValueResult(reply);
replyHandler(wkResult, error_message);
};
_callback.Run(message, replyValueHandler);
}
@end
ScopedWKScriptMessageHandler::ScopedWKScriptMessageHandler(
WKUserContentController* user_content_controller,
NSString* script_handler_name,
ScriptMessageCallback callback)
: user_content_controller_(user_content_controller),
script_handler_name_(script_handler_name),
script_message_handler_(
[[CRWScriptMessageHandler alloc] initWithCallback:callback]) {
DCHECK(callback);
[user_content_controller_ addScriptMessageHandler:script_message_handler_
name:script_handler_name_];
}
ScopedWKScriptMessageHandler::ScopedWKScriptMessageHandler(
WKUserContentController* user_content_controller,
NSString* script_handler_name,
WKContentWorld* content_world,
ScriptMessageCallback callback)
: content_world_(content_world),
user_content_controller_(user_content_controller),
script_handler_name_(script_handler_name),
script_message_handler_(
[[CRWScriptMessageHandler alloc] initWithCallback:callback]) {
DCHECK(callback);
if (content_world_) {
[user_content_controller_ addScriptMessageHandler:script_message_handler_
contentWorld:content_world_
name:script_handler_name_];
} else {
[user_content_controller_ addScriptMessageHandler:script_message_handler_
name:script_handler_name_];
}
}
ScopedWKScriptMessageHandler::ScopedWKScriptMessageHandler(
WKUserContentController* user_content_controller,
NSString* script_handler_name,
WKContentWorld* content_world,
ScriptMessageWithReplyCallback callback)
: content_world_(content_world),
user_content_controller_(user_content_controller),
script_handler_name_(script_handler_name),
script_message_handler_with_reply_(
[[CRWScriptMessageHandlerWithReply alloc]
initWithCallback:callback]) {
DCHECK(content_world);
DCHECK(callback);
[user_content_controller
addScriptMessageHandlerWithReply:script_message_handler_with_reply_
contentWorld:content_world_
name:script_handler_name_];
}
ScopedWKScriptMessageHandler::~ScopedWKScriptMessageHandler() {
if (content_world_) {
[user_content_controller_
removeScriptMessageHandlerForName:script_handler_name_
contentWorld:content_world_];
} else {
[user_content_controller_
removeScriptMessageHandlerForName:script_handler_name_];
}
}