I'm trying to receive the configuration that , to my understanding, should have been transmitted from a the previous website. The example below is a website that has a simple login button, when pressed, it opens a new tab (which I want to open in the same view). There you'd login and after that you would be brought back to the previous site.
The website can also be visited in a normal browser website
Its an open source project found here Github
I have the following code:
ContentView
import SwiftUI
import UIKit
import WebKit
struct ContentView: View {
var webView: WKWebView
init() {
let userContentController = WKUserContentController() //CustomContentController()
let webViewConfiguration = WKWebViewConfiguration()
webViewConfiguration.userContentController = userContentController
self.webView = WKWebView(frame: .zero, configuration: webViewConfiguration)
self.webView.configuration.limitsNavigationsToAppBoundDomains = true
self.webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
}
var body: some View {
WebviewNew(web: webView, req: URLRequest(url: URL(string: "https://vasb2-4yaaa-aaaab-qadoa-cai.ic0.app/")!))
}
}
WebViewNew
struct WebviewNew : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = web ?? WKWebView()
self.request = req
}
class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var parent: WebviewNew
init(_ parent: WebviewNew) {
self.parent = parent
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
let newWebView = WKWebView(frame: webView.frame, configuration: configuration)
newWebView.uiDelegate = self
newWebView.load(navigationAction.request)
//
return newWebView
// webView.load(navigationAction.request)
}
return nil
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}
This solution does somehow not work. When clicking the Login Button on the website inside the WKWebView nothing happens. When setting a breakpoint in func webView one can see that it gets passed but somehow nothing happens.
When altering the WebViewNew like this:
struct WebviewNew : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = web ?? WKWebView()
self.request = req
}
class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var parent: WebviewNew
init(_ parent: WebviewNew) {
self.parent = parent
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
// Changed HERE
webView.load(navigationAction.request)
}
return nil
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}
With a change in func webView it opens the login page but it seems to be missing the context as the login does not know who made the request.
In the open source website the login button can be found here
Why is my solution not working and what could make it work?
Related
I'm new to swift & am attempting to open a login page, login, use the WKNavigationDelegate to get the redirect uri and save the response. I was able to open the url using UIApplication.shared.open but attempting to hit the url using WKWebview, I am getting a loaded response but no view appears.
Am I not declarling the view correctly or is WKWebView not supposed to be used in that manner? This is the code i'm running, its building succesfully and responding that its 'loaded'. Any help would be be appreciated thanks.
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
// The webview
var webViewObj: WKWebView!
var webNav: WKNavigation!
// this calls the dbhelper to create a db and a table
let db = DBHelper()
var list = [DBGrade]()
override func loadView() {
super.loadView()
let webConfiguration = WKWebViewConfiguration()
webViewObj = WKWebView(frame: .zero, configuration: webConfiguration)
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.hackingwithswift.com")
let request = URLRequest(url: url!)
webViewObj.navigationDelegate = self
self.webViewObj.uiDelegate = self
webViewObj.load(request)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("loaded")
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
let hostStr = String(describing: navigationAction.request.url)
let host = hostStr
if host.range(of: "hackingwithswift.com") != nil {
decisionHandler(.allow)
print("did it")
return
}
else{
decisionHandler(.cancel)
}
}
}
So moving my delcaration of 'self.webViewObj.uiDelegate = self' & adding 'view = webViewObj' to the loadView() function worked & I'm able to see the webpage appear.
I am working on a web application for iOS. I would like that when the user clicks on the link sign in the link is redirected. I need this because I need to paste the token created for the user behind it. For now, the redirect link is nu.nl. I have this now, but unfortunately it doesn't work. I am not familiar with the language swift ui. Thanks in advance for your help :)
Contentview
import SwiftUI
import Foundation
import WebKit
struct ContentView: View {
var body: some View {
WebView(url: URL(string:"https://ferocity.bytemountains.com/client")!).frame(maxWidth: .infinity, maxHeight: .infinity).edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Webview
import Foundation
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
let url: URL
let webView = WKWebView()
func makeUIView(context: Context) -> some UIView {
let request = URLRequest(url: url)
webView.load(request)
return webView
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Swift.Void) {
if(navigationAction.navigationType == .other) {
if navigationAction.request.url != nil {
//do what you need with url
webView.load(URLRequest(url: URL(string: "https://nu.nl/")!))
}
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
}
enter image description here
You will have to use Coordinator and then need to conform the WKNavigationDelegate to call its delegate methods.
struct WebView : UIViewRepresentable {
let url: URL
var webView = WKWebView()
func makeUIView(context: Context) -> WKWebView {
let request = URLRequest(url: url)
webView.load(request)
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.navigationDelegate = context.coordinator
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
//Conform to WKNavigationDelegate protocol here and declare its delegate
class Coordinator: NSObject, WKNavigationDelegate {
var parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
//Navigate to other URL if user clicks on the sign in link
if navigationAction.request.url?.absoluteString == "https://sso.bytemountains.com/?clientId=2" {
webView.load(URLRequest(url: URL(string: "https://nu.nl/")!))
}
decisionHandler(.allow)
}
}
}
I am making an app that contains multiple web-view's. I am wanting to reload my web-view from the coordinator class after a JS command is sent from the webpage and inside the "func processReturnedJS(body: String)" shown below. I am wondering how I can achieve this in a simple way?
Thanks
SubscriptionViewController:
import SwiftUI
import WebKit
struct SubscriptionViewController: UIViewRepresentable {
#StateObject var storeManager: StoreManager
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
let config = WKWebViewConfiguration()
let cookies = HTTPCookieStorage.shared.cookies ?? []
func makeUIView(context: UIViewRepresentableContext<SubscriptionViewController>) -> WKWebView {
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
let preferences = WKPreferences()
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name:"observer")
configuration.userContentController = userContentController
let view = WKWebView(frame: frame, configuration: configuration)
view.navigationDelegate = context.coordinator
DispatchQueue.main.async {
let url = URL(string:"theurl")!
let request = URLRequest(url: url)
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
view.configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
view.load(request)
}
return view
}
func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<SubscriptionViewController>) {
}
func makeCoordinator() -> CoordinatorSubscription {
CoordinatorSubscription(self, storeManage: self.storeManager)
}
typealias UIViewType = WKWebView
}
class CoordinatorSubscription: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var control: SubscriptionViewController
var storeManage: StoreManager
init(_ control: SubscriptionViewController, storeManage: StoreManager) {
self.control = control
self.storeManage = storeManage
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
processReturnedJS(body: message.body as! String)
}
func sendjs(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func processReturnedJS(body: String) {
print("kkkk")
//want to reload webview from here
}
}
You can store a reference to the WKWebView in your coordinator:
class CoordinatorSubscription: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var control: SubscriptionViewController
var storeManage: StoreManager
var webView : WKWebView? //<-- Here
init(_ control: SubscriptionViewController, storeManage: StoreManager) {
self.control = control
self.storeManage = storeManage
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
processReturnedJS(body: message.body as! String)
}
func sendjs(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
func processReturnedJS(body: String) {
self.webView?.reload() //here
}
}
Then, make sure to set that property in makeUIView:
func makeUIView(context: UIViewRepresentableContext<SubscriptionViewController>) -> WKWebView {
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
let preferences = WKPreferences()
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name:"observer")
configuration.userContentController = userContentController
let view = WKWebView(frame: frame, configuration: configuration)
view.navigationDelegate = context.coordinator
DispatchQueue.main.async {
let url = URL(string:"theurl")!
let request = URLRequest(url: url)
for cookie in cookies {
config.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
view.configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
view.load(request)
}
context.coordinator.webView = view //<-- Here
return view
}
How would I set the text size of a SwiftUI WebKit View to a #State variable? I have this code that allows me to use WebViews in SwiftUI
import SwiftUI
import WebKit
struct WebView : UIViewRepresentable {
var url : URL;
func makeUIView(context: Context) -> WKWebView {
return WKWebView();
}
func updateUIView(_ uiView: UIViewType, context: Context) {
uiView.loadFileURL(url, allowingReadAccessTo: url)
}
}
I saw this and tried to replicate it,
class Coordinator : NSObject {
func webView(_ webView: WKWebView, js : String) {
webView.evaluateJavaScript(js)
}
}
But I wasn't able to get it to work.
Thanks in advance.
You can try to do this in navigation delegate, after loading did finish, as shown below:
class Coordinator : NSObject, WKNavigationDelegate {
// ... any other code
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript(js, completionHandler: { (value, error) in
// .. do anything needed with result, if any
})
}
}
struct WebView : UIViewRepresentable {
var url : URL;
func makeUIView(context: Context) -> WKWebView {
let webview = WKWebView()
webview.navigationDelegate = context.coordinator
return webview
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
func updateUIView(_ uiView: UIViewType, context: Context) {
uiView.loadFileURL(url, allowingReadAccessTo: url)
}
}
I'm creating a web app on Xcode v11 and having a trouble implementing WKUIDelegate to display Javascript alert and confirm properly on the web app.
I got a very simple webview app with below code on ContentView.swift but not sure how to implement WKUIDelegate properly with this code.
import SwiftUI
import WebKit
struct Webview : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = WKWebView()
self.request = req
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}
struct ContentView: View {
let webview = Webview(web: nil, req: URLRequest(url: URL(string: "https://google.com")!))
var body: some View {
VStack {
webview
HStack() {
Button(action: {
self.webview.goBack()
}){
Image(systemName: "chevron.left")
}.padding(32)
Button(action: {
self.webview.reload()
}){
Image(systemName: "arrow.clockwise")
}.padding(32)
Button(action: {
self.webview.goForward()
}){
Image(systemName: "chevron.right")
}.padding(32)
}.frame(height: 32)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
What is the best way to implement WKUIDelegate into this code? So, it will display Javascript Alert and Confirm properly.
You need to use Coordinator and then conform to WKUIDelegate:
class Coordinator: NSObject, WKUIDelegate {
var parent: Webview
init(_ parent: Webview) {
self.parent = parent
}
// Delegate methods go here
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping () -> Void) {
// alert functionality goes here
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
Then ensure your updateUIView(..) sets the uiDelegate to the context.coordinator:
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
[...]
}
If you want to conform to WKNavigationDelegate then conform to it and set the navigationDelegate to the context.coordinator as well.
Full code here:
import SwiftUI
import WebKit
struct Webview : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?
init(web: WKWebView?, req: URLRequest) {
self.webview = WKWebView()
self.request = req
}
class Coordinator: NSObject, WKUIDelegate {
var parent: Webview
init(_ parent: Webview) {
self.parent = parent
}
// Delegate methods go here
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: #escaping () -> Void) {
// alert functionality goes here
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
return webview!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}
func goBack(){
webview?.goBack()
}
func goForward(){
webview?.goForward()
}
func reload(){
webview?.reload()
}
}