NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

Need help , Project 4 first challenge.

Forums > 100 Days of Swift

I got to end of project number 4 and iv been trying to solve the first challenge of this project .

Q: users try to visit a URL that isn’t allowed, show an alert saying it’s blocked.

   

Please post what you are trying to do (code), would be helpful to help you

   

My temporary "solution" was to add a "unallowedwebsite" string in the websites array and check if the website url contain the "unallowed" word.

Actually there aren't url added by the user, so I think that this could be a good way to make this challenge. In future projects you will learn how to let users insert text but you have to wait some days... ;-)

   

Hacking with Swift is sponsored by Essential Developer

SPONSORED From January 26th to 31st you can join a FREE crash course for iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a senior developer!

Save your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

I actually tried to add some if else statement in the openPage func , I dont know if i do it correctly .

func openPage(action : UIAlertAction){
        if  let url = URL(string: "http://" + action.title!) {
            webView.load(URLRequest(url: url))
        }else{
            let ac = UIAlertController(title: "Valid URL", message: "wrong url", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "Close", style: .cancel))
            present(ac , animated: true)
        }
    }

   

Hi Eric.

You need to implement the following method:

  func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)

which is a function of the WKNavigationDelegate (which your class needs to conform to). Before loading a page, the web view will call this function so you can decide what to do before the page loads. That's why your logic should be here.

In that function, you will loop through the list of allowed sites and compare them to your URL's host.

  let url = navigationAction.request.url
  let host = url?.host

If it is a match, you'll allow the site to load:

  decisionHandler(.allow)
  return

Otherwise (after the loop), You'll show the error message and send .cancel to the decisionHandler closure.

  decisionHandler(.cancel)

Hope that helps.

1      

Following up with the below:

I actually solved this. all i did was to move the alert one " } " above.. so it would look like this instead, and the alert worked fine.HOWEVER I am actually not sure of the reason why it has to be one " } " above and why it would work now.

 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let url = navigationAction.request.url

        if let host = url?.host {
            for website in websites{
                if host.contains(website) {
                    decisionHandler(.allow)
                    return
                }
            }  // this is all i did differently

        let denied = UIAlertController(title: "denied", message: "This site is not allowed", preferredStyle: .alert)
            denied.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
            present(denied, animated: true)

            }

        decisionHandler(.cancel)

Hi all. I am having another problem with this challange as well

I have put the alert inside of the decisionHandler , and the alert works fine. However the alert shows regardless of the website url. I used the "Open" button to load another site , like apple.com( which is an allowed site) and when i click on apple.com link in my button , the alert shows up and the site still loads.

 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let url = navigationAction.request.url

        if let host = url?.host {
            for website in websites{
                if host.contains(website) {
                    decisionHandler(.allow)
                    return
                }
            }
        }

        let denied = UIAlertController(title: "denied", message: "This site is not allowed", preferredStyle: .alert)
            denied.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
            present(denied, animated: true)

        decisionHandler(.cancel)

        }

   

Hi teekachu,

I was having the same problem. I added some print statements after the decicionHandler calls, like

                    decisionHandler(.allow)
                    print("allowed:")
                    print(url!)

and

        print("not allowed:")
        print(url!)
        // cancel loading
        decisionHandler(.cancel)

Now you will see that some sites that are referenced try to make additional page loads within the html/css/js. Obviously a lot of sites do this without you being aware of it...

So I guess the coding is functioning ok: in case of the apple site it is allowed to go there and the page starts loading. During that load you get an alert on an attempted load within that page that isn't allowed.

For instance, if you have "hackingwithswift.com" in your allowed websites array, you will see that the pages that have an embedded youtube reference wil load, but with a warning and without the youtube reference visible.

1      

Hi guys,

@offgrid, thanks so much for your explanation. I've been trying to grasp this thing for some time now, and now I fully understand how it works.

What you're saying is true - indeed, the "hackingwithswift.com" subpages with an embedded YT reference do load, with a warning and without the youtube reference visible though. What makes me wonder is why some of the clickable links don't react to my interaction, only printing "allowed:". The links I'm talking about are the ones found in the "100 Days With Swift" days.

For example, if I try to enter Day 24. of "100 Days With Swift (UIKit)", everything loads fine (apart from the things we mentioned above). But when I try to click/tap "Setting Up" or other 2 links, literally NOTHING happens - the link gets an underline, message "allowed:" is printed, but that's all - the page is not loading.

Is it only my case, or do you guys experience the same thing?

   

Hi @MateusZ ,

I'm experiencing the same. Must be because these links try to open in a new tab using target="blank" in the html code. You would probably need to have some extra swift coding to make this work, like opening the new page in a new WKWebView, but that is beyond my knowledge. So for now I just take it for what it is.

1      

Lovely! Thank you for easing my mind with that.

   

I am also getting the same problem with apple.com and gmail.com. I, don't know why it is happening . For apple and gmail the alert appears after the website is loaded. I had tried printing statement to check the flow of code but in case of above mentioned sites it is going through both the print statements. Can, anyone help with this one.

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let url = navigationAction.request.url
        if let host = url?.host {
            for website in websites {
                if host.contains(website) {
                    print("Found")
                    decisionHandler(.allow)
                    return
                }
            }
        }
        print("Ouside")
        let ac = UIAlertController(title: "Blocked", message: "This site isn't allowed to visit", preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: nil))
        present(ac,animated: true)
        decisionHandler(.cancel)
    }

   

Hi fellas. I figured out why your block alert would display even if, say, "hackingwithswift.com" is in the websites array. It's because you put it inside the for loop, hence the for loop was only able to iterate just 1 time, at that moment website is being only "apple.com", therefore the alert displays as your for loop was not looping through to websites[1] aka "hackingwithswift.com".

This also took me an entire afternoon to figure out. Below is my code for it. Note that I decided to define a separate showBlockAlert() method, and then call it instead, just for readability's sake.

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  let url = navigationAction.request.url

  if let host = url?.host {
    for website in websites {
      if host.contains(website) {
        decisionHandler(.allow)
        return
      }
    }
    // If user somehow access a URL that isn't allowed, then show a blocking alert
    // This should be placed right below, and outside of the for loop above
    showBlockAlert()
  }

  decisionHandler(.cancel)
}

// Method to show a blocked website alert
func showBlockAlert() {
  let ac = UIAlertController(title: "Blocked website", message: "Unfortunately, this website is not in the website catalog", preferredStyle: .alert)
  ac.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: nil))
  present(ac, animated: true)
}

Updated: It seems to me that when a site tries to call - say - an ad with its host different from our preset hosts, the showBlockAlert() is also triggered. At the moment being I'm not able to find a solution to it yet; but as long as the app works properly with "apple.com" and "hackingwithswift.com", I think I'm good

   

Hacking with Swift is sponsored by Essential Developer

SPONSORED From January 26th to 31st you can join a FREE crash course for iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a senior developer!

Save your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.