Im working with sinch and using firebase as my database and using its cloud functions to send notifications. Sending notifications are working fine but the shouldSendPushNotifications function but it never gets called so i can't add the sinch payload to the notification data and I couldn't find anything on the internet of a solid working example so I gave up on that and decided to send the SINcall object to the database and the callee will retrieve it and answer that.
But the problem is that firebase only stores strings so when I retrieve the SINCall I stored i get an error Could not cast value of type '__NSCFString' (0x102096998) to '__ObjC.SINCall' (0x10209ab08). So is there a way to convert this to a SINCall so I can answer, decline, etc with it?
EDIT:
this is where i have my code in AppDelegate.swift
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("USERINFO: \(userInfo["sin"]!)") <-- prints call: <SINCallImpl: 0x1c00f2600>
let incomingCall = userInfo["sin"]!
SINClientManager.shared.call = incomingCall as! SINCall <-- Error occurs
...
}
You need to send the data to the sinch client to set up the call, you cant convert a string to a call.
NSString* payload = [remotePush objectForKey:#"SIN"];
// Get previously initiated Sinch client
id<SINClient> client = [self sinchClient];
id<SINNotificationResult> result = [client relayRemotePushNotificationPayload:payload];
if (result.isCall && result.callResult.isTimedOut) {
// Present alert notifying about missed call
} else if (!result.isValid) {
// Handle error
}
Related
When I create a CKSubscription, didReceiveRemoteNotification gets called on iOS just fine but not on MacOS. I came across a 2015 SO thread talking about a bug and the suggested workaround was to set the notification info's soundName to an empty string - unfortunately that didn't resolve the issue for me.
Here is how I register my remote notifications:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let subscription = CKQuerySubscription(recordType: "Reminder", predicate: NSPredicate(format: "TRUEPREDICATE"), options: [.firesOnRecordCreation, .firesOnRecordUpdate])
// Here we customize the notification message
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
info.desiredKeys = ["identifier", "title", "date"]
info.soundName = ""
subscription.notificationInfo = info
// Save the subscription to Private Database in Cloudkit
CKContainer.default().privateCloudDatabase.save(subscription, completionHandler: { subscription, error in
if error == nil {
// Subscription saved successfully
} else {
// Error occurred
}
})
}
This has to do with the bundle identifier being different on Mac Catalyst. Thanks to the soon to be introduced universal app purchase, catalyst apps can now bear the same bundle identifier as their iOS counterpart, and that fixes the issue.
Note that I was also experiencing issues with cloudkit key values not syncing on Mac (NSUbiquitousKeyValueStore). Having a single bundle id for Mac and iOS fixed the problem too.
I am having an issue where, when sending a message through WCConnection, the session.sendMessage fails sometimes if called in the delegate method activationDidCompleteWith. The issue is not repeatable every time (in fact, it works most of the time).
But forcing a session.sendMessage by using a button in my UI (calling the identical loading code) has a successful session communication immediately, so I know the issue is not in the session itself or the master app.
Is it unsafe to assume the session is ready to accept communication in activationDidCompleteWith? Is there a better place to be calling my initial communication?
In my experience watch OS is pretty finicky, especially when using older model watches. That being said I think the answer to the question: "Is it unsafe to assume the session is ready to accept communication in activationDidCompleteWith?" is yes, it is unsafe to assume that.
In my own app I have a very similar case to yours and I solved it by sending a message until a response is received.
// false until a response is received from the phone
let receivedResponse: Bool = false
// function that sends the message
func requestResponse() {
guard WCSession.default.isReachable else {
print("Phone not reachable")
return
}
// callback that handles response
let responseHandler: ([String: Any]) -> () = { response in
receivedResponse = true
callback(response)
}
WCSession.default.sendMessage(["Request": "Response"],
replyHandler: responseHandler) { error in
print(error.localizedDescription)
}
}
// timer that calls the request function repeatedly
let retryTimer = Timer.scheduledTimer(withTimeInterval: 1,
repeats: true) { timer in
if receivedResponse {
// we know we got a response so clean up timer
timer.invalidate()
}
requestResponse()
}
I'm having a hard time trying to figure out how to determine the login type during a resume session using AWS Cognito. My code is based upon the MobileHub sample (below).
I've integrated a name/password mode for user pools (account creation and login) as well as as a Facebook login button which all works perfectly.
I have some logic in my application that needs to behave differently depending on the login type but I can't figure out how to do it.
Anyone done this?
func didFinishLaunching(_ application: UIApplication, withOptions launchOptions: [AnyHashable: Any]?) -> Bool {
print("didFinishLaunching:")
// Register the sign in provider instances with their unique identifier
AWSSignInManager.sharedInstance().register(signInProvider: AWSFacebookSignInProvider.sharedInstance())
AWSIdentityProfileManager.sharedInstance().register(FacebookIdentityProfile.sharedInstance(), forProviderKey: AWSFacebookSignInProvider.sharedInstance().identityProviderName)
AWSSignInManager.sharedInstance().register(signInProvider: AWSCognitoUserPoolsSignInProvider.sharedInstance())
AWSIdentityProfileManager.sharedInstance().register(UserPoolsIdentityProfile.sharedInstance(), forProviderKey: AWSCognitoUserPoolsSignInProvider.sharedInstance().identityProviderName)
setupAPIGateway()
setupS3()
let didFinishLaunching: Bool = AWSSignInManager.sharedInstance().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
if (!isInitialized) {
AWSSignInManager.sharedInstance().resumeSession(completionHandler: { (result: Any?, authState: AWSIdentityManagerAuthState, error: Error?) in
print("didFinishLaunching Result: \(String(describing: result)) AuthState: \(authState) \n Error:\(String(describing: error))")
if authState == .authenticated {
// Facebook or Cognito???
AWSCognitoUserAuthHelper.getCurrentUserAttribute(name: "sub", completionHandler: { (userid) in
// we need to fetch the user
ObjectManager.instance.getUser(userid: userid, completionHandler: { (user) in
ObjectManager.instance.setCurrentUser(user: user)
})
})
}
}) // If you get an EXC_BAD_ACCESS here in iOS Simulator, then do Simulator -> "Reset Content and Settings..."
// This will clear bad auth tokens stored by other apps with the same bundle ID.
isInitialized = true
}
return didFinishLaunching
}
One solution I found was to cast to the different identity profile types such as the following:
let identityManager = AWSIdentityManager.default()
if let fbIdentityProfile = identityManager.identityProfile as? FacebookIdentityProfile {
print("didFinishLaunching - Facebook login")
} else if let upIdentityProfile = identityManager.identityProfile as? UserPoolsIdentityProfile {
print("didFinishLaunching - User Pools login")
}
I can model logic in my application around this. Not sure if there is a cleaner approach using the MobileHub helper classes or AWS APIs but this works.
I am attempting to call a SQLite insert method from the AppDelegate.swft method didReceiveRemoteNotiication. I have the following code :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
let db = try! Connection()
//try db.run(users.insert(email <- "xxx#gmail.com", name <- userInfo))
print(userInfo)
}
I want to insert the string "userInfo" when the remote notification is received, however when I attempt to run the commented code I get "Command failed due to signal: Abort trap: 6" error.
I was able to achieve this with my android version of the app, my question is how can I make this work for Swift 3.0?
First of all, i have no problem for FCM, firebase token is never null every time tokenRefreshNotification is called. But after, i add Google analytics, i got weird problem for Firebase token. Every time i turn off and turn on notification in my app settings used
UIApplication.shared.registerForRemoteNotifications()
my tokenRefreshNotification is called continously and it doesn't stop looping until i force close my apps. At first, my app crash, and when i try to trace it with NsLog, i found that Firebase token is null. The problem occurs only when i`m using my apps installed from TestFlight / production. When i try it from my Xcode builder, firebase token is null only once, but the second call, firebase token is exist and it stop working.
For google Analytics, it works fine and in my GoogleService-info.plist,
i have set IS_ANALYTICS_ENABLED to YES and IS_GCM_ENABLED to YES also. For the other, IS_ADS_ENABLED = YES, IS_APPINVITE_ENABLED = NO, and IS_SIGNIN_ENABLED = YES
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
NotificationCenter.default.addObserver(self, selector: #selector(self.registerNotification), name: NSNotification.Name(rawValue: "registerNotification"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification(_:)), name: .firInstanceIDTokenRefresh, object: nil)
setupGoogleAnalytics()
return true
}
//when firebase token is null, this function is working continously until my firebase token is exist
func tokenRefreshNotification(_ notification: Notification) {
print("token Refresh")
if FIRInstanceID.instanceID().token() == nil{
NSLog("firebase token is null")
}
if (UserDefaults.standard.object(forKey: "id") != nil) && FIRInstanceID.instanceID().token() != nil{
FIRInstanceID.instanceID().getWithHandler({ (instanceID, error) in
NSLog("instanceID: \(instanceID!)")
//save firebase token to my database, sorry i can`t show it
})
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
Note: At the first launch, i called my RegisterForRemoteNotifications, at TestFlight version, when tokenRefreshNotification is called, the firebase token is null, but the second call, firebase token is exist, so it could stop. But, when i run my app from Xcode, the first call is success because firebase token is not null.
i have figured it out! just change ANPS Type token from Sandbox to Unknown!
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// With swizzling disabled you must set the APNs token here.
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.unknown)
}