Giter Site home page Giter Site 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 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

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

`

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

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!

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

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

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.

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

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.

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>

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!

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"])
    ]
)

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

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?

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

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

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.

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.

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)

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

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

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.

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.

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.

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)

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.

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.'

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?

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 ?

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(
                // …
                ))
        }
  }

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

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?

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.