VOIP notification is being missing or delay - xcode

How do I know that my device is blocked from receiving VoIP notifications?
The application stops receiving VoIP notifications after receiving for 3-4 times. I understand that from iOS 13 VoIP notifications should be reported to CallKit. Even after reporting to CallKit, I'm going through this issue of not receiving VoIP notifications.
We have set apns-expiration to 0 and the priority to immediately(10).
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: #escaping () -> Void) {
dictPayload = payload.dictionaryPayload[K.KEY.APS] as? [String : Any]
if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.VOIPCALL {
self.displayIncomingCall(uuid: appDelegate.uudiForCall, handle: (self.dictPayload!["handle"] as? String)!) { (error) in
}
CallProviderDelegate.sharedInstance.callDidReceiveIncomingCallfromKill(callInfo: self.dictPayload!)
} else if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.PUSHTOTALK {
isPTTON = true
pjsua_set_no_snd_dev()
CallHandler.sharedCallManager()?.muteCall(true)
CallHandler.sharedCallManager()?.setAudioSessionSpeaker()
CallProviderDelegate.sharedInstance.callDidReceivePTTFromKIll(callFromName: dictPayload!["title"] as? String, callfromExt: dictPayload![K.KEY.BODY] as? String)
} else if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.HANGUP {
isPTTON = false
CallProviderDelegate.sharedInstance.endCallFromPTT(endCallUDID: appDelegate.uudiForCall)
}
}
func displayIncomingCall(
uuid: UUID,
handle: String,
hasVideo: Bool = false,
completion: ((Error?) -> Void)?
) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value:(handle))
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in })
}
XCODE: 11.3.1,
SWIFT: 4.2 &
iOS: 13.0 +
I am trying to figure out this issue since the last 2 months but not able to resolve it. Please help me
Thanks In Advance.

Actually, it seems that you aren't reporting a new incoming call for every VoIP push notification. It's true that when there is an active CallKit call, you can receive VoIP pushes without reporting a new incoming call, but it's not as simple as it might seem. Since CallKit and PushKit are asynchronous, you are not guaranteed that when you receive a push of type K.KEY.PUSHTOTALK or K.KEY.HANGUP the call has already started. Moreover, if dictPayload is nil, you fail to report a new incoming call.
Anyway, I think that the biggest problem in your code is that you're not calling the completion handler of the pushRegistry(:didReceiveIncomingPushWith...) method. You should do the following:
self.displayIncomingCall(uuid: appDelegate.uudiForCall, handle: (self.dictPayload!["handle"] as? String)!) { (error) in
completion() // <---
}
and
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in
completion()
})
// or
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: completion)

Related

Is it possible to use async/await syntax for UIActivityViewController's completionWithItemsHandler property?

I have this function:
struct Downloader {
static func presentDownloader(
in viewController: UIViewController,
with urls: [URL],
_ completion: #escaping (Bool) -> Void
) {
DispatchQueue.main.async {
let activityViewController = UIActivityViewController(
activityItems: urls,
applicationActivities: nil
)
activityViewController.completionWithItemsHandler = { _, result, _, _ in
completion(result)
}
viewController.present(
activityViewController,
animated: true,
completion: nil
)
}
}
}
It simply creates a UIActivityViewController and passes the completionWithItemsHandler as a completion block into the static func.
I am now trying to get rid of all the #escaping/closures as much as I can in order to adopt the new async/await syntax, however I don't know if I can do something here with this.
I started adding an async to my function, and realized that Xcode shows completionWithItemsHandler with an async keyword, but I really have no idea if I can achieve what I want here.
Thank you for your help
Yes, you can do that but you need to write yourself little wrapper over it. So it will look something like that:
#MainActor
func askToShareFile(url: URL) async {
let avc = UIActivityViewController(activityItems: [url], applicationActivities: nil)
present(avc, animated: true)
return await withCheckedContinuation { continuation in
avc.completionWithItemsHandler = { activity, completed, returnedItems, activityError in
print("Activity completed: \(completed), selected action = \(activity), items: \(returnedItems) error: \(activityError)")
if completed {
continuation.resume()
} else {
if activity == nil {
// user cancelled share sheet by closing it
continuation.resume()
}
}
}
}
}
However, important note here that, from my experimentation as of today (iOS 15.5), I can see completion handler is NOT called properly when, on share sheet, user selects any app that handle our file by copying it (activityType = com.apple.UIKit.activity.RemoteOpenInApplication-ByCopy).
If you do some changes - be careful, as you might loose continuation here so please test it yourself too.

Square Connect SDK opens a blank page

I am attempting to implement Square Connect iOS SDK, and after implementing and clicking the pay button it opens up the Square Payment app and redirects to a blank page .. have you guys had the same issues ?
My App delegate has the proper section:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
guard let sourceApplication = options[.sourceApplication] as? String,
sourceApplication.hasPrefix("com.squareup.square") else {
return false
}
do {
let response = try SCCAPIResponse(responseURL: url)
if let error = response.error {
// Handle a failed request.
print(error.localizedDescription)
} else {
// Handle a successful request.
}
} catch let error as NSError {
// Handle unexpected errors.
print(error.localizedDescription)
}
return true
}
I have created a proper URL scheme inside the Square portal. Also my view controller has the correct code:
func charge()
{
// connect v1
if let callbackURL = URL(string: "myscheme://")
{
do
{
SCCAPIRequest.setClientID("xxxxxxxxxxx")
let amount = try SCCMoney(amountCents: 100, currencyCode: "USD")
let request = try SCCAPIRequest(
callbackURL: callbackURL,
amount: amount,
userInfoString: nil,
locationID: nil,
notes: "Purchase for cleaning",
customerID: nil, supportedTenderTypes: .all,
clearsDefaultFees: true,
returnAutomaticallyAfterPayment: true)
try SCCAPIConnection.perform(request)
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
https://snag.gy/R4A30L.jpg
Andrei
You need to make sure you delete all apps from the phone with having duplicate bundle ids. This way you will make sure you go back to the original app which triggered the payment.

Sinch PushKit isn't working

When I test my VoIP cert with a 3rd party client like Pusher, didReceiveIncomingPushWith works. But when I call using Sinch, it doesn’t.
I followed the docs to ensure that I have push set up properly, and have the corresponding SINManagedPushDelegate setup as well:
sinchWrapper.shared.push = Sinch.managedPush(with: SINAPSEnvironment.production)
sinchWrapper.shared.push.delegate = self
sinchWrapper.shared.push.setDesiredPushTypeAutomatically()
sinchWrapper.shared.push.registerUserNotificationSettings()
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, forType type: PKPushType) {
print("PUSH CREDENTIALS")
print(pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined())
print(pushCredentials.token)
sinchWrapper.shared.client.registerPushNotificationData(pushCredentials.token)
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: #escaping () -> Void) {
print("Getting push")
sinchWrapper.shared.client.relayRemotePushNotification(payload)
}
//Setup Sinch pushKit------------------------------------------
func managedPush(_ managedPush: SINManagedPush!, didReceiveIncomingPushWithPayload payload: [AnyHashable : Any]!, forType pushType: String!) {
print("Getting poush notif")
return
}
func client(_ client: SINCallClient!, localNotificationForIncomingCall call: SINCall!) -> SINLocalNotification! {
print("Getting local notif")
let notif = SINLocalNotification()
notif.alertAction = "Missed call"
notif.alertBody = "Incoming call"
return notif
}
I’m pretty sure I have Since set up properly because didReceiveIncomingCall is called when the app is open.
So my question is, when user A calls user B, do I have to call any other function to ensure that user B gets notified when the app is in terminated state? Simply calling callUser doesn’t seem to work..

Xcode Apple Watch project, local notification not being presented?

I am trying to present a local notification on an Apple Watch simulator with a button. This is the code:
#IBAction func buttonOne() {
print("button one pressed")
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "Notified!", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "This is a notification appearing!", arguments: nil)
// Deliver the notification in five seconds.
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5,
repeats: false)
// Schedule the notification.
let request = UNNotificationRequest(identifier: "Notify", content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
} else {
print("successful notification")
}
}
}
The console is successfully printing "successful notification," but the notification never appears on the watch simulator. I have no idea why this is
1) Before scheduling a notification, request permissions. Use requestAuthorization method, for example:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization
}
2) Notifications will not appear on watch face if the application is running in foreground. Considering this you may use cmd + H to hide the app.

How to indicate network activity in status bar

I use Alamofire for networking in my iOS application. I need to run this app in iOS 7+. I want to indicate network activity in status bar, so I created this struct:
struct ActivityManager {
static var activitiesCount = 0
static func addActivity() {
if activitiesCount == 0 {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}
activitiesCount++
}
static func removeActivity() {
if activitiesCount > 0 {
activitiesCount--
if activitiesCount == 0 {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
}
}
But I don't know, where to call in code addActivity() and removeActivity() methods. I don't want to write them with every request. I want to, that they will be called automatically with every request.
I tried also use pure NSURLSession and NSURLSessionTask and extend them:
extension NSURLSessionTask {
func resumeWithActivity() {
ActivityManager.addAction()
self.resume()
}
}
public extension NSURLSession {
func OwnDataTaskWithRequest(request: NSURLRequest!, ownCompletionHandler: ((NSData!, NSURLResponse!, NSError!) -> Void)?) -> NSURLSessionDataTask! {
return self.dataTaskWithRequest(request, completionHandler: { (data, response, error) in
ActivityManager.removeAction()
ownCompletionHandler!(data, response, error)
})
}
}
Then I used them like this:
var session: NSURLSession = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
session.OwnDataTaskWithRequest(request) { (data, response, error) -> Void in
// some logic here
}.resumeWithActivity()
But this approach doesn't work. In iOS 7 is NSURLSession extension not visible. I created a bug report for this (with sample project).
Can you please give me some advise, how to reach my goal? With or without Alamofire?
If you don't want to call your functions manually for every request and that you want to use Alamofire, I suggest you to improve it to add the network activity indicator feature.
Have a look at the source of Alamofire
You need to register 2 notification observers in your ActivityManager and then trigger the notifications at the relevant places either in Alamofire.Manager or in Alamofire.Request.
Also have a look at the source of AFNetworkActivityIndicatorManager which implement the feature you want in AFNetworking.

Resources