Can't register for Sendbird push notifications in Swift - ios

I have an iOS app in which I am using Sendbird successfully. Nevertheless, the functionality of receiving notifications when the app is running in background does not work. In fact, when I try to register the user for these notifications in the AppSelegate.swift file, I get the error 800101 ERR_CONNECTION_REQUIRED, what suggests I am not connecting correctly to the Sendbird server. However, I have checked that the connection is established without giving errors as soon as the app launches and before trying to register for those notifications.
This is the code for establishing the connection:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
SBDMain.initWithApplicationId(Constants.SENDBIRD_APP_ID, useCaching: false) {
} completionHandler: { error in
print(error)
}
...
}
This is my code for trying to register:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
SBDMain.registerDevicePushToken(deviceToken, unique: true, completionHandler: { (status, error) in
if error == nil {
if status == SBDPushTokenRegistrationStatus.pending {
return
}
else {
print("Successfully registered")
}
}
else {
print(error)
}
})
}
As I said, I have made sure the sendbird application is initialized before the registration, but for some reason, when trying to register for the push notifications I get the "connection required" error. The rest of the Sendbird functionalities work fine, so I guess the connection is well established. The notifications work fine on Android using the same data.

Disclaimer: I am a Sendbird employee.
Hi Pepito,
I'm unsure specifically what version you're on however it looks like you may not be calling the actual connect method prior to trying to register the token.
There is a two step process when creating a connection. The first is initializing the SDK with your Application ID. The second is actually calling the connect method with the userId and accessToken(If you're using them).
// Initialize a SBDMain instance to use APIs in the client app.
SBDMain.initWithApplicationId(APP_ID, useCaching: false) {
} completionHandler: { error in
}
// The USER_ID below should be unique to your Sendbird application.
SBDMain.connect(withUserId: USER_ID, completionHandler: { (user, error) in
guard error == nil else {
// Handle error.
}
// The user is connected to Sendbird server.
...
})
If you're still having trouble after this, I suggest you reach out on our community forums so we can acquire more information from you. https://community.sendbird.com

Related

Firebase dynamic link short url returns nil ios

I am facing an issue with Firebase dynamic link. The link is generated from the backend. and it's working perfectly in android. but in iOS when I shared the dynamic link on whatsapp or messages app on iPhone. and tap on the link app is opened. and our following function is called in Appdelegate. and after that firebase function is called with the received URL. and the firebase functions return nil. But when I open that link from the safari app is opened and that same firebase function returns the deeplink URL. I have searched alot but did not find the solution. I am using firebase 7.11 version pods.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let incomingUrl = userActivity.webpageURL{
print("Incoming URL is \(incomingUrl)")
let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingUrl) { (dynamicLink, error) in
// guard error == nil else{
// print("Found an error! \(error!.localizedDescription)")
// return
// }
print("error \(error)")
print("dynamicLink \(dynamicLink)") // It returns nil when app open from whatsapp or any 3rd party app.
}
if linkHandled{
return true
}else{
return false
}
}
return false
}
I have also received the following error in both cases.
Error Domain=com.firebase.dynamicLinks Code=403 "(null)" UserInfo={code=403, message=Requests to this API firebasedynamiclinks.googleapis.com method google.firebase.dynamiclinks.v1.DynamicLinksService.GetIosReopenAttribution are blocked., status=PERMISSION_DENIED, details=(
{
"#type" = "type.googleapis.com/google.rpc.ErrorInfo";
domain = "googleapis.com";
metadata = {
consumer = "projects/37866531840";
service = "firebasedynamiclinks.googleapis.com";
};
reason = "API_KEY_SERVICE_BLOCKED";
}
)}
Did you add your custom domains in your info.plist file with FirebaseDynamicLinksCustomDomains parameter like image below.
Have you set AppBundle id as deepLinkURLScheme as like below in AppDelegate class under function didFinishLaunchingWithOptions
let kAppBundleID = Bundle.main.bundleIdentifier
FirebaseOptions.defaultOptions()?.deepLinkURLScheme = kAppBundleID
Please try with this.
Reference:
https://firebase.google.com/docs/dynamic-links/ios/create
By default, Dynamic Links uses your app's bundle identifier as the URL scheme needed to open up your application. We recommend staying with this default value to keep your implementation simple.

Log OneSignal Push Notification with Firebase Analytics Event

So my goal is to log event any push notification that comes up on my app. I'm using Firebase Analytics to log any event and I already know how to use it using :
Analytics.logEvent(FirebaseEventName, parameters: [:])
But is it possible to log event a push notification? I'm using OneSignal as my Push Notification service.
I've found my answer. But my method required Backend to be involved. Which I don't have the answer because I don't handle the Backend part. The following answer is only just for iOS part only.
So, the method is using OneSignal method, and it's implemented in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
If you're already using OneSignal for iOS you should already write below code in didFinishLaunchingWithOptions
OneSignal.initWithLaunchOptions(launchOptions, appId: ONE_SIGNAL_APPID, handleNotificationReceived: { (notification) in
let additionalData = notification?.payload.additionalData // Get additional data such as custom flaging from backend
if additionalData != nil { // A condition to avoid crash if additionalData is empty
let customFlag:String = additionalData!["tipe"] as! String // Get value of the custom flag, in this case mine is "tipe", and store the value to customFlag
Analytics.logEvent(customFlag, parameters: [:]) // Send Log Event to Firebase
}
}, handleNotificationAction: { (result) in
}, settings: [kOSSettingsKeyInFocusDisplayOption: OSNotificationDisplayType.none.rawValue,kOSSettingsKeyAutoPrompt : true])
For example, if you print additionalData the value should be looking like
[AnyHashable("tipe"): inbox]
And this value is set/declared in Backend part.

Failing to implement Firebase Phone Auth on iOS

hey so I have a function Firebase/iOS app and am trying to implement phone auth.
pods are installed
APNs authentication key uploaded to Firebase
Push notifs enabled in Xcode
calling this method
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
if let error = error {
self.showMessagePrompt(error.localizedDescription)
return
}
// Sign in using the verificationID and the code sent to the user
// ...
}
in the view controller and passing a valid number.
I get this error ->
The UIApplicationDelegate must handle remote notification for phone number authentication to work.
Error Domain=FIRAuthErrorDomain Code=17054 "If app delegate swizzling is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to FIRAuth's canHandleNotificaton: method." UserInfo={NSLocalizedDescription=If app delegate swizzling is disabled, remote notifications received by UIApplicationDelegate need to be forwarded to FIRAuth's canHandleNotificaton: method., error_name=ERROR_NOTIFICATION_NOT_FORWARDED}
Swizzling is not disabled not that I know of. Delegate doesn't have much goin on but this walkthrough https://firebase.google.com/docs/auth/ios/phone-auth didn't mention it.
I'm not getting the silent notification I assume and def not receiving an SMS.
Thanks.
Please add following code in your AppDelegate:
func application(_ application: UIApplication,
didReceiveRemoteNotification notification: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if Auth.auth().canHandleNotification(notification) {
completionHandler(.noData)
return
}
// This notification is not auth related, developer should handle it.
handleNotification(notification)
}

Check if iOS push notifications status is not determined

I’m prompting my user to enable push notifications after the user logs in to my app. I know how to test if push notifications are enabled or disabled using:
isRegisteredForRemoteNotifications
and it works just fine. It returns YES for enabled and NO for not available but I want to be able to figure out how to check for Not Determined (the user wasn’t prompted to enable push notifications to begin with). Is there a way to test that?
Thanks in advance!
You create Not Determined state yourself.
func registerNotification() {
// 1.Call register API
// ...
// 2.Save a bool value to indicate you've called this method or not.
let appleSuggestedUserDefaultsKeyPrefix = "com.yourcompany.product-"
let key = appleSuggestedUserDefaultsKeyPrefix + "didCallRegisterNotificationAPI"
NSUserDefaults.standardUserDefaults().setBool(true, forKey: key)
}
And in didFinishLaunchingWithOptions method you need check if you have called registerNotification().
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let didCallRegisterNotificationAPI = NSUserDefaults.standardUserDefaults().boolForKey(...)
if didCallRegisterNotificationAPI {
// If registered or user denied, call this method will NOT show the alert.
// Just the same as you did before.
registerNotification()
} else {
print("registerNotification() has not been called")
}
}
And finally you can call registerNotification() directly anywhere anytime as you need and the alert is under your control now.
isRegisteredForRemoteNotifications is a Bool. There is no undetermined status. You can verify this is the reference.
When the user first installs your app they must either allow or disallow push notifications. There is no other possible option.
However, maybe you're asking because you can delete the app, reinstall, and it won't ask you for permission. That's because the permission is remembered.
Resetting the Push Notifications Permissions Alert on iOS
The first time a push-enabled app registers for push notifications, iOS asks the user if they wish to receive notifications for that app. Once the user has responded to this alert it is not presented again unless the device is restored or the app has been uninstalled for at least a day.
If you want to simulate a first-time run of your app, you can leave the app uninstalled for a day. You can achieve the latter without actually waiting a day by following these steps:
Delete your app from the device.
Turn the device off completely and turn it back on.
Go to Settings > General > Date & Time and set the date ahead a day or more.
Turn the device off completely again and turn it back on.
Reference
Associated Question: When I delete my iOS application push notification state remains
EDIT:
You can only use isRegisteredForRemoteNotifications to check that they are simply not registered, whether that's due to declining or due to you never trying to register.
However, as long as you try to register in a valid way (valid certs and profiles etc) and the user declines, your app will call did register, but with nil UIUserNotificationSettings:
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
if notificationSettings.types == nil {
println("You didn't allow notifcations")
}
}
You can make use of UNNotificationSettings's authorizationStatus property.
private func checkNotificationsAuthorizationStatus() {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.getNotificationSettings { notificationSettings in
switch notificationSettings.authorizationStatus {
case .authorized:
print("Authorized to schedule or receive notifications.")
case .denied:
print("Not authorized to schedule or receive notifications.")
case .notDetermined:
print("Not determined whether the app is allowed to schedule notifications.")
case .provisional: // Available from iOS 12.0
print("Provisionally authorized to post noninterruptive user notifications.")
#unknown default:
print("Error")
}
}
}
Use it in didFinishLaunchingWithOptions like:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.registerForRemoteNotifications()
self.checkNotificationsAuthorizationStatus()
return true
}

Cannot Log into Meteor on iOS with ObjectiveDDP

I am trying out the objectiveDDP library to connect my iOS app to my Meteor app. I am running my meteor app on localhost:3000 and I am getting this error when I try to login:
Error Domain=boundsj.objectiveddp.transport Code=0 "You are not connected" UserInfo=0x7fe33b440500 {NSLocalizedDescription=You are not connected}
*Note - I have not done anything to the server to support this, I assuming that it is supported out of the box.
I'm not sure if the url I put in is correct because I couldn't find the documentation for which url I should connect to when using ObjectiveDDP.
Here is my code:
var meteorClient: MeteorClient = MeteorClient(DDPVersion: "1")
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.meteorClient.addSubscription("someSubscription")
var ddp = ObjectiveDDP(URLString: "ws://localhost:3000/websocket", delegate: self.meteorClient)
self.meteorClient.ddp = ddp;
self.meteorClient.ddp.connectWebSocket()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reportConnection", name: MeteorClientDidConnectNotification, object: nil)
}
func reportConnection() {
println("================> connected to server!")
println(self.meteorClient.connected)
self.meteorClient.logonWithEmail("blob#schmoe.com", password: "password", responseCallback: {
(response, error) -> Void in
if (error != nil) {
println("*****Error******")
println(error);
return;
}
println(response);
})
}
*Update
So I try to check whether my meteorClient is connected to the server before I login. I added
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reportConnection", name: MeteorClientDidConnectNotification, object: nil)
To get notify when I am connected. However, when the DidConnectNotification is receive, I check self.meteorClient.connected and got false.
maintainer of said library, can you specify what versions of ObectiveDDP and meteor you are using? First try using ObectiveDDP from master not cocoapods. Your url is correct. First thing to check also, do the sample apps connect to your server?
Can you try your login by using a button instead, I think your hitting a race condition. This is something that could use a bit of tidy up.
Change your DDPVersion from 1 to pre2
var meteorClient: MeteorClient = MeteorClient(DDPVersion: "pre2")
I realize this is old, but thought I could help someone in the future. The issue seems to be that you used MeteorClientDidConnectNotification to decide when to start the login procedure. You should wait for the subsequent notification - MeteorClientConnectionReadyNotification. The button "fixed" it because you coincidentally waited after the MeteorClientDidConnectNotification for the client to become ready and for you to start the login procedure.

Resources