Communication between Swift and Javascript in a project utilizing two way communication

I am currently developing an iOS Swift application and I would like to establish a bidirectional communication with JavaScript. My goal is to be able to listen for messages (JSON) from JavaScript and send JSONs back as well. I have come across various resources addressing this issue, however, due to my limited experience in iOS development, I have been unable to successfully implement it.

Based on the information I've gathered from other responses and tutorials such as Medium, it seems that most solutions involve creating a class that conforms to the UIViewController protocol. However, my view is a struct that implements the View protocol. How can I incorporate this UIViewController protocol into my view which is a struct? Is this even possible?

To simplify things, I initially added a WebView using WebKit to my View using a struct and the following functions:

func makeUIView(context: Context) -> WKWebView
func updateUIView(_ uiView: WKWebView, context: Context)

This initial setup worked fine. Now, the next step is to add JavaScript compatibility.

Following the examples I found related to UIViewController, it appears that I need to include the following code snippet:

let config = WKWebViewConfiguration()
config.userContentController.add(self, name: doSomething) // An error occurs at this line

The error message states:

Argument type 'SwiftUIWebView' does not conform to expected type 'WKScriptMessageHandler'

In an attempt to resolve this issue, I added 'WKScriptMessageHandler' to the struct (or via extension), resulting in several more errors:

struct SwiftUIWebView: UIViewRepresentable, WKScriptMessageHandler // Additional errors are displayed

The new errors indicate:

1. Non-class type 'SwiftUIWebView' cannot conform to class protocol 'NSObjectProtocol'
2. Non-class type 'SwiftUIWebView' cannot conform to class protocol 'WKScriptMessageHandler'

Subsequently, I decided to change the struct to a class, but this led to even more errors. The errors also appeared within the functions created for the original WebView, following the same pattern as mentioned above:

1. Protocol 'UIViewRepresentable' requirement 'makeUIView(context:)' cannot be satisfied by a non-final class ('SwiftUIWebView') because it uses 'Self' in a non-parameter, non-result type position
2. Protocol 'UIViewRepresentable' requirement 'updateUIView(_:context:)' cannot be satisfied by a non-final class ('SwiftUIWebView') because it uses 'Self' in a non-parameter, non-result type position

It seems like I may have taken the wrong approach.

After some investigation, it appears that the classes implementing the UIViewController protocol typically belong to projects based on storyboards. For instance, one of the links I referenced here includes a GitHub repository, providing more than just code snippets.

Is it feasible to achieve this functionality in a Swift project? If so, what steps should I take?

Answer №1

To ensure compatibility with SwiftUI, it is crucial for SwiftUI views to be defined as `struct`s. Therefore, you must establish a separate `class` that adheres to the `WKScriptMessageHandler` protocol and then retain an instance of this class within your `WebView`.

struct WebView: UIViewRepresentable {
    private let messageHandler: WebKitMessageHandler

    init(messageHandler: WebKitMessageHandler) {
        self.messageHandler = messageHandler
    }

    func makeUIView(context: Context) -> WKWebView {
        let config = WKWebViewConfiguration()
        config.userContentController.add(messageHandler, name: "name")
        // Insert appropriate frame specifications here
        let webView = WKWebView(frame: CGRect.zero, configuration: config)
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {

    }
}

class WebKitMessageHandler: NSObject, WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the memory layout of untyped JavaScript arrays, given their lack of homogeneity?

I am interested in learning more about the performance attributes of untyped JavaScript arrays, given that they are not homogenous. I wonder how this is handled internally. For instance, if I were to have a number and an arbitrary object in an array, woul ...

Present Different Content for Visitors Using Ad-Blocking Software

I am currently working on a project that is supported by ads. These ads are subtle and relevant to the content, not obnoxious popups for questionable products. However, since the project relies on ad revenue, users with Ad Blockers unfortunately do not co ...

Create a triangular shaped division element to contain text and automatically close when the user moves the cursor away

Is there a way to create a triangular div that can display text and images? I tried this method, but the issue I'm facing is that when the div opens on hover, it doesn't close properly when I hover out. Since the div is in a square shape, how ca ...

No search results found for Mongoose text search query

Despite using Mongoose 5.7.8 for my app, the text search feature is not yielding any results. Below is a schema/model example: import mongoose, { Document, Schema } from 'mongoose'; import { Moment } from 'moment'; import { IUser } fr ...

What is the best way to trigger a function once a person has finished typing?

Whenever someone enters text into an input field on my HTML page, I want a function to be triggered only after they stop typing. The onkeypress event is not suitable because it triggers with every character typed. Here's an example of the behavior I a ...

Unusual sighting of NavBar background image on iOS7

When setting the background image of the Navigation bar, the code performs well on iOS6 but shows unexpected results on iOS7. UIImage *navBackgroundImage = [UIImage imageNamed:@"nav-bkg.png"]; [[UINavigationBar appearance] setBackgroundImage:navBackground ...

Conceal and reveal modal by leveraging the power of redux

Is there a way to toggle the visibility of a modal using an axios post method? I keep encountering the error message, 'Cannot read property 'hide' of undefined.' Any suggestions on how to fix this issue? // Function to hide the modal ...

Make sure to validate onsubmit and submit the form using ajax - it's crucial

Seeking assistance for validating a form and sending it with AJAX. Validation without the use of ''onsubmit="return validateForm(this);"'' is not functioning properly. However, when the form is correct, it still sends the form (page r ...

How to override the styling of a parent element in CSS

I'm encountering an issue with my website's sidebar. I've set the background color to yellow for elements with the currentPage class. This works fine for the 'Home' tab, but when I try to do the same for a nested tab like 'tag ...

Bootstrap auto-suggest feature that preloads data source on initial page load

I am attempting to dynamically load the entire source data using jQuery from the server only once on pageload. I want to store this data in a variable. The jQuery part is functioning properly, but the input is not autocompleting as expected. It only works ...

Angular has surpassed the maximum call stack size, resulting in a Range Error

I am facing an issue while trying to include machine detail and a button bar in my app. Interestingly, this setup has worked perfectly fine in other parts of the application but is causing errors in the core module. Here is the error message main.ts impo ...

Having trouble getting a Three.js invisible plane to work correctly with raycaster.intersectObject?

I've been experimenting with creating draggable objects similar to this interesting example: The array objectMoverLines contains the objects that should be draggable. To incorporate a plane into my scene, I utilized the following code: plane = new ...

How can I efficiently store and access DOM elements in my React application to avoid constant re-fetching?

Is there a known pattern for storing references to both regular DOM elements and jQuery elements within a class? Despite the general advice against using jQuery with React, I needed the jQuery functions for my menu to function properly and did not have ti ...

Tips on validating emails using mongoose

As a beginner with Mongoose, I have a code snippet here. How can I validate the text that appears after the @ symbol in an email before saving it to the database? var user = new User ({ firstName: String, lastName: String, email: String, ...

Issue with Heroku: Unable to serve images through NodeJS Express server

I have an app deployed on Heroku that displays an image. app.js package.json package-lock.json public |__ image1.png |__ image2.png This is the code within app.js const express = require('express'); const app = express(); const path = re ...

Is it possible to create a unique iOS project template that is exclusively based on ARC?

I am designing a custom template that includes additional files from a previous project built with ARC. I want to set ARC as the default option and prevent it from being turned off. I have been using this resource as a guide and have also been searching f ...

Tips on creating a resizable box that can move from left to bottom and also from right to top

Hey there, I'm currently working on developing my own catalog and I'm in the process of creating a selection tool to allow users to zoom in on a specific part of an image. If you're interested, you can check out the project here. However, I ...

Struggling to implement nested routes with react-router-dom version 5.2.0?

I'm currently working on implementing nested routing in React using react-router-dom 5.2.0. For a better understanding of the project, you can access the CodeSandbox link here: https://codesandbox.io/s/nested-routes-8c7wq?file=/src/App.js Let's ...

Using only Node.js, demonstrate the image

I want to show an image using only Node.js without involving HTML or ID's. I have been looking for solutions but most examples I find use HTML, which I prefer not to use. Unfortunately, I don't have any code to share, but I'm wondering if th ...

Generating React components with random numbers dynamically during runtime

If I have the following basic components: const CompOne = (props) => { return ( <div className="compOne"> {props.children} </div> ); }; const CompTwo = (props) => { return ( <div className="compTwo"> ...