Unsubscribe all subscriptions on logout #Quickblox APNS & APNS.VOIP - ios

I am trying to Unsubscribe subscriptions APNS & APNS.VOIP on logout in iOS swift Quickblox project. It unsubscribes only one of them can anyone please guide me.
Here's my code for logout.
#objc func didTapLogout(_ sender: UIBarButtonItem) {
if QBChat.instance.isConnected == false {
SVProgressHUD.showError(withStatus: "Error")
return
}
SVProgressHUD.show(withStatus: "SA_STR_LOGOUTING".localized)
SVProgressHUD.setDefaultMaskType(.clear)
guard let identifierForVendor = UIDevice.current.identifierForVendor else {
return
}
let uuidString = identifierForVendor.uuidString
#if targetEnvironment(simulator)
disconnectUser()
#else
QBRequest.subscriptions(successBlock: { (response, subscriptions) in
if let subscriptions = subscriptions {
for subscription in subscriptions {
if let subscriptionsUIUD = subscriptions.first?.deviceUDID,
subscriptionsUIUD == uuidString,
subscription.notificationChannel == .APNS {
self.unregisterSubscription(forUniqueDeviceIdentifier: uuidString)
return
}
}
}
self.disconnectUser()
}) { response in
if response.status.rawValue == 404 {
self.disconnectUser()
}
}
#endif
}
private func unregisterSubscription(forUniqueDeviceIdentifier uuidString: String) {
QBRequest.unregisterSubscription(forUniqueDeviceIdentifier: uuidString, successBlock: { response in
self.disconnectUser()
}, errorBlock: { error in
if let error = error.error {
SVProgressHUD.showError(withStatus: error.localizedDescription)
return
}
SVProgressHUD.dismiss()
})
}
Environment details
Info Value
iOS Version 13.0
Quickblox iOS SDK version 2.17.4
QuickbloxWebRTC SDK version 2.7.4
Xcode Version e.g. Xcode 12.0

Make sure you are connected to chat when removing subscriptions and logout only when all unsubscribe completions are called. You can also simply unsubscribe from remote notifications and PushKit in the app.

Related

Why is my Google AdMob GDPR consent form not presented in my iOS app

I am in the process of implementing UMP SDK into my iOS app. I have setup the GDPR and IDFA messages in the Google AdMob dashboard's Privacy and Messaging section. I am having trouble getting the GDPR message to show up. The IDFA and iOS' ATT messages work perfectly.
Below is the code that I am using. I have tested this on both simulator and physical device. Also, I am located in the EU.
static func trackingConsentFlow(completion: #escaping () -> Void) {
let umpParams = UMPRequestParameters()
let debugSettings = UMPDebugSettings()
debugSettings.geography = UMPDebugGeography.EEA
umpParams.debugSettings = debugSettings
umpParams.tagForUnderAgeOfConsent = false
UMPConsentInformation
.sharedInstance
.requestConsentInfoUpdate(with: umpParams,
completionHandler: { error in
if error != nil {
print("MYERROR #1 \(String(describing: error))")
completion()
} else {
let formStatus = UMPConsentInformation.sharedInstance.formStatus
print("FORM STATUS: \(formStatus)")
if formStatus == .available {
loadForm(completion)
} else {
completion()
}
}
})
}
private static func loadForm(_ completion: #escaping () -> Void) {
UMPConsentForm.load(completionHandler: { form, loadError in
if loadError != nil {
print("MYERROR #2 \(String(describing: loadError))")
completion()
} else {
print("CONSENT STATUS: \(UMPConsentInformation.sharedInstance.consentStatus)")
if UMPConsentInformation
.sharedInstance.consentStatus == .required {
guard let rootViewController = UIApplication.shared.currentUIWindow()?.rootViewController else {
return completion()
}
form?.present(from: rootViewController, completionHandler: { dismissError in
if UMPConsentInformation
.sharedInstance.consentStatus == .obtained {
completion()
}
})
}
}
})
}
Just to be clear:
With this code I am able to show the IDFA message, after which the AppTrackingTransparency alert is shown. But I am expecting to also see the GDPR consent form.
For anyone wondering the same thing. The GDPR message was not appearing because I had not finalised my Admob account setup. I had not added my payment method. After adding it (and sending the app for review in Admob) the GDPR message started to appear.

Realtime way to detect push notifcation is enable or not in swift (Combine publisher)

I have a function that checks whether the user has enabled their push notification/ notification alert in the iphone. If the user has turned on their notification, it will print true in the swift view, and if the user has turned off their notification, it will print false.
I could achieve this using the stated below function and gives relevant output. But, this is not real-time. I have to close and re-open the app to reflect current changes. Im looking way to give true/false real-time and async using publisher and subscriber which show status realtime in my app
My code :-
var isRegister : Bool = false
func isEnabled() -> Bool {
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized) {
isRegister = true
print("Push notification is enabled")
} else {
isRegister = false
print("Push notification is not enabled")
}
}
return isRegister
}
there are a delay in getting authorization status of notification
so you should have to use completion
func authorizeStatus(completion: #escaping (_ isAuthorized: Bool) -> Void) {
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized) {
completion(true)
print("Push notification is enabled")
} else {
completion(false)
print("Push notification is not enabled")
}
}
}
and how to check
override func viewDidLoad() {
super.viewDidLoad()
authorizeStatus { isAuthorized in
print(isAuthorized)
}
}
and if you want check status when click on Allow or Cancel of Notification Alert you can check it as follow
UNUserNotificationCenter.current().requestAuthorization(options: [ .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
else{
print(success) // check here
if success {
print("you enable it")
} else {
print("you cancel it")
}
}
}
how to check in swift ui
var body: some View {
VStack {
.onAppear { self. authorizeStatus { isAuthorized in
print(isAuthorized)
}
}
}
how to check in swift ui
var body: some View {
VStack {
.onAppear { self. authorizeStatus { isAuthorized in
print(isAuthorized)
}
}
}
Im trying to add text componenet to display text in my app. These solution does display in the log of xcode but no in the app. There is no way to use Text() as its bool value.
Any way to display text message on the screen directly and in the realtime

Show AdMob gdpr consent form in Xcode

I have developed my game in Godot game engine and I'm now trying to implement googles gdpr consent form into my Xcode project.
I am using Xcode 11.5
The code below is my current code which does not result in the consent form popping up.
It might be something with the class I made but I'm not sure how that works.
import UIKit
import PersonalizedAdConsent
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
PACConsentInformation.sharedInstance.requestConsentInfoUpdate(
forPublisherIdentifiers: ["I have the id just not posted here"])
{(_ error: Error?) -> Void in
if let error = error {
// Consent info update failed.
} else {
// Consent info update succeeded. The shared PACConsentInformation
// instance has been updated.
}
}
guard let privacyUrl = URL(string: "My_privacy_policy(not_actual)"),
let form = PACConsentForm(applicationPrivacyPolicyURL: privacyUrl) else {
print("incorrect privacy URL.")
return
}
form.shouldOfferPersonalizedAds = true
form.shouldOfferNonPersonalizedAds = true
form.shouldOfferAdFree = false
form.load {(_ error: Error?) -> Void in
print("Load complete.")
if let error = error {
// Handle error.
print("Error loading form: \(error.localizedDescription)")
} else {
// Load successful.
}
}
//Finally present the consent form
form.present(from: self) { (error, userPrefersAdFree) in
if let error = error {
// Handle error.
} else if userPrefersAdFree {
// User prefers to use a paid version of the app.
} else {
// Check the user's consent choice.
let status =
PACConsentInformation.sharedInstance.consentStatus
}
}
}
}
Any help is appreciated :)

Is this correct to check FaceID?

Sorry, unavailability of iPhone-X.
After the launch of iPhone-X, everyone wants their application should be compatible with iOS11 and with touchID but the problem is it's too expensive for a developer to test touch ID.
I don't have iPhone to check my code but can I check the same in iOS simulator?
let context = LAContext()
if ( context.biometryType == .typeFaceID ) {
// Face ID
}
if ( context.biometryType == .typeTouchID) {
// Touch ID
} else {
// Stone Age
}
You can test it without device also. Use simulator's Face ID to validate your code and it will behave similarly in iPhone-X also.
Simulator does not recognise a face but allows you to simulate a matching and non-matching faces, if you've enabled Enrolled option from Face ID.
Add following code to your view controller and try with Face-ID
import LocalAuthentication
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
localAuthentication()
}
func localAuthentication() -> Void {
let laContext = LAContext()
var error: NSError?
let biometricsPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
if (laContext.canEvaluatePolicy(biometricsPolicy, error: &error)) {
if let laError = error {
print("laError - \(laError)")
return
}
var localizedReason = "Unlock device"
if #available(iOS 11.0, *) {
if (laContext.biometryType == LABiometryType.faceID) {
localizedReason = "Unlock using Face ID"
print("FaceId support")
} else if (laContext.biometryType == LABiometryType.touchID) {
localizedReason = "Unlock using Touch ID"
print("TouchId support")
} else {
print("No Biometric support")
}
} else {
// Fallback on earlier versions
}
laContext.evaluatePolicy(biometricsPolicy, localizedReason: localizedReason, reply: { (isSuccess, error) in
DispatchQueue.main.async(execute: {
if let laError = error {
print("laError - \(laError)")
} else {
if isSuccess {
print("sucess")
} else {
print("failure")
}
}
})
})
}
}
}
FaceID authentication will prompt you for first time to allow FaceID detection for your app.
Now enable Face ID enrolment and run your app to test Face ID simulation Testing.
Here is simulation result for matching and non-matching faces.
Result for matching face:
Result for non-matching face:

Swift ios check if remote push notifications are enabled in ios9 and ios10

How can I check if the user has enabled remote notifications on ios 9 or ios 10?
If the user has not allowed or clicked No I want to toggle a message asking if they want to enable notifications.
Apple recommends to use UserNotifications framework instead of shared instances. So, do not forget to import UserNotifications framework. As this framework is new in iOS 10 it's really only safe to use this code in apps building for iOS10+
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .notDetermined {
// Notification permission has not been asked yet, go for it!
} else if settings.authorizationStatus == .denied {
// Notification permission was previously denied, go to settings & privacy to re-enable
} else if settings.authorizationStatus == .authorized {
// Notification permission was already granted
}
})
You may check official documentation for further information: https://developer.apple.com/documentation/usernotifications
Updated answer after iOS 10 is using UNUserNotificationCenter .
First you need to import UserNotifications then
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { permission in
switch permission.authorizationStatus {
case .authorized:
print("User granted permission for notification")
case .denied:
print("User denied notification permission")
case .notDetermined:
print("Notification permission haven't been asked yet")
case .provisional:
// #available(iOS 12.0, *)
print("The application is authorized to post non-interruptive user notifications.")
case .ephemeral:
// #available(iOS 14.0, *)
print("The application is temporarily authorized to post notifications. Only available to app clips.")
#unknown default:
print("Unknow Status")
}
})
this code will work till iOS 9, for iOS 10 use the above code snippet.
let isRegisteredForRemoteNotifications = UIApplication.shared.isRegisteredForRemoteNotifications
if isRegisteredForRemoteNotifications {
// User is registered for notification
} else {
// Show alert user is not registered for notification
}
I tried Rajat's solution, but it didn't work for me on iOS 10 (Swift 3). It always said that push notifications were enabled. Below is how I solved the problem. This says "not enabled" if the user has tapped "Don't Allow" or if you have not asked the user yet.
let notificationType = UIApplication.shared.currentUserNotificationSettings!.types
if notificationType == [] {
print("notifications are NOT enabled")
} else {
print("notifications are enabled")
}
PS: The method currentUserNotificationSettings was deprecated in iOS 10.0 but it's still working.
If your app supports iOS 10 and iOS 8, 9 use below code
// At the top, import UserNotifications
// to use UNUserNotificationCenter
import UserNotifications
Then,
if #available(iOS 10.0, *) {
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { settings in
switch settings.authorizationStatus {
case .notDetermined:
// Authorization request has not been made yet
case .denied:
// User has denied authorization.
// You could tell them to change this in Settings
case .authorized:
// User has given authorization.
}
})
} else {
// Fallback on earlier versions
if UIApplication.shared.isRegisteredForRemoteNotifications {
print("APNS-YES")
} else {
print("APNS-NO")
}
}
in iOS11, Swift 4...
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
if settings.authorizationStatus == .authorized {
// Already authorized
}
else {
// Either denied or notDetermined
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
// add your own
UNUserNotificationCenter.current().delegate = self
let alertController = UIAlertController(title: "Notification Alert", message: "please enable notifications", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
})
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(settingsAction)
DispatchQueue.main.async {
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)
}
}
}
}
#Rajat's answer is not enough.
isRegisteredForRemoteNotifications is that your app has connected to APNS and get device token, this can be for silent push notification
currentUserNotificationSettings is for user permissions, without this, there is no alert, banner or sound push notification delivered to the app
Here is the check
static var isPushNotificationEnabled: Bool {
guard let settings = UIApplication.shared.currentUserNotificationSettings
else {
return false
}
return UIApplication.shared.isRegisteredForRemoteNotifications
&& !settings.types.isEmpty
}
For iOS 10, instead of checking for currentUserNotificationSettings, you should use UserNotifications framework
center.getNotificationSettings(completionHandler: { settings in
switch settings.authorizationStatus {
case .authorized, .provisional:
print("authorized")
case .denied:
print("denied")
case .notDetermined:
print("not determined, ask user for permission now")
}
})
Push notification can be delivered to our apps in many ways, and we can ask for that
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge])
User can go to Settings app and turn off any of those at any time, so it's best to check for that in the settings object
open class UNNotificationSettings : NSObject, NSCopying, NSSecureCoding {
open var authorizationStatus: UNAuthorizationStatus { get }
open var soundSetting: UNNotificationSetting { get }
open var badgeSetting: UNNotificationSetting { get }
open var alertSetting: UNNotificationSetting { get }
open var notificationCenterSetting: UNNotificationSetting { get }
}
for iOS12 and Swift 4 also support iOS13 and Swift5
I also created a git for this you can check here
just add this singleton file in your XCode Project
import Foundation
import UserNotifications
import UIKit
class NotificaionStatusCheck {
var window: UIWindow?
private var currentViewController : UIViewController? = nil
static let shared = NotificaionStatusCheck()
public func currentViewController(_ vc: UIViewController?) {
self.currentViewController = vc
checkNotificationsAuthorizationStatus()
}
private func checkNotificationsAuthorizationStatus() {
let userNotificationCenter = UNUserNotificationCenter.current()
userNotificationCenter.getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .authorized:
print("The app is authorized to schedule or receive notifications.")
case .denied:
print("The app isn't authorized to schedule or receive notifications.")
self.NotificationPopup()
case .notDetermined:
print("The user hasn't yet made a choice about whether the app is allowed to schedule notifications.")
self.NotificationPopup()
case .provisional:
print("The application is provisionally authorized to post noninterruptive user notifications.")
self.NotificationPopup()
}
}
}
private func NotificationPopup(){
let alertController = UIAlertController(title: "Notification Alert", message: "Please Turn on the Notification to get update every time the Show Starts", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
})
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(settingsAction)
DispatchQueue.main.async {
self.currentViewController?.present(alertController, animated: true, completion: nil)
}
}
}
to access this code on ViewController user this on viewDidLoad
NotificaionStatusCheck.shared.currentViewController(self)
Here's a solution for getting a string describing the current permission that works with iOS 9 trough iOS 11, with Swift 4. This implementation uses When for promises.
import UserNotifications
private static func getNotificationPermissionString() -> Promise<String> {
let promise = Promise<String>()
if #available(iOS 10.0, *) {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.getNotificationSettings { (settings) in
switch settings.authorizationStatus {
case .notDetermined: promise.resolve("not_determined")
case .denied: promise.resolve("denied")
case .authorized: promise.resolve("authorized")
}
}
} else {
let status = UIApplication.shared.isRegisteredForRemoteNotifications ? "authorized" : "not_determined"
promise.resolve(status)
}
return promise
}
class func isRegisteredForRemoteNotifications() -> Bool {
if #available(iOS 10.0, *) {
var isRegistered = false
let semaphore = DispatchSemaphore(value: 0)
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { settings in
if settings.authorizationStatus != .authorized {
isRegistered = false
} else {
isRegistered = true
}
semaphore.signal()
})
_ = semaphore.wait(timeout: .now() + 5)
return isRegistered
} else {
return UIApplication.shared.isRegisteredForRemoteNotifications
}
}
Even though user doesn't allow the push notifications, the device token is available. So it would be also a good idea to check if it's allowed to receive the push notifications.
private func checkPushNotificationAllowed(completionHandler: #escaping (Bool) -> Void) {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
if settings.authorizationStatus == .notDetermined || settings.authorizationStatus == .denied {
completionHandler(false)
}
else {
completionHandler(true)
}
}
}
else {
if let settings = UIApplication.shared.currentUserNotificationSettings {
if settings.types.isEmpty {
completionHandler(false)
}
else {
completionHandler(true)
}
}
else {
completionHandler(false)
}
}
}
All answers above are almost correct BUT if you have push notifications enabled and all options disabled (alertSetting, lockScreenSetting etc.), authorizationStatus will be authorized and you won't receive any push notifications.
The most appropriate way to find out if you user can receive remote notifications is to check all these setting values. You can achieve it using extensions.
Note: This solution works for iOS 10+. If you support older versions, please read previous answers.
extension UNNotificationSettings {
func isAuthorized() -> Bool {
guard authorizationStatus == .authorized else {
return false
}
return alertSetting == .enabled ||
soundSetting == .enabled ||
badgeSetting == .enabled ||
notificationCenterSetting == .enabled ||
lockScreenSetting == .enabled
}
}
extension UNUserNotificationCenter {
func checkPushNotificationStatus(onAuthorized: #escaping () -> Void, onDenied: #escaping () -> Void) {
getNotificationSettings { settings in
DispatchQueue.main.async {
guard settings.isAuthorized() {
onDenied()
return
}
onAuthorized()
}
}
}
}
The new style with async await
static func getPermissionState() async throws {
let current = UNUserNotificationCenter.current()
let result = await current.notificationSettings()
switch result.authorizationStatus {
case .notDetermined:
//
case .denied:
//
case .authorized:
//
case .provisional:
//
case .ephemeral:
//
#unknown default:
//
}
}

Resources