13

I was able to get my app to automatically load a url via the SFSafariViewController per this post, and it works great, the only drawback is the navbar.

The SFSafariViewController navbar is kind of useless when being used this way, as the url is read-only, and the 'done' link doesn't do anything but reload the page. As such, I would like to hide the navbar altogether.

Per the comments attached to accepted answer, it was suggested to set my root view controller to SFSafariViewController which I can't get working. The setup is simple as there is a single view controller with the code included in the aforementioned post.

How can I hide the navbar but still maintain the benefits of the SFSafariViewController? Or if I can't hide the navbar, at least hide the 'done' link?

Code snippet:

import UIKit import SafariServices class ViewController: UIViewController { private var urlString:String = "https://example.com" override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let svc = SFSafariViewController(URL: NSURL(string: self.urlString)!) self.presentViewController(svc, animated: true, completion: nil) self.navigationItem.rightBarButtonItem = nil } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

----- Works. Navbar is "hidden" -----

import UIKit import SafariServices class ViewController: UIViewController { private var urlString:String = "https://example.com" override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. // This will remove the status (battery, time, etc) bar UIApplication.sharedApplication().statusBarHidden = true } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let svc = SFSafariViewController(URL: NSURL(string: self.urlString)!) // Kind of a hack, in that we really aren't removing the navbar // Rather we are adjusting the starting point of the vpc object so it appears as the navbar is hidden self.presentViewController(svc, animated: true) { var frame = svc.view.frame let OffsetY: CGFloat = 42 frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY) frame.size = CGSize(width: frame.size.width, height: frame.size.height + OffsetY) svc.view.frame = frame } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // For this to work be sure to set the following setting to OFF, in info.plist // 'View controller-based status bar appearance' override func prefersStatusBarHidden() -> Bool { return true } } 
8
  • Can you subclass SFSafariViewController and hide the nav bar on viewWillAppear:? Commented Nov 19, 2015 at 19:54
  • 1
    I can try... I'm hella newb at ios dev so any code snippets would def help. Commented Nov 19, 2015 at 20:06
  • You can try something like: self.navigationItem.rightBarButtonItem = nil Commented Nov 19, 2015 at 20:34
  • @CraigOtis: Doesn't appear to work, as the Done link is still rendering. I'd prefer to remove the entire nav bar. However, I wonder if in the context of SFSafariViewController, navbar refers to the bottom navigation menu. Commented Nov 19, 2015 at 20:53
  • It shouldn't - the bottom menu is the toolbar, I think a better approach might be to switch to UIWebView if you're needing a fullscreen solution. Commented Nov 19, 2015 at 21:44

4 Answers 4

8

Put this code in viewDidAppear:

let safariViewController = SFSafariViewController(URL: url) presentViewController(safariViewController, animated: true) { var frame = safariViewController.view.frame let OffsetY: CGFloat = 64 frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY) frame.size = CGSize(width: frame.width, height: frame.height + OffsetY) safariViewController.view.frame = frame } 

To hide the status bar, set View controller-based status bar appearance to YES in your info.plist file and insert this in your view controller.

override func prefersStatusBarHidden() -> Bool { return true } 

Warning: I will suggest you against using SFSafariViewController for full screen view because reloading is not possible(since reload button is in UINavigationBar). In case request fails, it will render the application useless. Rather go for full screen WKWebView with custom toolbar instead.

Update: To avoid hiding the reload button, just add a view/imageView over the done button in your SFSafariViewController and render button invisible or at least untappable.

presentViewController(svc, animated: true) { let width: CGFloat = 66 let x: CGFloat = self.view.frame.width - width // It can be any overlay. May be your logo image here inside an imageView. let overlay = UIView(frame: CGRect(x: x, y: 20, width: width, height: 44)) overlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5) svc.view.addSubview(overlay) } 

The problem with this approach is only that overlay stays on screen, but if you can find a nice image for it, you will be fine.

Sign up to request clarification or add additional context in comments.

10 Comments

Ic, so the suggestion is to move the svc object up 64 pixels, thereby 'hiding' the navbar. It works. The only issue left is the prefersStatusBarHidden override doesn't seem to be working, as the status bar is still rendering.
Got the prefersStatusBarHidden to work. Thanks. But doesn't the SFSafariViewController offer more advantages such as cookie handling and better javascript rendering (via nitro)? The cookie handling is huge for us as we can now allow FB shares via mobile.
Yes, it definitely does. May be apple will give more choices in SafariServices in future.
What a terrible hack
"To avoid hiding the reload button, just add a view/imageView over the done button in your SFSafariViewController and render button invisible or at least untappable." - I wouldn't recommend that due to the Apple documentation on SafariViewController. From Apple documentation: Important In accordance with App Store Review Guidelines, this view controller must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SFSafariViewController to track users without their knowledge and consent.
|
5

Customising SafariViewController may not be a good idea.

The Apple Guidelines clearly says

SafariViewController must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SafariViewController to track users without their knowledge and consent.

Refer:-https://developer.apple.com/app-store/review/guidelines/

Comments

3
import Foundation import UIKit import SafariServices class MySafariFullScreenViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //WONT WORK read only you need to override it in this VC or in SFSafVC using extension - see bottom of this code //self.prefersStatusBarHidden = true } override func viewDidAppear(_ animated: Bool){ let urlString = "https://......" //if a log screen - i think SFSafariViewController can handle this //let urlString = "https://<domain>login?redirect=https:<homescreen>" if let url: URL = URL(string: urlString) { let safariViewController = SFSafariViewController(url: url) present(safariViewController, animated: true) { var frame = safariViewController.view.frame //if status bar not hidden l//et OffsetY: CGFloat = 64 //if status bar hidden let OffsetY: CGFloat = 44 frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY) frame.size = CGSize(width: frame.width, height: frame.height + OffsetY) safariViewController.view.frame = frame } }else{ //url error } } //this is for this vc - but for SFSafariVC you need override using extension override var prefersStatusBarHidden: Bool{ get{ return true } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } extension SFSafariViewController{ override open var prefersStatusBarHidden: Bool{ get{ return true } } } 

Comments

1

Just present it using presentViewController:animated:completion:

https://stackoverflow.com/a/40460594/842655

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.