stleamist / bettersafariview Goto Github PK
View Code? Open in Web Editor NEWA better way to present a SFSafariViewController or start a ASWebAuthenticationSession in SwiftUI.
License: MIT License
A better way to present a SFSafariViewController or start a ASWebAuthenticationSession in SwiftUI.
License: MIT License
`
//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)
}
}
`
I am wondering if there should be an example of using inside a NavigationLink since there is an example of the native view for this scenario.
BetterSafariView is opened twice on the same URL.
Xcode 15.1 targeting iOS 17.2. The containing view does not have a navigation stack.
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()
}
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!
I want to use SafariView without Cookies.
How to remove Cookies? or Launch without Cookies?
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
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 :)
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:
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.
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.
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 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
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.
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>
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
@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"])
]
)
Unfortunately, universal links do not open the app.
I tried everything, including https://stackoverflow.com/questions/61748589/does-aswebauthenticationsession-support-universal-links
Does anyone have a tip?
Thanks !! :)
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
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?
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
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.
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.
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.
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)
I get the following errors when attempting to compile.
I'm running:
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()
}
}
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)
}
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.
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.
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.
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.
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.
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)
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.
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.'
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?
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 ?
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(
// …
))
}
}
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:
In Mac apps built with Mac Catalyst, SFSafariViewController launches the default web browser instead of displaying a modal window.
Perhaps a custom WKWebView to look like SFSafariViewController?
Might be out of scope for this project tho.
https://github.com/JakubMazur/SwiftUIWKWebView could be useful
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?
When I try to click on the navigate to previous url button in SafariView, nothing happens. How can I fix it?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.