In my app, I have functionality where the user could open another app lets call it as 'App2'. If App2 is not present on the device, then user will be present with an app not available alert that I created, lets call this as Alert1.
However if App2 is present on the device and user tries to open it, Apple's "${App} wants to open App2" dialog is presented. If user clicks 'Cancel' on this, the callback executes my code to present Alert1.
I don't want my app to display Alert1 when user clicks 'Cancel' on Apple's dialog. Is there a way to control Apple's dialog?
Below is my code:
if let url = urlComponents.url {
UIApplication.shared.open(url, completionHandler: { success in
if !success {
showAppNotAvailableAlert(url.absoluteString, actionLabel: action.label)
}
})
return
}
try
if let url = urlComponents.url {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, completionHandler: { didURLOpen in
if !didURLOpen {
debugPrint("User pressed cancel button")
}
})
}
else {
showAppNotAvailableAlert(url.absoluteString, actionLabel: action.label)
}
return
}
idea is to check if app exists by using canOpenURL, if it exists then try to open the app and handle error in completion block
Related
Opening settings URLs works for me from a UIAlertController but not from a UNUserNotificationCenter notification. Both approaches use the same URLs and the same code, namely this function:
func open() {
if let url = self.url {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, completionHandler: { (success) in
Log.log("Opened settings url: \(url), \(success)", true)
})
}
}
}
My logging line shows the completionHandler gets called with true from the alert and false from the notification. At first I thought it might be an issue with the phone being locked, but I also got false through a notification interacted with on the home screen.
What do I need to do to get this to work from notifications?
Try it with ".foreground" in options while declaring UNNotificationAction.
(this action should cause the application to launch in the foreground.)
In my application, there is an option to make a call when the user taps a phone number. I'm implementing this as shown below:
if let url = URL(string:"tel://\(String(describing: Util.checkForNullString(contactNo)))"), UIApplication.shared.canOpenURL(url){
if #available(iOS 10, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
I want to do another action soon after the user finishes the call. But how to get notified when the call is finished ?
I am writing UI test cases for my project.
My project flow is as below:
Login Screen. User enters credentials and press login.
Home Screen. There is location requirement so system as for user's permission. I allow it.
Logout.
So when I do fresh install of application this flow is recorded in test case and works if I perform on new fresh build.
But problem is when I test on old build there is no alert for location permission and the test's gets fail. How can I handle this cases or ask user for permission every time when I run tests?
For resetting credentials of user I am passing launchArguments to XCUIApplication() and handle in AppDelegate.
I have implemented code let me know if its correct way:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
alert.buttons["Only While Using the App"].tap()
return true
}
The above code works for both if alert comes or not.
Using an interruption monitor is the correct way. However, it's safer to check if the alert being displayed is the alert you're expecting before you interact with the alert:
addUIInterruptionMonitor(withDescription: "Allow “APP” to access your location?") { (alert) -> Bool in
let button = alert.buttons["Only While Using the App"]
if button.exists {
button.tap()
return true // The alert was handled
}
return false // The alert was not handled
}
Try this
let app2 = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let button = app2.alerts.firstMatch.buttons["Allow While Using App"]
button.waitForExistence(timeout: 10)
button.tap()
I use the following code to allow user's location:
// MARK: - Setup
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launch()
addUIInterruptionMonitor(withDescription: "System Dialog") { (alert) -> Bool in
alert.buttons["Allow Once"].tap()
return true
}
}
In this setup, I "register" the interruption monitor for tapping the allow button, so in this case I can dismiss that modal. Now, there's my test:
// MARK: - Test change mall
func testChangeMall() {
let selectorChangeButton = app.buttons["change_mall_button"]
XCTAssert(selectorChangeButton.exists, "Selector change button does not exist")
selectorChangeButton.tap()
app.navigationBars.firstMatch.tap()
let cell = app.staticTexts["Shopping Centre"]
XCTAssert(cell.exists, "There's no cell with this title")
cell.tap()
sleep(1)
let label = app.staticTexts["Shopping Centre"]
XCTAssert(label.exists, "Nothing changes")
}
In this test, simply I go to a view controller with a list sorted by location. First, I need to dismiss the location's system alert. So, first I dismiss that modal and then I tap a cell from my TableView. Then, I need to show it in my main view controller so I dismiss my view controller and I expect the same title.
Happy Coding!
at the start of my UI test I have
addUIInterruptionMonitor(withDescription: "Location Dialog") { (alert) -> Bool in
let button = alert.buttons["Allow"]
if button.exists {
snapshot("request location service")
button.tap()
return true
}
return false
}
which should dismiss the location services request dialog, but it does nothing and it never reaches the handler. I have also tried to set this code in setUp() but it didn't work either.
I think the problem might be that the first thing that happens in the app is that the dialog is being shown, it may be too soon (it may happen before addUIInterruptionMonitor is called)
How can I solve this issue?
You have to interact with the app right after adding the UIInterruptionMonitor. This can be a simple tap:
addUIInterruptionMonitor(withDescription: "Location Dialog") { (alert) -> Bool in
let button = alert.buttons["Allow"]
if button.exists {
button.tap()
return true
}
return false
}
// interact with the app
app.tap()
If app.tap() interferes with your test you could also use app.swipeUp()
Be aware that the location service permission dialog changed in iOS11. There are now 3 Buttons, so you have to use alert.buttons["Always Allow"] to dismiss the dialog.
I have a function that places a phone call when a button is pressed.
private func callNumber(phoneNumber:String) {
if let phoneCallURL = URL(string: "tel://\(phoneNumber)") {
let application:UIApplication = UIApplication.shared
if (application.canOpenURL(phoneCallURL)) {
application.open(phoneCallURL, options: [:], completionHandler: nil)
}
}
}
I want to add some functionality if the users hit cancel when the alert pops up to confirm the call. How would I do that?
According to this question: Prompt when trying to dial a phone number using tel:// scheme on iOS 10.3
This alert is actually a bug in iOS 10.3 and should be removed at some point in the future. It isn't supposed to come up for "tel:" links in native apps.
That said, I don't believe there is a way to detect the alert and how the user interacts with it.