chromium/ios/web_view/internal/web_view_message_handler_java_script_feature.h

// Copyright 2022 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_VIEW_INTERNAL_WEB_VIEW_MESSAGE_HANDLER_JAVA_SCRIPT_FEATURE_H_
#define IOS_WEB_VIEW_INTERNAL_WEB_VIEW_MESSAGE_HANDLER_JAVA_SCRIPT_FEATURE_H_

#import <map>
#import <optional>
#import <string>

#import "base/functional/callback.h"
#import "base/no_destructor.h"
#import "base/supports_user_data.h"
#import "base/values.h"
#import "ios/web/public/js_messaging/java_script_feature.h"

namespace web {
class BrowserState;
}  // namespace web

// A feature which listens for messages sent from the webpage to the
// 'CWVWebViewMessage' message handler and routes them to the callback for the
// associated command. `command` and `payload` are required top level keys. The
// value of the `command` key must be a string matching a registered callback.
// `payload` key must be a dictionary which will be sent to the callback mapped
// to the value of `command`.
//
// Example call from JavaScript:
//
//  let message = {
//    'command': 'myFeatureMessage',
//    'payload' : {'key1':'value1', 'key2':42}
//  }
//  window.webkit.messageHandlers['CWVWebViewMessage'].postMessage(message);
//
class WebViewMessageHandlerJavaScriptFeature
    : public base::SupportsUserData::Data,
      public web::JavaScriptFeature {
 public:
  WebViewMessageHandlerJavaScriptFeature();
  ~WebViewMessageHandlerJavaScriptFeature() override;

  WebViewMessageHandlerJavaScriptFeature(
      const WebViewMessageHandlerJavaScriptFeature&) = delete;
  WebViewMessageHandlerJavaScriptFeature& operator=(
      const WebViewMessageHandlerJavaScriptFeature&) = delete;

  static WebViewMessageHandlerJavaScriptFeature* GetInstance();

  // Returns the WebViewMessageHandlerJavaScriptFeature associated with
  // `browser_state`, creating one if necessary. `browser_state` must not be
  // null.
  static WebViewMessageHandlerJavaScriptFeature* FromBrowserState(
      web::BrowserState* browser_state);

  using WebViewMessageHandlerCallback =
      base::RepeatingCallback<void(const base::Value::Dict& payload)>;
  void RegisterHandler(std::string& command,
                       WebViewMessageHandlerCallback handler);
  void UnregisterHandler(std::string& command);

 private:
  friend class base::NoDestructor<WebViewMessageHandlerJavaScriptFeature>;

  // JavaScriptFeature overrides
  std::optional<std::string> GetScriptMessageHandlerName() const override;
  void ScriptMessageReceived(web::WebState* web_state,
                             const web::ScriptMessage& script_message) override;

  // Notifies any handler registered in `handlers_` for the command specified in
  // `message_body`.
  void NotifyHandlers(const base::Value::Dict& message_body);

  std::map<std::string, WebViewMessageHandlerCallback> handlers_;
};

#endif  // IOS_WEB_VIEW_INTERNAL_WEB_VIEW_MESSAGE_HANDLER_JAVA_SCRIPT_FEATURE_H_