How can I open URLs in watchOS? - swift

Can a standalone Apple Watch app open a URL like we can in iOS:
UIApplication.sharedApplication().openURL(url!)
I want to display a message about an update when a new app is published. I want the user to go the URL for the update. Is there any good way?

The following answer works in watchOS 6.2 and above. It initiates a web authentication session, which opens a web view, similar to WKWebView on iOS. You can even swipe from the left to go back.
Keep in mind that it doesn't save cookies, so, for example, if you log in to a website and close it, you have to log in again when you open it back up.
import AuthenticationServices
import SwiftUI
struct ContentView: View {
var body: some View {
Button("Tap me") {
guard let url = URL(string: "https://example.com") else {
return
}
// Source: https://www.reddit.com/r/apple/comments/rcn2h7/comment/hnwr8do/
let session = ASWebAuthenticationSession(
url: url,
callbackURLScheme: nil
) { _, _ in
}
// Makes the "Watch App Wants To Use example.com to Sign In" popup not show up
session.prefersEphemeralWebBrowserSession = true
session.start()
}
}
}

I don't know if you're using SwiftUI or not, but the Link View is shown in the Documentation as available for watchOS. However using it in practice only prompts the user to open the link on their iPhone. As a standalone app since Safari is not available on watchOS you might want to consider other options to alert your user of an update.
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, World!")
Link("Apple.com", destination: URL(string: "https://www.apple.com")!)
}
}
}

Related

Prevent open multiply tabs (Safari App Extension)

I'm currently working on a Safari App Extension for specific site site (example.com for example) and configure toolbar item to show popover. But if safari have not tab with loaded site.com then this site must be loaded in new tab. Code in SafariExtensionHandler
override func popoverWillShow(in window: SFSafariWindow) {
if SafariExtensionHandler.thePage == nil {
let theURL = URL(string: "https://example.com")
window.openTab(with: theURL, makeActiveIfPossible: true)
}
}
static property thePage get its value when handler receive first message from script, but there need some time for page loading and message from script will be send. While the page is loading second click on extensions toolbar item open new tab with example.com, next click open next tab... Block new tab opening I tried like this
override func popoverWillShow(in window: SFSafariWindow) {
if SafariExtensionHandler.thePage == nil && loadingInProgress != true {
loadingInProgress = true
let theURL = URL(string: "https://example.com")
window.openTab(with: theURL, makeActiveIfPossible: true)
}
}
Because all tabs in Safari lives in sandbox opning new tab reset all property of SafariExtensionHandler to it default value.
How to prevent open multiply tabs.
Thank you.

Is it possible to start the NavigationSplitView in an expanded state on macOS using SwiftUI?

I like the sidebar to be opened at launch.
However when I build and run the app, this is what I get.
So I need to click on the sidebar icon to show it. This is not the behavior I want. Is it possible to change this?
Somehow, without explicitly setting it in code, the app likes to change the column visibility to .detailOnly at launch. To avoid this behavior, I explicitly set it to .all at onAppear
#State private var columnVisibility =
NavigationSplitViewVisibility.all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
Text("Side bar")
} detail: {
Text("Main part")
}
.onAppear() {
columnVisibility = .all
}
}

Launch windows in a SwiftUI App-based project from custom events on macOS

In a SwiftUI macOS app that uses the SwiftUI App lifecycle I have been struggling to understand how to launch a new window and then assign it some initial state.
Using Xcode 12.5’s new project we get:
import SwiftUI
#main
struct StackOverflowExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
To keep the question simple, let’s say that I would like to launch a new window every minute and send the time the window was launched to the view. For this we can use a Timer like so:
Timer.scheduledTimer(
withTimeInterval: 60,
repeats: true,
block: {_ in
// do something here that launches a new window containing
// ContentView and sends it the current time
}
)
Any ideas on how to proceed?

PHPickerViewController hide Search Bar and Navigation Bar

I've been trying to implement a photo selection feature in a new app. My current approach is to use a PHPickerViewController embedded in a UIViewControllerRepresentable to display in a swiftUI view.
This is my makeUIViewController function.
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration()
configuration.filter = filter
configuration.selectionLimit = limit
let controller = PHPickerViewController(configuration: configuration)
controller.delegate = context.coordinator
return controller
}
It is inside a struct named PhotoPicker :
struct PhotoPicker: UIViewControllerRepresentable {
What I want to hide is this part :
Yes, all of that.
Let me explain myself, the PickerView is always presented, it is not a pop-up, so there is no need for a cancel button. As you can see there is no done button either. That's because only one image needs to be selected so what happens is when the user taps on an image, the event that a new image was selected is called immediately. Removing the need for user confirmation. Then concerning the search bar, I don't really want it, I just want the user to select a photo and finally the little switch between photos and albums isn't really necessary in my case either.
I've tried a lot of different ways, including trying to set options for the controller when it is created in makeUIViewController. These options were for example :
controller.navigationController?.setToolbarHidden(true, animated: false)
controller.navigationController?.setNavigationBarHidden(true, animated: false)
And I also tried invoking view modifier in my SwiftUI body :
PhotoPicker(filter: .images, limit: 1) { (results) in
}
.navigationBarTitle("")
.navigationBarHidden(true)
.statusBar(hidden: true)
.navigationBarBackButtonHidden(true)
But again, none of them seems to work. So that's why I'm asking here, because it seems I tried everything and nothing is working...

Using ObservableObject to navigate to different views using SwiftUI

I'm trying to create logic that will send the user to the correct view once they have entered their credentials. In the login page, when the user logs in they get a token that can be used to call an API. I store that token in KeychainSwift. I then can check to see if the field where I stored it has an entry that is not null and not empty to route the user to the main page. I'm using logic like this and this to route me to the correct view.
My content view code is as follows:
struct ContentView: View {
#ObservedObject var userAuth = UserAuth()
var body: some View {
if(self.userAuth.isLoggedIn){
return AnyView(MainPageView())
}else{
return AnyView(AccountPageView())
}
}
}
UserAuth is as follows:
import Combine
class UserAuth: ObservableObject {
// let objectWillChange = ObservableObjectPublisher()
#Published var isLoggedIn: Bool = false;
init() {
let keychain = KeychainSwift()
let userToken = keychain.get("userToken") ?? ""
if(!userToken.isEmpty || userToken != "" ){
self.isLoggedIn = true
}else{
self.isLoggedIn = false
}
}
}
The overall architecture im trying to achieve is this:
The issue is that there is no direct way to route from a view to another hence why I resorted to using logic that that displayed in ContentView. I have similar logic for login. I have a view (loginformview) that either routes you to the login form view or to the main page view. But once you login in the login form I would need to go back to the previous view (loginformview) where the check exist to see if I should return the login page or go to the main page(this time sending you to the main page). It seems very cyclical, anyone had any idea to proper tackle logic like this ?