Search code examples
javascripthtmlswiftswiftuiwkwebview

SwiftUI WKWebview how to transfer variable to html?


My question is how to transfer a variable (i.e. "ATOR01" as string) in swift to variable code in my index.html by a javascript function populate(param)

Here is my swift code ContentView.swift

import SwiftUI
import WebKit

struct ContentView: View {
    
    let testHTML = Bundle.main.url(forResource: "www/index", withExtension: "html")
    var body: some View {
        WebView(request: URLRequest(url: testHTML!))
    }

    struct WebView: UIViewRepresentable {
        let request: URLRequest
        
        func makeUIView(context: Context) -> WKWebView {
            let preferences = WKPreferences()
            preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
            
            let configuration = WKWebViewConfiguration()
            configuration.preferences = preferences
            
            let contentController = WKUserContentController()
            let scriptSource = "populate(\"ATOR01\")"
            let script = WKUserScript(source: scriptSource, injectionTime: .atDocumentStart, forMainFrameOnly: true)
            contentController.addUserScript(script)
            
            let config = WKWebViewConfiguration()
            config.userContentController = contentController
            
            let webView = WKWebView(frame: CGRect.zero, configuration: configuration)
            webView.scrollView.isScrollEnabled = true
            return webView
        }
        func updateUIView(_ uiView: UIViewType, context: UIViewRepresentableContext<WebView>) {
             uiView.load(request)
        }
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            let scriptSource = "populate(\"ATOR01\")"
            
            webView.evaluateJavaScript(scriptSource, completionHandler: { (object, error) in
                if let error = error {
                    print("Error calling javascript:valueGotFromIOS()")
                    print(error.localizedDescription)
                } else {
                    print("Called javascript:valueGotFromIOS()")
                }
            })
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Here is my html code index.html

<!DOCTYPE html>
<html>
<head>


    <title>Dosing</title>
    
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta charset="UTF-8">

    <meta http-equiv="Window-target" content="_top">
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate">
    <meta name="viewport" content="width=device-width, initial-scale=1">




<style>

body{
    padding: 0px;
}

#content{
    padding: 0px 0px 0px 0px;
}


</style>


    <!-- CSS/ BS3 -->
    <script type="text/javascript" language="javascript" src="script2/jquery-1.12.4.min.js"></script>
    <script type="text/javascript" language="javascript" src="script2/bootstrap.js"></script>
    <script type="text/javascript" language="javascript" src="script2/json2.js"></script>
    <script type="text/javascript" language="javascript" src="script2/jquery.csv.js"></script>

    <link rel="stylesheet" type="text/css" href="script2/genDosingTable.css">
    <script src="script2/genDosingTable.js"></script>

<script>

var code = ""
function populate(param) {
    var code = param;
}

var arr_formList = [];
$.ajax({
    url: "csv_formList.csv",
    dataType: "text",
    async: false,
    success: function(csvd) {
        var data = $.csv.toObjects(csvd);
        arr_formList.PO = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].PO !== "") { arr_formList.PO.push(data[i].PO) }
        }
        arr_formList.EYE = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].EYE !== "") { arr_formList.EYE.push(data[i].EYE) }
        }
        arr_formList.INJ = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].INJ !== "") { arr_formList.INJ.push(data[i].INJ) }
        }
        arr_formList.PR = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].PR !== "") { arr_formList.PR.push(data[i].PR) }
        }
        arr_formList.INHALATION = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].INHALATION !== "") { arr_formList.INHALATION.push(data[i].INHALATION) }
        }
        arr_formList.EAR = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].EAR !== "") { arr_formList.EAR.push(data[i].EAR) }
        }
        // console.log(arr_formList)
    },
    complete: function(data) {
    }
});


var arr_dosingRoute = [];
$.ajax({
    url: "csv_dosingRoute.csv",
    dataType: "text",
    async: false,
    success: function(csvd) {
        var data = $.csv.toObjects(csvd);
        arr_dosingRoute.INJ = []
        for (var i = 0; i < data.length; i++) {
            if (data[i].INJ !== "") { arr_dosingRoute.INJ.push(data[i].INJ) }
        }
    },
    complete: function(data) {
    }
});


var arr_dosing = [];
var arr_master = [];
var arr_groupList = [];
var arr_dosingWithDrugNumber = [];
$.ajax({
    url: "csv_dosing.csv",
    dataType: "text",
    success: function(csvd){
    var data = $.csv.toObjects(csvd); //toObjects: returns Objects (with headers); toArrays: returns plain text array
    arr_dosing = data;
    for (var i = 0; i < arr_dosing.length; i++) {
        arr_groupList.push(arr_dosing[i].group_code)
    }
    arr_groupList = arr_groupList.filter ( onlyUnique )
    arr_groupList = arr_groupList.sort()


    $.ajax({
        url: "csv_master.csv",
        dataType: "text",
        async: false,
        success: function(csvd) {
            var data = $.csv.toObjects(csvd);
            arr_master = data;
            // console.log(arr_master)
        },
        complete: function(data) {
            arr_dosingWithDrugNumber = countDrugOfGroup(arr_master, arr_groupList)

            $("#test").append( '<div class="drugDosingDiv" drugCode="' + code + '""></div>' )
            $('div[class="drugDosingDiv"][drugCode="' + code +'"]').append( '<div class="column1"></div>' )
            $('div[class="drugDosingDiv"][drugCode="' + code +'"]').append( '<div class="column2"></div>' )
            $( 'div[class="drugDosingDiv"][drugCode="' + code +'"] > div.column1' ).append( code + '</br>');
            $( 'div[class="drugDosingDiv"][drugCode="' + code +'"] > div.column1' ).append(renderDrugBox(code, arr_master, arr_dosingWithDrugNumber, 'filtered') );

        }
    });
 }
})


$(document).ready(function() {
});

</script>

</head>

<body>

<div id="test"></div>

<script>

</script>

</body>

</html>

For now nothing is loaded when I tried to run in simulator as code = "". I bet I either miss some code so didn't run the javascript through swift or I write something wrong in javascript. I will be grateful with any help!


Solution

  • You need to make a coordinator within your WebView. The coordinator should be the webview delegate. You need a delegate otherwise

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)

    will never be called. This article does the same with MapKit but the pattern is the same: https://www.hackingwithswift.com/books/ios-swiftui/communicating-with-a-mapkit-coordinator