How to display a specific ViewController in OneSignal Swift - swift

I do app with OneSignal and Swift 3. I got push. How to display a specific ViewController with WebView in OneSignal when notification is clicked. In push in additional data with field "link" I got link, but can't display this link in my WebView.
I try use global variable tempURL to put url from additional data. But it not work.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
OneSignal.initWithLaunchOptions(launchOptions, appId: "MYID", handleNotificationAction: { (result) in
let payload = result?.notification.payload
print("This is Payload \(payload)")
var fullMessage = payload?.title
let messageTitle = "OneSignal Example"
if (result?.action.actionID) != nil {
let additionalData = payload?.additionalData
let url = additionalData?["link"] as! String?
tempURL = url!
fullMessage = fullMessage! + "\nPressed ButtonId:\(url)"
}
let alertController = UIAlertController(title: messageTitle, message: fullMessage, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default)
alertController.addAction(okAction)
alertController.show(alertController, sender: nil)
})
return true
}
Try to show:
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
let aViewController = ViewController()
aViewController.loadAddressURL(url: tempURL)
UIApplication.shared.keyWindow?.rootViewController?.present(aViewController, animated: true, completion:nil)
}
I have error:
fatal error: unexpectedly found nil while unwrapping an Optional value

first of all you can't pass data in your way. You should instantiate ViewController with StoryboardID. I explained how to use it with this link.
If you are pretty sure, your additionalData is not nil, you can pass your data with StoryboardID.

Related

AppCenterPush does not register device and does not receive notification - Swift 4

I'm following microssoft's step-by-step to use AppCenterPush, however when trying to insert "MSPushDelegate.setDelegate (self)" Xcode returns me the following error "Type 'MSPushDelegate' has no member 'setDelegate'".
I think I can not register the device or receive notification because I can not associate MSPushDelegate.
My current code:
import UIKit
import UserNotifications
import AppCenter
import AppCenterAnalytics
import AppCenterCrashes
import AppCenterPush
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MSPushDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Clean notifications
application.applicationIconBadgeNumber = 0
application.cancelAllLocalNotifications()
//enable notification (used for local notifications)
let notificationSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(notificationSettings)
UIApplication.shared.registerForRemoteNotifications()
// Notification by AppCenterPush
MSPush.setDelegate(self) // this line show the error: "Type 'MSPush' has no member 'setDelegate'"
MSAppCenter.setEnabled(true)
MSAppCenter.start("{MyAppSecret}", withServices: [
MSAnalytics.self,
MSCrashes.self,
MSPush.self
])
return true
}
My code to show the notification:
func push(_ push: MSPush!, didReceive pushNotification: MSPushNotification!) {
print("Working")
let title: String = pushNotification.title ?? ""
var message: String = pushNotification.message ?? ""
var customData: String = ""
for item in pushNotification.customData {
customData = ((customData.isEmpty) ? "" : "\(customData), ") + "\(item.key): \(item.value)"
}
if (UIApplication.shared.applicationState == .background) {
NSLog("Notification received in background, title: \"\(title)\", message: \"\(message)\", custom data: \"\(customData)\"");
} else {
message = message + ((customData.isEmpty) ? "" : "\n\(customData)")
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel))
// Show the alert controller.
self.window?.rootViewController?.present(alertController, animated: true)
}
}

Firebase - Swift 4: Message sent but not received

Ran pod update on the terminal to update my firebase. However i don't receive FCM's
This is my app delegate code:
import UIKit
import Firebase
import FirebaseFirestore
import StoreKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
override init() {
super.init()
FirebaseApp.configure()
// not really needed unless you really need it FIRDatabase.database().persistenceEnabled = true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Auth.auth().signInAnonymously() { (authResult, error) in
// ...
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
}
Messaging.messaging().delegate = self
UIApplication.shared.statusBarStyle = .default
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "gateway") as! gatewayViewController
window!.rootViewController = viewController
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
// if let messageID = userInfo[gcmMessageIDKey] {
// print("Message ID: \(messageID)")
// }
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
//if let messageID = userInfo[gcmMessageIDKey] {
// print("Message ID: \(messageID)")
//}//
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
But when trying to send a message on my console.firebase.com it gets labeled as "Completed" but my iPhone 6S don't shows the notification.
Notifications are also enabled in app capabilities
I need your help
I think you're not setting your APN token. Push your APNs token.
func application(_ application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { //data -> String in
return String(format: "%02.2hhx", $0)
}
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
UserDefaults.standard.synchronize()
}

Open a ViewController from remote notification

I try to open a particular ViewController when my app catch a remote notification.
Let me show my project's architecture.
Here my storyboard :
When I receive a notification I want open a "SimplePostViewController", so this is my appDelegate :
var window: UIWindow?
var navigationVC: UINavigationController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let pushNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.navigationVC = storyboard.instantiateViewControllerWithIdentifier("LastestPostsNavigationController") as? UINavigationController
application.registerUserNotificationSettings(pushNotificationSettings)
application.registerForRemoteNotifications()
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
if let postId = userInfo["postId"] as? String {
print(postId)
let api = EVWordPressAPI(wordpressOauth2Settings: Wordpress.wordpressOauth2Settings, site: Wordpress.siteName)
api.postById(postId) { post in
if (post != nil) {
self.navigationVC!.pushViewController(SimplePostViewController(), animated: true)
} else {
print("An error occurred")
}
}
}
}
I save my UINavigationViewController when the app is launch and simply try to push a new SimplePostViewController when I receive a notification. But nothing happen.
I placed breakpoints and seen that my pushViewController method was reached, but not the ViewWillAppear of my SimplePostViewController.
I also used the "whats new" view add perform my segue but nothing happen too.
Solution :
for child in (self.rootViewController?.childViewControllers)! {
if child.restorationIdentifier == "LastestPostsNavigationController" {
let lastestPostsTableViewController = (child.childViewControllers[0]) as! LastestPostsTableViewController
let simplePostVC = (self.storyboard?.instantiateViewControllerWithIdentifier("PostViewController"))! as! PostViewController
simplePostVC.post = post
lastestPostsTableViewController.navigationController?.pushViewController(simplePostVC, animated: true)
}
}
I use :
child.childViewControllers[0]
because I've only one child in my example.
I created a sample project with a local notification instead of a remote notification for ease of showing the functionality but it should be as simple as setting the root view controller of the window in the app delegate didreceiveremote notification.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Subscribe for notifications - assume the user chose yes for now
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil))
return true
}
func applicationDidEnterBackground(application: UIApplication) {
//Crete a local notification
let notification = UILocalNotification()
notification.alertBody = "This is a fake notification"
notification.fireDate = NSDate(timeIntervalSinceNow: 2)
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewControllerWithIdentifier("otherVC") as! OtherViewController
window?.rootViewController = otherVC;
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
//Your code here
}
`
You need to worry about managing your view hierarchy and sending anything to it that you need to send from the notification user data.
In my example, I create a local notification when you close the app that fires after a view seconds. If you then launch the app from the notification, it will open the "other view controller" which would be the "SimplePostViewController" in your case.
Also, be sure that you are registering for remote notifications in the didFinishLaunchWithOptions.
Github very simple sample : https://github.com/spt131/exampleNotificationResponse

reachability issue when open my app. Swift

My reachability function is executed if I open my app with internet. So, if I turn off the wifi, alert would be displayed. But, it doesn't work if I open my app with no internet. No alert is displayed. Any suggestions? Thanks.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var reachability: Reachability?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "checkForReachability:", name: kReachabilityChangedNotification, object: nil)
self.reachability = Reachability.reachabilityForInternetConnection()
self.reachability!.startNotifier()
}
func checkForReachability(notification: NSNotification) {
let remoteHostStatus = self.reachability!.currentReachabilityStatus()
if (remoteHostStatus.rawValue == NotReachable.rawValue) {
let myAlert = UIAlertController(title: "Alert", message: "Please check your internet connection.", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title:"Try again.", style:UIAlertActionStyle.Default) {
action in
self.checkForReachability(notification)
}
myAlert.addAction(okAction)
self.window?.rootViewController?.presentViewController(myAlert, animated:true, completion:nil)
}
}
}

Different APN Device Token ID for same application

I just followed the tutorial of http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1 for creating a sample push notification example....
But I dono where I went wrong I am receiving different token ID on different devices for the same application.
Here is my code for reference,
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var type = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound;
var setting = UIUserNotificationSettings(forTypes: type, categories: nil);
UIApplication.sharedApplication().registerUserNotificationSettings(setting);
UIApplication.sharedApplication().registerForRemoteNotifications();
return true
}
func application(application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
println("My token is \(deviceToken)") // am getting it different for different devices
}
//Called if unable to register for APNS.
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println(error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("Recived: \(userInfo)")
//Parsing userinfo:
var temp : NSDictionary = userInfo
if let info = userInfo["aps"] as? Dictionary<String, AnyObject>
{
var alertMsg = info["alert"] as! String
var alert: UIAlertView!
alert = UIAlertView(title: "", message: alertMsg, delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
One more problem is that I am receiving a sound and banner but not "badge"
Any help would be appreciated....
In your "didRegisterForRemoteNotificationsWithDeviceToken"
send your device Token to server like this
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let deviceTokenStr = HDDataLayer.convertDeviceTokenToStr(deviceToken)
HDDataLayer.postNotificationServiceResponseByUrlString("pushnotifications/notifications/register", andParams: tempDict, andDictCompletion: { (response: AnyObject!, error: NSError!) -> Void in
NSLog("Device Register successfully")
})
}
Please Note that HDDataLayer is my own class and you will use class you are using to interact with your server.