Layer synchronizeWithRemoteNotification not getting called in iOS - ios

I'm building an iOS app and making use of layer.
According to the documentation, when a push notification for a message comes in, you should not immediately switch to the conversation because the message might not have finished synching. So you call a synchronise method and pass it a completion function as follows:
self.layerClient!.synchronizeWithRemoteNotification(userInfo, completion: { (conversation, message, error) in
if (conversation != nil || message != nil) {
NSNotificationCenter.defaultCenter().postNotificationName(CXOConstants.Notifications.BadgeChatTabNotification.rawValue, object: nil, userInfo: userInfo)
let msgPart = message?.parts.first
if msgPart?.MIMEType == "text/plain"{
let msgText = String(data: msgPart!.data!,encoding: NSUTF8StringEncoding)
debugPrint("msgText:: \(msgText)")
} else {
debugPrint("The user sent an image")
}
completionHandler(.NewData)
} else {
completionHandler(.Failed)
}
})
Problem is, this method never gets called. I have tried implementing the same logic outside of the synchronizeWithRemoteNotification method, but when I switch to the conversation, it takes a couple seconds for the message to appear in the conversation.
Could use some help here figuring out why the method isn't getting called.
Thanks :)

Related

First time SignIn pop-up with Firebase SwiftUI

I'm trying to make a feature to show a pop-up when a user logs in for the first time with Firebase, except that when I print it doesn't work. When printing it returns false in all cases
Good to know, the accounts are created from the console!
AuthView.swift
func on_connect() {
if self.email != "" && self.pass != "" {
Auth.auth().signIn(withEmail: self.email, password: self.pass) { (res, err) in
if err != nil {
self.error = err!.localizedDescription
self.alert.toggle()
return
}
if res?.additionalUserInfo?.isNewUser == true{
print("IM NEW!")
UserDefaults.standard.set(true, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("status"), object: nil)
}
else{
UserDefaults.standard.set(true, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("status"), object: nil)
}
}
}
}
Thanks for your precious help!
Issue #1:
You have two delivViewModels:
#ObservedObject private var viewModel = delivViewModel()
#ObservedObject var first_log: delivViewModel
The first one is getting created inside LoggedView and the second looks like it's getting passed in via a parameter. It's hard to imagine a scenario where you'd need both, so get rid of one of them so that you don't end up calling functions on both, which happens later on:
self.viewModel.is_first_loggin() // called on viewModel
print("first sign in-> \($first_log.first_log)") // called on first_log
Issue #2:
Auth.auth().signIn, like nearly every network function, is asynchronous. This means that it doesn't return immediately (it'll return at an indeterminate point in the future), so code run directly after it will complete before signIn itself has completed. However, the code in the callback function/closure (what you see in the {} after signIn) will get called after its completion.
In terms of printing the value, I'd just move that code inside of the callback function. You'd have:
Auth.auth().signIn(with: credential) { (result, error) in
if error == nil {
if result?.additionalUserInfo!.isNewUser == true {
self.first_log = true
} else {
self.first_log = false
}
print("First log in? \(self.first_log)")
}
}
In terms of showing the popup that you mentioned, you can show that conditionally based on $viewModel.first_log (this is assuming that you've chosen viewModel to be the delivViewModel you want to keep.
Something like:
.sheet(isPresented: $viewModel.first_log) {
Text("Popup stuff")
}
If you did want a way to respond to first_log in your view once it is asynchronously set, you could also look into onReceive (How can I get data from ObservedObject with onReceive in SwiftUI?), however there may not be a use case for it here (unless you're going to drop back into UIKit to display the popup imperatively or something).

CallKit UI for reportNewIncomingCall is not showing when the user disconnect by clicking on "remind me" and a different call come

Sometimes the CallKit UI is not visible.
This happens all the time when the user clicks on the "Remind me" button on CallKit UI and cancel the call.
Now, when the user gets the call for the second time, there is only vibration but no UI for CallKit.
let callHandle = CXHandle(type: .generic, value: callerName ?? "Unknown".localized)
let callUpdate = getCallUpdate(callHandle: callHandle)
print("reportNewIncomingCall uuid = \(uuid)")
callKitProvider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in
if let error = error {
NSLog("Failed to report incoming call successfully: \(error.localizedDescription).")
} else {
NSLog("Incoming call successfully reported.")
}
completion?(error as NSError?)
}
I am also faced this issue and came to know that I have used same uuid for all calls, after changing it to below it worked for me .so make sure to generate new uuid for each call.
provider.reportNewIncomingCall(with: UUID(), update: update) { error in
if let error = error{
print("error while reporting incoming call \(error)")
}else{
print("incoming call successfully reported")
}
completion?(error)
}

CallKit issue with call holding (iOS 10)

I have an issue with CallKit API on iOS 10.3.3 and lower iOS versions.
My configuration supports call holding and grouping, here is the snippet.
let configuration = CXProviderConfiguration(localizedName: applicationName)
configuration.supportsVideo = supportsVideo
configuration.supportedHandleTypes = [.phoneNumber]
configuration.maximumCallGroups = 2
configuration.maximumCallsPerCallGroup = 3
On iOS 10, CallKit drops the call when app requests setHeld action for call.
Here is the snippet of setHeld call action request.
public func performSetCallOnHoldAction(_ call: Call, isOnHold: Bool) {
let setHeldAction = CXSetHeldCallAction(call: UUID(uuidString: call.callUUID)!, onHold: isOnHold)
let transaction = CXTransaction()
transaction.addAction(setHeldAction)
requestTransaction(transaction)
}
And finally, here is the CXProvider delegate method, which completes the hold/unhold action for call:
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
// Retrieve the Call instance corresponding to the action's call UUID
guard let call = CallList.sharedInstance().call(withUUID: action.callUUID.uuidString) else {
action.fail()
return
}
// Perform PJSUA set held action
if action.isOnHold {
Pjsua2Wrapper.sharedInstance()?.holdCall(withCallUUID: call.callUUID, completion: { (error) in
(error != nil) ? action.fail() : action.fulfill()
})
} else {
Pjsua2Wrapper.sharedInstance()?.unholdCall(withCallUUID: call.callUUID, completion: { (error) in
(error != nil) ? action.fail() : action.fulfill()
})
}
}
Note that I use Pjsip to perform a hold/unhold action and inside a completion block I call action.fulfill() or action.fail(), depending wether psjip returns the error.
In application GUI, there is a toggle swap button, which calls function to perform CXSetHeldCallAction on CXCallController.
On iOS 11.0 everything works perfectly, but on iOS 10, when you press that toggle button, the call which is supposed to be set on hold, gets ended by the CXProvider for some reason (CXProvider responds with CXEndCallAction).
I have looked in debugger for requestTransaction method wether it returns transaction error, but there is no error in requesting a transaction to call controller.
Does anyone have an idea what is wrong, or something that I can try out to fix this issue?

FaceID/TouchID success case keeps prompting for further authentication

I've implemented password/TouchID/FaceID on a view controller and when I hit the success case, I'd expect the prompt to stop firing but it just fires over and over again.
In my VC:
var context: LAContext!
func authenticateReturningUser() {
context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
let reason = "Verify that this is your device to continue."
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, error in
DispatchQueue.main.sync {
guard success else {
guard let error = error else {
// show error
return
}
switch error {
case LAError.userCancel:
// do stuff
return
default: return
}
}
print("success")
}
}
}
}
The prompt should fire once and not again if the user successfully authorizes
Edit:
authenticateReturningUser is called from the AppDelegate's applicationDidBecomeActive function:
self.coverVC?.completionHandler = { self.removeBackgroundVC() }
self.coverVC?.authenticateReturningUser()
As far as I remember, when showing the Touch ID prompt, your app becomes inactive. So when the prompt is dismissed, your app becomes active again, triggering the App Delegate's applicationDidBecomeActive again.
You might consider introducing a flag that stores whether the app became inactive because of Touch ID / Face ID etc. or because of another reason and use it in applicationDidBecomeActive to decide if authentication should be triggered or not.
Where are you calling authenticateReturningUser()? You may want to create a static boolean authenticated that if false, allows the call to authenticateReturningUser(), and if true, skips the call, and set authenticated = true after calling the function once.

Parse.com PFUser signUpInBackgroundWithBlock: block not being called on first tap

i am developing an iOS-App with Swift and the parse.com framework and have a big problem with registering new users.
The block of "signUpInBackgroundWithBlock" is not being called on the first tap, although the new user is getting registered. When i am tapping the button a second time, the block gets finally called and i get an error, that the username is already registered.
var newUser = PFUser()
newUser.username = registerView.nicknameTextField.text.trim()
newUser.email = registerView.emailTextField.text
newUser.password = registerView.passwordTextField.text
newUser.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError!) -> Void in
self.registerCompletionBlock(succeeded, error: error)
}
Is someone having the same problem and knows a solution for this strange behaviour?
Thanks!
Edit:
The completion block should call the "registerCompletionBlock()" function:
func registerCompletionBlock(succeeded: Bool, error: NSError!) {
if error == nil {
let subscriptionStoryboard = UIStoryboard(name: "Subscription", bundle: nil)
let viewcontroller: UIViewController = subscriptionStoryboard.instantiateInitialViewController() as UIViewController
self.presentViewController(viewcontroller, animated: true, completion: nil)
} else {
if let errorString = error.userInfo?["error"] as? NSString {
println(errorString)
if error.userInfo?["code"] as Float == 202{
let alert = UIAlertView(title: "vergeben", message: "name vergeben", delegate: nil, cancelButtonTitle: "abbrechen")
alert.show()
}
}
}
}
I tried the solution posted previously (eliminating PFUser.enableAutomaticUser()), and the issue persisted.
In case anyone else is still looking for a solution to this issue, try changing the if error == nil to if succeeded == true in the block of signUpInBackground. This worked for me and all is functional in backend.
Its calling at first time, but its taking a little time for calling this .. because its sending data on server in asynchronous. Asynchronous never block the main thread..
Because : -
Asynchronous never block the main thread waiting for a network response.
Asynchronous can be either synchronous on a separate thread, or scheduled in the run loop of any thread.
Asynchronous can be either synchronous on a separate thread, or scheduled in the run loop of any thread.
Synchronous blocks main thread until they complete request.
Because you call the method asynchronous, it takes some time to do it and your main thread doesn't wait for the method to finish. So you should, if you want to show a message or perform a segue, after the registration, put it inside the completion-block:
newUser.signUpInBackgroundWithBlock {
(succeeded: Bool!, error: NSError!) -> Void in
if error == nil {
// Perform a segue, show a message or whatever you want
} else {
let errorString = error.userInfo["error"] as NSString
// Show the errorString somewhere and let the user try again.
}
}
Also if you don't want to do it asynchronous, you can call the signUp() method(without the inBackgroundWithBlock. That way the application waits for the signup to finish until it continues.
i figured it out. Problem was, that i used PFUser.enableAutomaticUser() in the AppDelegate. I removed that line and the signup-block works flawlessly now!

Resources