SFSafariViewController:隐藏导航栏

12
我已经成功通过SFSafariViewController使我的应用程序自动加载了一个url,参考post。它的工作非常出色,但唯一的缺点是导航栏。
使用这种方式时,SFSafariViewController的导航栏有些无用,因为url是只读的,而“完成”链接除了重新加载页面外没有其他作用。 因此,我想完全隐藏导航栏。
根据接受答案所附的评论建议,建议将我的根视图控制器设置为SFSafariViewController,但我无法让其运行。 这个设置很简单,因为只有一个视图控制器,其中包含上述帖子中的代码。
如何隐藏导航栏,但仍然保持SFSafariViewController的好处? 或者,如果我无法隐藏导航栏,至少可以隐藏“完成”链接吗?
代码片段:
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.
    }
}

----- 工作正常。导航栏被“隐藏” -----

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
    }
}

你能够继承 SFSafariViewController 并在 viewWillAppear: 中隐藏导航栏吗? - JAL
1
我可以尝试... 我在iOS开发方面非常新手,所以任何代码片段肯定会有所帮助。 - Mike Purcell
你可以尝试这样做: self.navigationItem.rightBarButtonItem = nil - Craig Otis
@CraigOtis:看起来不起作用,因为“完成”链接仍在呈现。我更喜欢删除整个导航栏。但是,我想知道在SFSafariViewController的上下文中,导航栏是否指底部导航菜单。 - Mike Purcell
不应该这样 - 底部菜单是“工具栏”,我认为更好的做法可能是如果你需要全屏解决方案,可以切换到“UIWebView”。 - Craig Otis
显示剩余3条评论
4个回答

8

将此代码放在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
}

要隐藏状态栏,请在您的info.plist文件中将View controller-based status bar appearance设置为YES,并在您的视图控制器中插入以下内容。

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

警告:我建议你不要使用SFSafariViewController来进行全屏浏览,因为无法重新加载页面(因为刷新按钮在UINavigationBar中)。如果请求失败,将使应用程序无法使用。 相反,最好使用带有自定义工具栏的全屏WKWebView。

更新: 为了避免隐藏刷新按钮,只需在你的SFSafariViewController上添加一个视图/ imageView,并使按钮不可见或至少无法点击即可。

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)
}

这种方法的问题在于叠加层会一直停留在屏幕上,但如果您能找到一个漂亮的图片来替代它,就没问题了。

成功解决了 prefersStatusBarHidden 的问题,谢谢。但是 SFSafariViewController 不是提供了更多的优势吗?例如处理 cookie 和更好的 JavaScript 渲染(通过 nitro)?对于我们来说,cookie 处理非常重要,因为现在我们可以允许通过移动设备分享到 Facebook。 - Mike Purcell
1
是的,它肯定会。也许苹果将来会在SafariServices中提供更多选择。 - Sahil Kapoor
我点赞了你的回答,因为它解决了问题,但是我会暂时不接受它,以防有更好的解决方案。再次感谢你的帮助。 - Mike Purcell
15
多么可怕的黑客攻击。 - Magoo
3
为了避免隐藏重新加载按钮,只需在SFSafariViewController中添加一个视图/ imageView覆盖完成按钮,并使按钮不可见或至少无法点击即可。- 我不建议这样做,因为苹果关于SafariViewController的文档中有重要说明:根据App Store审核指南,必须使用此视图控制器向用户呈现信息;控制器不能被其他视图或层隐藏或遮挡。此外,应用程序不得使用SFSafariViewController跟踪用户而不经过他们的知情和同意。 - Morten Gustafsson
显示剩余5条评论

4

自定义SafariViewController可能不是一个好主意。

苹果的指南明确说明:

SafariViewController必须用于向用户可见地呈现信息;控制器不能被其他视图或图层隐藏或遮挡。此外,应用程序不得使用SafariViewController在未经用户知情和同意的情况下跟踪用户。

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


2
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
        }
    }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接