I want to test faceId/touchId mechanism in my app.
I have following:
func auth(){
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
var reason: String = Strings.Common.unknownBiometryTip.value
if BiometricService.biometricType() == .touchID {
reason = Strings.Common.touchIDEnterTip.value
}
if BiometricService.biometricType() == .faceID {
reason = Strings.Common.faceIDEnterTip.value
}
context.evaluatePolicy(LAPolicy.deviceOwnerAuthentication, localizedReason: reason) { [weak self] (success, error) in
print("error \(error)")
if let error = error as? LAError, error.errorCode == Int(kLAErrorUserCancel) {
self?.cancelTapped?()
return
}
if success {
self?.authSucceed?()
}
else {
self?.authFailure?()
}
}
}
else {
print("Touch ID neither Face ID not available")
}
}
I actually can't test authFailure block, because when i hit "not-matching face" button in XCode, it shows up pin entry view, and look like anything i type in handled as "correct".
I actually want callback anytime user have "wrong" face/touchId/pin entry attempt, but i can't figure out how to get it.
Related
I have created a zone for privateCloudDatabase.
static var privateCloudDatabase: CKDatabase {
let container = CKContainer(identifier: "iCloud.<bundle>")
return container.privateCloudDatabase
}
static func createZone() {
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = {
(recordZones: [CKRecordZone.ID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
return
}
for recordID in recordZones.keys {
if recordID.zoneName == zoneName {
print("Zone Already Created: \(recordID)")
} else if recordID.zoneName == "_defaultZone" {
print("Deafult Zone")
} else {
let customZone = CKRecordZone(zoneName: zoneName)
privateCloudDatabase.save(customZone) { zone, error in
if let error = error{
print("Zone creation error: \(String(describing: error))")
} else {
print("Zone created: \(String(describing: zone?.zoneID.zoneName))")
}
}
}
}
}
fetchZonesOperation.qualityOfService = .utility
privateCloudDatabase.add(fetchZonesOperation)
}
It works successfully and I got a success message but created Zone doesn't display in CloudKit Dashboard. It only shows the _default zone as of now.
The other issue is related to delete all data from Zone. For that, I used below code
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = {
(recordZones: [CKRecordZone.ID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
return
}
guard let recordZones = recordZones else { return }
let deletionOperation = CKModifyRecordZonesOperation(recordZonesToSave: nil, recordZoneIDsToDelete: recordZones.keys.map { $0 })
deletionOperation.modifyRecordZonesCompletionBlock = { _, deletedZones, error in
guard error == nil else {
let error = error!
print("Error deleting records.", error)
return
}
print("Records successfully deleted in this zone.")
}
}
fetchZonesOperation.qualityOfService = .userInitiated
privateCloudDatabase.add(fetchZonesOperation)
Here I neither get any success message not get any error message. The other method I tried to delete all data from the zone is
let customZone = CKRecordZone(zoneName: zoneName)
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: recordType, predicate: predicate)
privateCloudDatabase.perform(query, inZoneWith: customZone.zoneID) { (records, error) in
if error == nil {
for record in records! {
removeRecord(record.recordID.recordName) { record, error in
}
}
}
}
Here, I get the success message but when I am trying to fetch data from the zone, I get all entries and that suggests data aren't deleted using any of the above methods. Any suggestions for these queries?
Whenever I have run into inexplicable errors and the absence of data updates in CloudKit, it was usually because of something silly like:
A typo in the container identifier so it was interacting with the wrong database on CloudKit.
The account on my Apple device that I was using was different than the account I was signing into in the CloudKit Dashboard.
Have you checked the CloudKit logs to confirm that these actions are hitting your database?
I'm trying to write a function that I can call on my iOS app to return me the current (or approximate) firebase server time.
I couldn't get any success with the following attempts. am I doing something wrong?
Obs.: The second one return an object of type FIRHTTPSCallableResult and I couldn't find a way to parse it, neither see the content into it to be sure if it worked.
exports.currentTime = functions.https.onRequest((req, res) => {
res.send({"timestamp":new Date().getTime()})
});
exports.currentTimeTwo = functions.https.onCall((data, context) => {
return {"timestamp":new Date().getTime()};
});
exports.currentTimeThree = functions.https.onRequest((req, res) => {
const data = {"timestamp":new Date().getTime()}
res.send(data)
});
iOS Code:
static func getServerTime(){
Functions.functions().httpsCallable("currentTimeTwo").call { (result, error) in
if let error = error as NSError? {
print("error \(error)")
if error.domain == FunctionsErrorDomain {
print("error domain: \(error.domain)")
let code = FunctionsErrorCode(rawValue: error.code)
print("error code: \(code)")
let message = error.localizedDescription
print("error message: \(message)")
let details = error.userInfo[FunctionsErrorDetailsKey]
print("details: \(details)")
}
}
print(result)
}
}
exports.currentTimeTwo = functions.https.onCall((data, context) => {
return {"timestamp":new Date().getTime()};
});
The function above is right. As Frank informed in the comments of my question, I was missing to access the property data from swift code result.
New Swift Code:
static func getServerTime(){
Functions.functions().httpsCallable("currentTimeTwo").call { (result, error) in
if let error = error as NSError? {
print("error \(error)")
if error.domain == FunctionsErrorDomain {
print("error domain: \(error.domain)")
let code = FunctionsErrorCode(rawValue: error.code)
print("error code: \(code)")
let message = error.localizedDescription
print("error message: \(message)")
let details = error.userInfo[FunctionsErrorDetailsKey]
print("details: \(details)")
}
}
let resultFireBase = result as! HTTPSCallableResult
print(result?.data)
}
}
}
Only the functions.https.onCall in your Cloud Functions code matches with the Functions.functions().httpsCallable in your Swift code, so the other ones are meaningless here.
When you call the httpsCallable, you get a FIRHTTPSCallableResult whose data property contains whatever your Cloud Function returns, as long as it's a valid JSON type, which your new Date().getTime() seems to be
I don't understand why the Google-rendered consent form is not showing up. It says that it loads successfully, but then it doesn't show up. (I am in Europe, so my location is not a problem). I have tried both on simulators and real devices, I have manually selected only 12 ad providers.
Here is the code in question:
PACConsentInformation.sharedInstance.debugIdentifiers = ["4FDF7D7F-8F56-4E65-8570-103100943386"]
PACConsentInformation.sharedInstance.debugGeography = PACDebugGeography.EEA
PACConsentInformation.sharedInstance.requestConsentInfoUpdate(forPublisherIdentifiers: ["pub-5765803665103285"]){
(_ error: Error?) -> Void in
if let error = error {
// Consent info update failed.
print(error)
} else {
// Consent info update succeeded. The shared PACConsentInformation
// instance has been updated.
if PACConsentInformation.sharedInstance.consentStatus == PACConsentStatus.unknown {
guard let privacyUrl = URL(string: "http://www.gdgapps.altervista.org/index.html/gdg-privacy.html"),
let form = PACConsentForm(applicationPrivacyPolicyURL: privacyUrl) else {
print("incorrect privacy URL.")
return
}
form.shouldOfferPersonalizedAds = true
form.shouldOfferNonPersonalizedAds = true
form.shouldOfferAdFree = true
form.load {(_ error: Error?) -> Void in
print("Load complete.")
if let error = error {
// Handle error.
print("Error loading form: \(error.localizedDescription)")
} else {
print("Load successful.")
}
}
form.present(from: self) { (error, userPrefersAdFree) in
if error != nil {
// Handle error.
} else if userPrefersAdFree {
// User prefers to use a paid version of the app.
//TODO: buy pro version
} else {
// Check the user's consent choice.
let status = PACConsentInformation.sharedInstance.consentStatus
// TODO: show ads
}
}
} else if PACConsentInformation.sharedInstance.consentStatus == PACConsentStatus.nonPersonalized || PACConsentInformation.sharedInstance.consentStatus == PACConsentStatus.personalized{
print("ads")
self.bannerView.isHidden = false
self.tableBasso.constant = 50
self.bannerView.adUnitID = "ca-app-pub-5765803665103285/9440944250"
self.bannerView.rootViewController = self
let request = GADRequest()
if PACConsentInformation.sharedInstance.consentStatus == PACConsentStatus.nonPersonalized {
let extras = GADExtras()
extras.additionalParameters = ["npa": "1"]
request.register(extras)
}
self.bannerView.load(request)
}
}
}
}
You should present the form after it's loaded. Put form.present inside the completion block of form.load.
form.load { [weak self] error in
print("Load complete.")
if let error = error {
print("Error loading form: \(error.localizedDescription)")
} else {
guard let strongSelf = self else { return }
form.present(from: strongSelf) { error, userPrefersAdFree in
[...]
}
}
}
I'm writing a Swift extension on FIRStorageReference to detect if a file exists or not. I am calling metadataWithCompletion(). If the completion block's optional NSError is not set, I think it's safe to assume that the file exists.
If the NSError is set, either something went wrong or the file doesn't exist. The storage documentation on handling errors in iOS states that FIRStorageErrorCodeObjectNotFound is the type of error that I should be checking, but is doesn't resolve (possibly Swiftified into a shorter .Name-style constant?) and I'm not sure what I should be checking it against.
I'd like to be calling completion(nil, false) if FIRStorageErrorCodeObjectNotFound is set somewhere.
Here's my code so far.
extension FIRStorageReference {
func exists(completion: (NSError?, Bool?) -> ()) {
metadataWithCompletion() { metadata, error in
if let error = error {
print("Error: \(error.localizedDescription)")
print("Error.code: \(error.code)")
// This is where I'd expect to be checking something.
completion(error, nil)
return
} else {
completion(nil, true)
}
}
}
}
Many thanks in advance.
You can check the error code like so:
// Check error code after completion
storageRef.metadataWithCompletion() { metadata, error in
guard let storageError = error else { return }
guard let errorCode = FIRStorageErrorCode(rawValue: storageError.code) else { return }
switch errorCode {
case .ObjectNotFound:
// File doesn't exist
case .Unauthorized:
// User doesn't have permission to access file
case .Cancelled:
// User canceled the upload
...
case .Unknown:
// Unknown error occurred, inspect the server response
}
}
Thats a simple code that I use to check if user has already got a user photo by hasChild("") method ,and the reference is here:
https://firebase.google.com/docs/reference/ios/firebasedatabase/interface_f_i_r_data_snapshot.html
hope this can help
let userID = FIRAuth.auth()?.currentUser?.uid
self.databaseRef.child("users").child(userID!).observeEventType(.Value, withBlock: { (snapshot) in
// Get user value
dispatch_async(dispatch_get_main_queue()){
let username = snapshot.value!["username"] as! String
self.userNameLabel.text = username
// check if user has photo
if snapshot.hasChild("userPhoto"){
// set image locatin
let filePath = "\(userID!)/\("userPhoto")"
// Assuming a < 10MB file, though you can change that
self.storageRef.child(filePath).dataWithMaxSize(10*1024*1024, completion: { (data, error) in
let userPhoto = UIImage(data: data!)
self.userPhoto.image = userPhoto
})
}
Swift 5
let storageRef = Storage.storage().reference().child("yourPath").child("\(someFile)") // eg. someVideoFile.mp4
print(storageRef.fullPath) // use this to print out the exact path that your checking to make sure there aren't any errors
storageRef.getMetadata() { (metadata: StorageMetadata?, error) in
if let error = error {
guard let errorCode = (error as NSError?)?.code else {
print("problem with error")
return
}
guard let err = StorageErrorCode(rawValue: errorCode) else {
print("problem with error code")
return
}
switch err {
case .objectNotFound:
print("File doesn't exist")
case .unauthorized:
print("User doesn't have permission to access file")
case .cancelled:
print("User cancelled the download")
case .unknown:
print("Unknown error occurred, inspect the server response")
default:
print("Another error occurred. This is a good place to retry the download")
}
return
}
// Metadata contains file metadata such as size, content-type.
guard let metadata = metadata else {
// an error occured while trying to retrieve metadata
print("metadata error")
return
}
if metadata.isFile {
print("file must exist becaus metaData is a file")
} else {
print("file for metadata doesn't exist")
}
let size = metadata.size
if size != 0 {
print("file must exist because this data has a size of: ", size)
} else {
print("if file size is equal to zero there must be a problem"
}
}
A shorter version without the detailed error check:
let storageRef = Storage.storage().reference().child("yourPath").child("\(someFile)")
storageRef.getMetadata() { (metadata: StorageMetadata?, error) in
if let error = error { return }
guard let metadata = metadata else { return }
if metadata.isFile {
print("file must exist because metaData is a file")
} else {
print("file for metadata doesn't exist")
}
let size = metadata.size
if size != 0 {
print("file must exist because this data has a size of: ", size)
} else {
print("if file size is equal to zero there must be a problem"
}
}
I am working on one application in which using google plus login
It works fine but I want to integrate with parse also
I have refer for example
func finishedWithAuth(auth: GTMOAuth2Authentication!, error: NSError!) {
let token = auth.accessToken
PFUser.becomeInBackground(token, block: { (user : PFUser?, error : NSError?) -> Void in
if error != nil {
print("Error in become user : \(error)")
} else {
print("user : \(user)")
}
})
}
but it give me error like
Error in become user : Optional(Error Domain=Parse Code=209 "invalid session token" UserInfo={code=209, temporary=0, error=invalid session token, NSLocalizedDescription=invalid session token})
I have try also this example Login with google plus in ios on parse.com
but it is in objective c ,try to convert to swift2 but it also give error
Please give me correct solution
Finally solved issues
convert answer into swift code and its work fine
func finishedWithAuth(auth: GTMOAuth2Authentication!, error: NSError!) {
if error == nil && auth.expirationDate.compare(NSDate(timeIntervalSinceNow: 0)) == NSComparisonResult.OrderedDescending {
let user = GPPSignIn.sharedInstance().googlePlusUser
let userName = user.name.JSONValueForKey("givenName") as! String
let userEmail = GPPSignIn.sharedInstance().userEmail
let pfUser = PFUser()
pfUser.username = userName
pfUser.email = userEmail
let userPassword = "\(userName)#123"
pfUser.password = userPassword
pfUser.signUpInBackgroundWithBlock({ (success, error : NSError?) -> Void in
if error == nil {
let plusService = GTLServicePlus()
plusService.retryEnabled = true
plusService.authorizer = GPPSignIn.sharedInstance().authentication
let query : GTLQueryPlus! = GTLQueryPlus.queryForPeopleGetWithUserId("me") as! GTLQueryPlus
plusService.executeQuery(query, completionHandler: { (ticket, person, error) -> Void in
if error != nil {
print("Error in execute query : \(error!)")
} else {
let aPerson : GTLPlusPerson! = person as! GTLPlusPerson
let imgUrl = aPerson.image.url
if let imgData = NSData(contentsOfURL: NSURL(string: imgUrl)!) {
self.userProfilePic.image = UIImage(data: imgData)
}
let currentUser = PFUser.currentUser()
currentUser?.username = aPerson.displayName
currentUser?.saveInBackground()
}
})
} else {
print("Error in signup : \(error!.localizedDescription)")
PFUser.logInWithUsernameInBackground(self.userName, password: userPassword, block: { (user : PFUser?, error : NSError?) -> Void in
if error == nil {
print("Login Sccessfully")
} else {
print("Error in login : \(error!.localizedDescription)")
}
})
}
})
} else {
print("Error in authentication : \(error.localizedDescription)")
}
}
Hope Help to someone!!!
I don't think it's a matter of incorrect translation to Swift (as the error is generated by Parse itself during the runtime, not the Swift compiler or the Swift runtime). Try using "PFUser.enableRevocableSessionInBackground()". For more details please visit https://parse.com/tutorials/session-migration-tutorial. Hope it'll help you. Cheers.