I want to show an activity indicator after the user enters login credentials and clicks the login button. This seemed straight forward but the indicator is not showing when I run (build succeeded). I am not sure if this is because when the app runs for real, it will be passing the credentials up to a server for verification but that code is not active yet, so the login is instantaneous, or if I have written this wrong but not to cause an error. Thank you for your help.
#IBAction func loginButtonTapped(sender: AnyObject) {
//add error checking for loginEntered and passwordEntered if they are blank
if loginEntered.text == "" || passwordEntered.text == "" {
//Define the variable error for the message that should be displayed
self.alertError = "Please enter your Login ID and/or Password"
}
if self.alertError != "" { //if there is an error with the login
//Display the error message on screen
self.displayAlert("Missing Required Information", error: alertError)
//reset error variable
self.alertError = ""
//return the user to the LoginID field and empty it if there is data in it. Empty the password field too. ?? How do I do that??
} else { //the login ID and password are entered
//setup for a spinner to notify the user the app is working on something
activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 80, 80))
activityIndicator.center = self.view.center;
activityIndicator.backgroundColor = (UIColor(white: 0.3, alpha: 0.5)) //creates a background behind the spinner
activityIndicator.layer.cornerRadius = 10
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
The code goes on to several if statements based on the login credentials and returning data from the server. Finally, is stops ignoring interaction events. Finally, I put this same code into an IBAction for a button I created to test the code. It works for the button.
Your code is fine or rather I would say it works, as mention is because the process takes milliseconds and not persives, I recommend that you put breakpoints in your code so that when you press Build can view the interaction to steps in your code.
Related
I'm trying to lock my app when the app goes to background and the user can unlock the app when the app is in the foreground using biometric (FaceID/TouchID) authentication.
Here's a simple, reproducible example of my code:
import LocalAuthentication
import SwiftUI
struct ContentView: View {
#State var isUnlocked = false
var body: some View {
if isUnlocked {
// if the app is unlocked, app shows the text "Unlocked"
Text("Unlocked")
.font(.title)
// app gets locked when the app goes to background
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
self.isUnlocked = false
print("locked the app")
}
} else {
// if the app is locked, app shows the text "Locked" and app should show prompt FaceID/TouchID prompt
Text("LOCKED")
.font(.title)
// FaceID prompt shows when the app opens (from Non-running state)
.onAppear(perform: authenticate)
// FaceID prompt shows when the app coming from background to foreground
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
authenticate()
print("back inside the app")
}
}
}
// I use this to prompt the biometric authentication
func authenticate() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "We need to unlock your data"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
DispatchQueue.main.async {
if success {
// app gets unlocked if biometrix authentication succeeded
self.isUnlocked = true
} else {
// authentication failed
}
}
}
} else {
// no biometrics
}
}
}
When the user opens the app (from non-running state), FaceID prompt shows instantly without any delay. BUT when the app comes from background to foreground, FaceID prompt takes around 5 seconds to show up. I use the same function authenticate() to prompt the biometric authentication and Xcode console prints "back inside the app" instantly when the app comes from background to foreground. So what causes that FaceID delay?
Please help me. Thanks.
i want to put function with "sharing facebook" when "user start live"
if that Fb Button is on then user touches that Live Button,
the content will publish on user's timeline on facebook automatically, then start "Live Broadcasting"
so the ShareDialog will not be present up.
but if ShareDialog should be presented for permission,
i want to do it when user touches that fb button.
======== ref
https://developers.facebook.com/docs/sharing/opengraph/ios
var content = FBSDKShareLinkContent()
content.contentURL = URL.init(string: "https://www~")
content.hashtag = FBSDKHashtag(string: "#ABCDE")
// content.contentTitle = self.broadcastingInfo.title ?? ""
// content.imageURL = self.broadcastingInfo.image
// var shareDialog = FBSDKShareDialog()
// shareDialog.shareContent = content
// shareDialog.mode = .native
// try shareDialog.show()
// do not want shareDialog
FBSDKShareAPI.share(with: content, delegate: self)
// error : The operation couldn’t be completed. (com.facebook.sdk.core error 8.)
I'm getting this error in Xcode.
2018-02-26 07:13:22.326888-0500 Watch Extension[1298:2691330] [View]
First responder warning: '<SPInterfacePicker: 0x14dc1740; frame = (76
0; 58 44); gestureRecognizers = <NSArray: 0x14dcd8a0>; layer =
<CALayer: 0x14dc1910>>' rejected resignFirstResponder when being
removed from hierarchy
My InterfaceController has 4 WkInterfacePickers and it seems like this error might be related to presenting an alert (when the user saves data), but I am not sure.
Has anyone else ever seen this?
My code:
if successSaving == true {
DispatchQueue.main.async {
WKInterfaceDevice.current().play(.success)
self.showSuccessAlertWith(message: "Workout Saved, Stats Added.")
}
func showSuccessAlertWith(message: String){
let action1 = WKAlertAction(title: "OK", style: .default) {
WKInterfaceController.reloadRootPageControllers(withNames: ["InterfaceController"],
contexts: nil,
orientation: .vertical,
pageIndex: 0)
}
presentAlert(withTitle: "Success", message: message, preferredStyle: .alert, actions: [action1])
}
}
I think what is happening is that WKInterfacePickers are very easy to accidentally leave in a "still editing" state, in other words if you scroll through the values then tap "Done" button (which calls reloadRootPageControllers) the system thinks the user was still in the process of editing the picker's value.
I can just ask users to be more careful (unlikely)...but I am unsure how to solve which in iOS the equivalent would be calling resignFirstResponder.
Neither resignFocus nor setting isActive to false, according to my testing, prevent this message from logging.
How can I prevent a simple NSAlert from being dismissed?
F.ex., when the application launches, I show a NSAlert with a NSTextField included.
The user shall type in a password. Only if the password is correct, the user should be allowed to use the application, if not (if the password is not correct), the Alert should stay there and ask again for the password.
This is my code so far (to create the alert):
func applicationDidFinishLaunching(_ aNotification: Notification){
let alert = NSAlert()
alert.addButton(withTitle: "Send")
alert.delegate = self
alert.alertStyle = .informational
alert.messageText = "Password - Login"
alert.informativeText = "Please type in your password: "
let txt = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
txt.stringValue = "Password:"
alert.accessoryView = txt
alert.beginSheetModal(for: NSApplication.shared().mainWindow!) { (response) in
if (response == NSAlertFirstButtonReturn) {
// the alert closes here, is there any way to prevent this?
} else {
print("No value.")
}
}
OS: OS X Sierra,
Swift 3
You can present the alert a second time; if you need to customize the behavior beyond that, you'll need to eschew NSAlert and run an NSWindow or NSPanel of your own making.
I want to prevent taking screenshot of a page in app.
how to do it programmatically so that screenshots cannot be taken.
Found code to detect screenshot. Can it be deleted as soon as a screenshot is taken?
let mainQueue = NSOperationQueue.mainQueue()
NSNotificationCenter.defaultCenter().addObserverForName(UIApplicationUserDidTakeScreenshotNotification,
object: nil,
queue: mainQueue) { notification in
// executes after screenshot
}
There is no way to prevent ScreenShots but you can prevent Screen Recording
through this code.
func detectScreenRecording(action: #escaping () -> ()) {
let mainQueue = OperationQueue.main
NotificationCenter.default.addObserver(forName: UIScreen.capturedDidChangeNotification, object: nil, queue: mainQueue) { notification in
// executes after screenshot
action()
}
}
//Call in vewWillApper
detectScreenRecording {
print(UIScreen.main.isCaptured)
if UIScreen.main.isCaptured {
//your vier hide code
print("self.toHide()")
} else {
// self.sceneDeleg(ate?.window?.isHidden = false
//your view show code
print("self.toShow()")
}
}
There is absolutely no way to completely prevent user from taking screenshot during the app process, and that's because you do not have access to delete photos in the photo gallery of the user. It would totally be a security issue if you could access your user's photos.
However, there are ways to partially prevent screenshots, as described here: Prevent screen capture in an iOS app
Technically that is possible, via the Photos framework, the docs for which can be found here.
Example code can be found here.
However, this will ask the user's permission first, and then again to confirm deletion; so possibly not the ideal solution. Unfortunately this is as good as it gets as Apple has the Camera Roll fairly locked down.
You cannot prevent user from taking screenshot, however, you can hide the content while a screenshot is taken, Use this code to do so..
extension UIView {
func hideContentOnScreenCapture() {
DispatchQueue.main.async {
let field = UITextField()
field.isSecureTextEntry = true
self.addSubview(field)
field.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
field.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
self.layer.superlayer?.addSublayer(field.layer)
field.layer.sublayers?.first?.addSublayer(self.layer)
}
}
}
Usage:
yourView.hideContentOnScreenCapture()