Coder Social home page Coder Social logo

stleamist / bettersafariview Goto Github PK

View Code? Open in Web Editor NEW
564.0 8.0 56.0 1.98 MB

A better way to present a SFSafariViewController or start a ASWebAuthenticationSession in SwiftUI.

License: MIT License

Swift 100.00%
sfsafariviewcontroller sfauthenticationsession aswebauthenticationsession safari swiftui ios swift

bettersafariview's Introduction

version Swift: 5.1+ iOS: 13.0+ macOS: 10.15+ watchOS: 6.2+
Build on Xcode SwiftPM: compatible license contact: @stleamist

BetterSafariView

A better way to present a SFSafariViewController or start a ASWebAuthenticationSession in SwiftUI.

Contents

Motivation

SwiftUI is a strong, intuitive way to build user interfaces, but was released with some part of existing elements missing. One example of those missing elements is the SFSafariViewController.

Fortunately, Apple provides a way to wrap UIKit elements into SwiftUI views. A common approach to place the SFSafariViewController inside SwiftUI is to create a simple view representing a SFSafariViewController, then present it with a sheet(isPresented:onDismiss:content:) modifier or a NavigationLink button (See RootView.swift in the demo project).

However, there’s a problem in this approach: it can’t present the SFSafariViewController with its default presentation style — a push transition covers full screen. A sheet modifier can present the view only in a modal sheet, and a navigation link shows the two navigation bars at the top so we have to deal with them. This comes down to the conclusion that there’s no option to present it the right way except for using present(_:animated:completion:) method of a UIViewController instance, but it is prohibited and not a good design to access the UIHostingController directly from the SwiftUI view.

BetterSafariView clearly achieves this goal by hosting a simple UIViewController to present a SFSafariViewController as a view’s background. In this way, a ASWebAuthenticationSession is also able to be started without any issue in SwiftUI.

Requirements

  • Xcode 11.0+
  • Swift 5.1+

SafariView

  • iOS 13.0+
  • Mac Catalyst 13.0+

WebAuthenticationSession

  • iOS 13.0+
  • Mac Catalyst 13.0+
  • macOS 10.15+
  • watchOS 6.2+

Usage

With the following modifiers, you can use it in a similar way to present a sheet.

SafariView

Example

import SwiftUI
import BetterSafariView

struct ContentView: View {
    
    @State private var presentingSafariView = false
    
    var body: some View {
        Button(action: {
            self.presentingSafariView = true
        }) {
            Text("Present SafariView")
        }
        .safariView(isPresented: $presentingSafariView) {
            SafariView(
                url: URL(string: "https://github.com/")!,
                configuration: SafariView.Configuration(
                    entersReaderIfAvailable: false,
                    barCollapsingEnabled: true
                )
            )
            .preferredBarAccentColor(.clear)
            .preferredControlAccentColor(.accentColor)
            .dismissButtonStyle(.done)
        }
    }
}

View Modifiers

safariView(isPresented:onDismiss:content:)
/// Presents a Safari view when a given condition is true.
func safariView(
    isPresented: Binding<Bool>,
    onDismiss: (() -> Void)? = nil,
    content: @escaping () -> SafariView
) -> some View
safariView(item:onDismiss:content:)
/// Presents a Safari view using the given item as a data source for the `SafariView` to present.
func safariView<Item: Identifiable>(
    item: Binding<Item?>,
    onDismiss: (() -> Void)? = nil,
    content: @escaping (Item) -> SafariView
) -> some View

SafariView Initializers

init(url:)
/// Creates a Safari view that loads the specified URL.
init(url: URL)
init(url:configuration:)
/// Creates and configures a Safari view that loads the specified URL.
init(url: URL, configuration: SafariView.Configuration)

SafariView Modifiers

preferredBarAccentColor(_:)
/// Sets the accent color for the background of the navigation bar and the toolbar.
func preferredBarAccentColor(_ color: Color?) -> SafariView
preferredControlAccentColor(_:)
/// Sets the accent color for the control buttons on the navigation bar and the toolbar.
func preferredControlAccentColor(_ color: Color?) -> SafariView
dismissButtonStyle(_:)
/// Sets the style of dismiss button to use in the navigation bar to close `SafariView`.
func dismissButtonStyle(_ style: SafariView.DismissButtonStyle) -> SafariView

WebAuthenticationSession

Example

import SwiftUI
import BetterSafariView

struct ContentView: View {
    
    @State private var startingWebAuthenticationSession = false
    
    var body: some View {
        Button(action: {
            self.startingWebAuthenticationSession = true
        }) {
            Text("Start WebAuthenticationSession")
        }
        .webAuthenticationSession(isPresented: $startingWebAuthenticationSession) {
            WebAuthenticationSession(
                url: URL(string: "https://github.com/login/oauth/authorize")!,
                callbackURLScheme: "github"
            ) { callbackURL, error in
                print(callbackURL, error)
            }
            .prefersEphemeralWebBrowserSession(false)
        }
    }
}

View Modifiers

webAuthenticationSession(isPresented:content:)
/// Starts a web authentication session when a given condition is true.
func webAuthenticationSession(
    isPresented: Binding<Bool>,
    content: @escaping () -> WebAuthenticationSession
) -> some View
webAuthenticationSession(item:content:)
/// Starts a web authentication session using the given item as a data source for the `WebAuthenticationSession` to start.
func webAuthenticationSession<Item: Identifiable>(
    item: Binding<Item?>,
    content: @escaping (Item) -> WebAuthenticationSession
) -> some View

WebAuthenticationSession Initializers

init(url:callbackURLScheme:completionHandler:)
/// Creates a web authentication session instance.
init(
    url: URL,
    callbackURLScheme: String?,
    completionHandler: @escaping (URL?, Error?) -> Void
)
init(url:callbackURLScheme:onCompletion:)
/// Creates a web authentication session instance.
init(
    url: URL,
    callbackURLScheme: String?,
    onCompletion: @escaping (Result<URL, Error>) -> Void
)

WebAuthenticationSession Modifier

prefersEphemeralWebBrowserSession(_:)
/// Configures whether the session should ask the browser for a private authentication session.
func prefersEphemeralWebBrowserSession(_ prefersEphemeralWebBrowserSession: Bool) -> WebAuthenticationSession

Known Issues

  • In .webAuthenticationSession(item:content:) modifier, the functionality that replaces a session on the item's identity change is not implemented, as there is no non-hacky way to be notified when the session's dismissal animation is completed.

Installation

Swift Package Manager

Add the following line to the dependencies in your Package.swift file:

.package(url: "https://github.com/stleamist/BetterSafariView.git", .upToNextMajor(from: "2.4.2"))

Next, add BetterSafariView as a dependency for your targets:

.target(name: "MyTarget", dependencies: ["BetterSafariView"])

Your completed description may look like this:

// swift-tools-version:5.1

import PackageDescription

let package = Package(
    name: "MyPackage",
    dependencies: [
        .package(url: "https://github.com/stleamist/BetterSafariView.git", .upToNextMajor(from: "2.4.2"))
    ],
    targets: [
        .target(name: "MyTarget", dependencies: ["BetterSafariView"])
    ]
)

Xcode

Select File > Swift Packages > Add Package Dependency, then enter the following URL:

https://github.com/stleamist/BetterSafariView.git

For more details, see Adding Package Dependencies to Your App.

Demo

You can see how it works on each platform and compare it with the other naive implementations in the demo project. Check out the demo app by opening BetterSafariView.xcworkspace.

NOTE: This demo project is available for iOS 14.0+, macOS 11.0+, and watchOS 7.0+, while the package is compatible with iOS 13.0+, macOS 10.15+, and watchOS 6.2+.

License

BetterSafariView is released under the MIT license. See LICENSE for details.

bettersafariview's People

Contributors

boherna avatar kevvdevv avatar songjiyeon avatar stleamist avatar tunous avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bettersafariview's Issues

Share sheet button doesn't work

I tested this on the demo app and it seems that the share button does not invoke the share sheet when pressed. (doesn't work on all demos)

Unexpectedly found nil while unwrapping an Optional value

I am getting the "Unexpectedly found nil while unwrapping an Optional value" error when trying to call webAuthenticationSession in a SwiftUI project. The error points to line 185 in WebAuthenticationPresenter.swift.

func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
                return coordinator!.viewController.view.window!
            }

My code looks like this:

struct OnBoardingView: View {
    @State var showAuth = true
    var body: some View {
        checkInoReaderAuth()
            .webAuthenticationSession(isPresented: $showAuth) {
                WebAuthenticationSession(url: [my url], callbackURLScheme: nil) { url, error in
                    webAuthSessionClosure(url, error)
                }
            }
    }
}

Welcome any suggestions.

View opens twice

Hi! Just pasted example code into my project:

`...
.onTapGesture() {

                        self.presentingSafariView = true

                    }.safariView(isPresented: $presentingSafariView) {
                        SafariView(
                            url: URL(string: "https://google.com")!,
                            configuration: SafariView.Configuration(
                                entersReaderIfAvailable: false,
                                barCollapsingEnabled: true
                            )
                        )
                        .preferredBarAccentColor(.clear)
                        .preferredControlAccentColor(.accentColor)
                        .dismissButtonStyle(.done)
                    }`

When I tap, the Safari View opens two times, and I need to close two Safaris to get back into my app. Any ideas what could be causing this?

Auto-signs in with some websites

I am using a webauthsession to authenticate my users Spotify accounts. However, once they sign in, the webauthsession auto-signs them in whenever I re-present it. This is annoying because my users may want to sign into a different account, which they can't do if they are auto-signed in. Is there anyway for me to get around this? Seems like a bug with how it is cached even when the app is deleted.

Configuration on NaiveSafariView

It seems there is no way to configure NaiveSafariView at the moment.
For example to add entersReaderIfAvailable: true to a sheet that has NaiveSafariView as its content.

Programmatic URL navigation and dismissal

Is there any current way to update the URL for, or programmatically dismiss an already displayed SafariView? I've tried a number of ways to do this but haven't been able to make it work.

The use case is handling taps arriving from a Widget Extension in .onOpenURL(), and updating the URL accordingly.

Thanks for building the package!

How to load dynamic url

initial
var url = "https://www.github.com"

after click a button or other event, url become another value
url = "https://www.google.com"

the SafariView how to load the lasted url

BetterSafariView Opens URL Twice

Description

BetterSafariView is opened twice on the same URL.

Project Configuration

Xcode 15.1 targeting iOS 17.2. The containing view does not have a navigation stack.

Sample Project

SafariDemo.zip

Demo Video

Simulator.Screen.Recording.-.iPhone.15.-.2024-01-01.at.12.50.53.mp4

Sample Code

The relevant code is in this listing.

import SwiftUI
import BetterSafariView

enum UseCaseButtons: CaseIterable, Identifiable {
    var id: Self { self }

    case networkKit
    case betterSafariView
    case reviewKit
    case urlEncodedForm

    var url: URL {
        switch self {
        case .networkKit:
            URL(string: "https://swiftpackageindex.com/sabapathyk7/NetworkKit").unsafelyUnwrapped
        case .betterSafariView:
            URL(string: "https://swiftpackageindex.com/stleamist/BetterSafariView").unsafelyUnwrapped
        case .urlEncodedForm:
            URL(string: "https://swiftpackageindex.com/interactord/URLEncodedForm").unsafelyUnwrapped
        case .reviewKit:
            URL(string: "https://swiftpackageindex.com/FlineDev/ReviewKit").unsafelyUnwrapped
        }
    }

    var title: String {
        switch self {
        case .networkKit:
            "NetworkKit"
        case .betterSafariView:
            "BetterSafariView"
        case .reviewKit:
            "ReviewKit"
        case .urlEncodedForm:
            "URLEncodedForm"
        }
    }
}

struct ContentView: View {
    @State var selectedUseCase: UseCaseButtons?

    var body: some View {
        ScrollView {
            VStack {
                ForEach(UseCaseButtons.allCases) { message in
                    Button(message.title) {
                        selectedUseCase = message
                    }
                }
                .padding()
                .safariView(item: $selectedUseCase) { useCase in
                    SafariView(url: useCase.url)
                }
            }
        }
    }
}

#Preview {
    ContentView()
}

How to dismiss programatically?

How can I dismiss the view controller programmatically? Following minimal example does not work:

struct MyView: View {
  @State var showView = false

  var body: some View {
    let _ = print("current value: \(showView)")

    Button("Show it") {
      print("showing it")
      showView = true
      DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        print("hiding it")
        showView = false
      }
    }
      .safariView(isPresented: $showView) {
        SafariView(url: URL(string: "https://www.google.com")!)
      }
  }
}

Log:

current value: false
showing it
current value: true
hiding it
current value: false

According to my debugging, view modifier does not detect that the value of the binding changed, this might be related: https://stackoverflow.com/questions/59299260/swiftui-binding-update-doesnt-refresh-view

Support for system light mode.

When using this package, I noticed it's always displayed the safari service view in dark mode.

Is there a way to manually set it, or let it follows the system?

List of URL Items

I've been running into trouble when trying to create a list of items that can be tapped to redirect to the SafariView.

I've tried to use the NaiveSafariView as shown in the demo doesn't give the behavior that I'd like (squished under the navigation view and tab bar)

The .safariView modifier is great, but not scaleable to a list of items.

Attempts to resolve:

  1. One work around would be to create a bunch of $isPresented State variables and assign each item to one of them, but it is not efficient or scaleable.

  2. Another work around is to just assign all of them to the same $isPresented State variable, but this poses a different problem which is that the Url of the webpage must be declared in advance and passed as context to the .safariView modifier, resulting in all items to return the same webpage. In this scenario the swipe to dismiss also causes a bug where it dismisses, goes back to the webpage, then dismisses again.

  3. The last work around tried was to assign each row in the List its own State variable and bind the .safariView to that. But when clicked on that it sends the view into an infinite loop of popping and pushing the webpage that can only be stopped by pressing the "Done" button in the top left corner.

The only solution found currently is to use a navigation link to push a DetailView where the user is able to click "go to webpage" which then pushes to the webpage. This is not preferred as being able to go to the webpage from the original list of items is optimal.

Any ideas are appreciated.

Safari View Controller not presented

I have a .safariView attached to a NavigationView inside a sheet presented by another sheet. When I set the item for the safari view to a non-nil value, this error message is printed out and nothing happens on the screen. How can I fix this?

Attempt to present <SFSafariViewController: 0x10a020000>
on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x104c0aad0> 
(from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x104c0aad0>)
which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x108305f70>

Attempting to load the view of a view controller while it is deallocating is not allowed

Using the WebAuthenticationSession example, verbatim, from the README, on iOS 15.4.

When the popup appears on the device saying "Test App" Wants to Use "github.com" to Sign In, press Cancel on device. The following warning is then produced in the Xcode console:

2022-03-19 10:04:38.212806-0700 Test App[38555:3159860] [Warning] Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<SFAuthenticationViewController: 0x7f9a1481da00>)

Ideas how to fix?

Could not find module `BetterSafariView` for target `x86_64-apple-ios-simulator`

I am getting the following error when trying to build my project on my M1 mac mini.

Could not find module 'BetterSafariView' for target 'x86_64-apple-ios-simulator'; found: arm64, arm64-apple-ios-simulator, at: /Users/username/Library/Developer/Xcode/DerivedData/Project-abcdefg/Build/Products/Debug-iphonesimulator/BetterSafariView.swiftmodule

Any ideas how to fix this? Does BetterSafariView need to be compiled as an XCFramework?

Thanks!

No such module 'BetterSafariView'

BetterSafariView has really messed up my project... can build but cant use editor and so many red errors.

Could not find module 'BetterSafariView' for target 'arm64-apple-ios-simulator'; found: x86_64-apple-ios-simulator, x86_64

using @State variable to change which URL is loaded fails

Hi,

I am using iOS 14.5 and am trying to render a different SafariView depending on which button is clicked. I change the URL on the button action, but I still see a fatal error that nil was unexpectedly found. Any idea what a fix is?
Here is how I was to render the .safariView

VStack {
List {
Button(action: {self.url = appTermsUrl; self.showSafari = true}) {
HStack {
Text("Terms of Service").font(.custom("HelveticaNeue", size: 18))
Image(systemName: "chevron.right")
}
}
Button(action: {self.url = appPrivacyPolicyUrl; self.showSafari = true}) {
HStack {
Text("Privacy Policy").font(.custom("HelveticaNeue", size: 18))
Image(systemName: "chevron.right")
}
}
Button(action: {self.url = appAboutUrl; self.showSafari = true}) {
HStack {
Text("About us").font(.custom("HelveticaNeue", size: 18))
Image(systemName: "chevron.right")
}
}

        }
    }.padding(.top)
        .safariView(isPresented: $showSafari) {
            SafariView(
                url: URL(string: url)!,
                configuration: SafariView.Configuration(
                    entersReaderIfAvailable: false,
                    barCollapsingEnabled: true
                )
            )
            .preferredBarAccentColor(.clear)
            .preferredControlAccentColor(.accentColor)
            .dismissButtonStyle(.done)
        }

Using web authentication session in an app

Understanding how the alert in the demo works:

I’m very new to using oauth and better safari view and I’m trying to set up a login screen.

I’ve noticed in the demo that when you log into GitHub the app goes back to the main screen. Is this handled by setting the callback url scheme to github and then using a redirect url starting with github:// on the oauth provider redirect ?

error: cannot find 'WebAuthenticationSessionOptions' in scope

error: cannot find 'WebAuthenticationSessionOptions' in scope
    @State private var webAuthenticationSessionOptions =  WebAuthenticationSessionOptions()
                                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brandon_kurtz/swiftauthexperiment/Sources/swiftauthexperimenttarg/main.swift:19:35: error: cannot find 'gitHubAuthorizationURLString' in scope
                        TextField(gitHubAuthorizationURLString, text: $webAuthenticationSessionOptions.urlString)
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brandon_kurtz/swiftauthexperiment/Sources/swiftauthexperimenttarg/main.swift:25:35: error: cannot find 'gitHubAuthorizationURLString' in scope
                        TextField(gitHubAuthorizationURLString, text: $webAuthenticationSessionOptions.callbackURLScheme)
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
[1/2] Compiling swiftauthexperimenttarg main.swift

I'm guessing that my personal Package.swift file is wrong in some way but would appreciate any advice if you can spot the problem:

// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "swiftauthexperiment",
    platforms: [
        .macOS(.v11)
    ],
    dependencies: [
        .package(url: "https://github.com/stleamist/BetterSafariView.git", .upToNextMajor(from: "2.3.1"))
    ],
    targets: [
        .target(name: "swiftauthexperimenttarg", dependencies: ["BetterSafariView"])
    ]
)

how to use it inside inside a VStack loop

Hello and thank you for your package :)
My problem is that inside a list of articles (VStack loop) if I use the current README example I get 2 instances/URLs (belonging to 2 different articles) opens every time I click a button.

I now tried:


List(fetch.Novitadss) { Novitads in
                    VStack(alignment: .leading) {


 Button(action: {
                                self.selectedURL = URL(string: Novitads.link)
                                                               }) {
                                                                   Text(Novitads.title)
                                                                       .platformFontNegative()
                                                                           .italic()
                                                               }
                                                 
                            .safariView(item: $selectedURL) {selectedURL in
                                
                                
                                        SafariView(url: selectedURL)
                                    }
                            

but I get again 2 browsers opens at every click (just with the same link now). Thanks in advance for your help.

Originally posted by @gurugeek in #1 (comment)

Example code does not compile

I get the following errors when attempting to compile.

  • Argument passed to call that takes no arguments
  • Type 'SafariView' has no member 'Configuration'
  • Cannot infer contextual base in reference to member 'systemBlue'
  • Cannot infer contextual base in reference to member 'done'

I'm running:

  • Apple Swift version 5.2.4
    Xcode: 11.7
import SwiftUI
import BetterSafariView

struct SafariView: View {

    @State private var presentingSafariView = false

    var body: some View {
        Button(action: {
            self.presentingSafariView = true
        }) {
            Text("Present SafariView")
        }
        .safariView(isPresented: $presentingSafariView) {
            SafariView(
                url: URL(string: "https://github.com/")!,
                configuration: SafariView.Configuration(
                    entersReaderIfAvailable: false,
                    barCollapsingEnabled: true
                )
            )
            .preferredControlTintColor(.systemBlue)
            .dismissButtonStyle(.done)
        }
    }
}

struct SafariView_Previews: PreviewProvider {
    static var previews: some View {
        SafariView()
    }
}

Errors when adding swift package via xcode

When adding the package as a dependency from xcode's add swift package dependency, I keep getting errors of this sort like it's not actually linking against the package properly:
Cannot convert value of type 'Example_App_Name.SafariView' to closure result type 'BetterSafariView.SafariView'

I've done the old derived data dance and still no luck, yet the demo project works fine.

Update:
I had been developing an app with xcode 12 beta, switched to xcode 11 & iOS 13 so I could get a testflight build uploaded, and that's when I started seeing breakage.
I just opened the demo app in xcode 11 and changed the deployment target to ios 13 and I see that there are quite a few errors, so now it makes a lot more sense.

I originally thought it was maybe a problem with the way I included the dep, or the SafariView.Configuration convenience init, but it looks like there are other issues.

Sticky navigation toolbar

As opposed to the native SFSafariViewController, the toolbar for navigation (which remains under the keyboard at all times) is sliding above the keyboard in BetterSafariView.
There does not seem to be any item in SFSafariViewController.Configuration() to control the placement.

Any ideas?

122614309-68dbd600-d054-11eb-87de-de229d0a40fb

What if you need a Access Token back?

`
//this what i am trying below, but no code returned. any idea where would it return the code?

@State private var startingWebAuthenticationSession = false

var body: some View {
    Button(action: {
        self.startingWebAuthenticationSession = true
    }) {
        Text("Login")
    }
    .webAuthenticationSession(isPresented: $startingWebAuthenticationSession) {
        WebAuthenticationSession(
            url: URL(string: "https://accounts.spotify.com/authorize")!,
            callbackURLScheme: "spotify"
        ) { callbackURL, error in
            print(callbackURL, error)
        }
        .prefersEphemeralWebBrowserSession(false)
    }
}

`

ColorScheme not working

Thanks for the lib, when passing color scheme (light/dark mode)

 .preferredBarAccentColor(Color.BackgroundColor)
  .preferredControlAccentColor(Color.TintColor)

The safariView colors wont update even when doing a new fresh launch

Interference with navigation bar in iOS 15

I'm not sure if there is anything this package can do about this, but I experienced an issue in iOS 15 and at least it might help somebody else.

The problem:

If you have a parent-child view scenario with a NavigationView in the parent view and a ScrollView in the detail/child view, you must not attach .safariView() to the ScrollView.

This was perfectly fine in iOS 14, but it seems in iOS 15 the navigation no longer detects the ScrollView, or at least the scroll position and therefore, the navigation bar at the top does not update when the user scrolls down.

Solution:

Simply attach .safariView() to an element inside ScrollView { … }.

I hope my description makes sense. I have no deeper insights, I only narrowed down the issue in my app and came up with this solution. Hope it helps somebody.

Expose item to onDismiss closure

Awesome work with v2, congrats :)

It would be useful if the presented item is also exposed to the onDismiss closure, to adjust "cleanup" actions based on the item that was visible. Think of tracking each item that was opened, …

struct CustomItem {
 var id: String
  var name: String
  var url: URL?
  //…
}

struct ArticleList : View {
  // …
  @State private var itemToShow: CustomItem? = nil

  var body: some View {
      List {
        ForEach(viewModel.feedItems) { item in
           Button(action: { itemToShow = item }) {
               // …
          }
        }
      }.safariView(item: $itemToShow, onDismiss: { item in // <-- not possible at the moment
        print("Mark Item \(item.name) as read")
      }) { item in
            SafariView(
              url: item.url,
               configuration: SafariView.Configuration(
                // …
                ))
        }
  }

preferredControlAccentColor does not support dark mode in Asset Catalog colors

Hey,

I'm using the pre-defined AccentColor color in the Asset Catalog of my app, and I've struggled a bit applying it to the SafariView.

I initially tried this, which I'm using in a few places in my app:

.preferredControlAccentColor(.accentColor)

Unfortunately, this resulted iOS' default blue accent color being used. I guess SFSafariViewController lives in its own context that ignores the accent color?

I then tried loading the AccentColor from the Asset Catalog like this:

.preferredControlAccentColor(Color("AccentColor"))

This worked fine in light mode, but failed in dark mode: The light mode color was used in both scenarios.

I finally got it to work by switching back to the deprecated method, setting the UIColor directly:

.preferredControlTintColor(UIColor(named: "AccentColor"))

This works - it appears converting from Color to UIColor loses a lot of information!

I'm not sure if there's a good way to solve this, but it might be worth putting this into the README.md.

2 different BSVs in same View

I have 2 Buttons in the same View. Each of them should open a BSV with given URLs slnURL[0] and slnURL[1]:

Button("Show details") {
                        showSafari.toggle()
                    }
                    .safariView(isPresented: $showSafari) {
                        SafariView(
                            url: URL(string: slnURL[0])!,
                            configuration: SafariView.Configuration(
                                entersReaderIfAvailable: false,
                                barCollapsingEnabled: true
                            )
                        )
                        .preferredBarAccentColor(.clear)
                        .preferredControlAccentColor(.accentColor)
                        .dismissButtonStyle(.close)
                    }
Button("Show details") {
                        showSafari.toggle()
                    }
                    .safariView(isPresented: $showSafari) {
                        SafariView(
                            url: URL(string: slnURL[1])!,
                            configuration: SafariView.Configuration(
                                entersReaderIfAvailable: false,
                                barCollapsingEnabled: true
                            )
                        )
                        .preferredBarAccentColor(.clear)
                        .preferredControlAccentColor(.accentColor)
                        .dismissButtonStyle(.close)
                    }

When running the App both buttons open the URL from the first Button in the View.

E.g.:
First Button URL: google.com, Second Button URL: amazon.com -> Opens google.com from both Buttons
First Button URL: amazon.com, Second Button URL: google.com -> Opens amazon.com from both Buttons

Is this expected behavior? Am I doing something wrong?

Thanks for your help in advance :)

Package does not have version tags

I'm trying to use this package in Swift Playgrounds 4 and I get an error saying "package does not have version tags" when trying to add this package.

Crash when used with URL without scheme

Example: //someplace.com will crash the application.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported.'

WebAuthenticationSession fails on iOS 14.1

Unfortunately, I get an exception on iOS 14.1: "Fatal error: Unexpectedly found nil while unwrapping an Optional value: file BetterSafariView/WebAuthenticationPresenter.swift, line 185". On iOS 14.6 everything works great tho'.

I've carefully studied the docs and implemented it like shown in the code example.

URL goes into external browser on Mac Catalyst.

An interesting (actually weird) issue here, when running on Mac Catalyst, instead of showing the specified URL with the ViewController, it opens externally with the default browser:

Screen.Recording.2024-02-17.at.13.27.45.mp4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.