簡體   English   中英

應用未運行/應用終止時如何獲取推送通知

[英]How to get push notification when app is not running/app is terminated

我曾嘗試過Google開發人員的“在iOS上設置GCM客戶端應用”。 我的應用程序具有android版本,並且服務器已將推送通知成功發送至Android。 在ios中,我可以將消息檢索到didRecieveRemoteNotification函數。打印后,如下圖所示,

aps: {
    alert =     {
        body = tyyy;
        title = "2 is going out at 03/24/2016 15:02:48";
    };
    badge = 2;
    sound = default;
}

當應用程序處於前台和后台時,它將收到此消息。 當應用程序為后台時,系統任務欄中沒有任何顯示。

當應用終止並且服務器正在發送推送通知時,我什么也沒有收到,也沒有活動顯示。

我的代碼如下。

AppDelegate.swift

import UIKit

 @UIApplicationMain



class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate,  GCMReceiverDelegate {

var window: UIWindow?

var connectedToGCM = false
var subscribedToTopic = false
var gcmSenderID: String?
var registrationToken = "AIzaSy-.....-11bSP6v72UvyKY"
var registrationOptions = [String: AnyObject]()

let registrationKey = "onRegistrationCompleted"
let messageKey = "onMessageReceived"
let subscriptionTopic = "/topics/global"


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "APP_RUNNING")


    // Override point for customization after application launch.

    // [START_EXCLUDE]
    // Configure the Google context: parses the GoogleService-Info.plist, and initializes
    // the services that have entries in the file
    var configureError:NSError?
    GGLContext.sharedInstance().configureWithError(&configureError)
    assert(configureError == nil, "Error configuring Google services: \(configureError)")
    gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
    // [END_EXCLUDE]
    // Register for remote notifications
    if #available(iOS 8.0, *) {
        let settings: UIUserNotificationSettings =
        UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
        application.registerUserNotificationSettings(settings)
        application.registerForRemoteNotifications()
    } else {
        // Fallback
        let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
        application.registerForRemoteNotificationTypes(types)
    }

    // [END register_for_remote_notifications]
    // [START start_gcm_service]
    let gcmConfig = GCMConfig.defaultConfig()
    gcmConfig.receiverDelegate = self
    GCMService.sharedInstance().startWithConfig(gcmConfig)
    // [END start_gcm_service]

    application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound],categories: nil))

    if let options = launchOptions {
        if let notification = options[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {
            if let userInfo = notification.userInfo {

                // do something neat here
            }
        }
    }

    return true
}

func subscribeToTopic() {
    // If the app has a registration token and is connected to GCM, proceed to subscribe to the
    // topic
    if(registrationToken != "" && connectedToGCM) {
        GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, topic: subscriptionTopic,
            options: nil, handler: {(error:NSError?) -> Void in
                if let error = error {
                    // Treat the "already subscribed" error more gently
                    if error.code == 3001 {
                        print("Already subscribed to \(self.subscriptionTopic)")
                    } else {
                        print("Subscription failed: \(error.localizedDescription)");
                    }
                } else {
                    self.subscribedToTopic = true;
                    NSLog("Subscribed to \(self.subscriptionTopic)");
                }
        })
    }
}

func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
    deviceToken: NSData ) {

        // [END receive_apns_token]
        // [START get_gcm_reg_token]
        // Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
        let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
        instanceIDConfig.delegate = self
        // Start the GGLInstanceID shared instance with that config and request a registration
        // token to enable reception of notifications
        GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
        registrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
            kGGLInstanceIDAPNSServerTypeSandboxOption:true]
        GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
            scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
        // [END get_gcm_reg_token]


}

// [START receive_apns_token_error]
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
    error: NSError ) {
        print("Registration for remote notification failed with error: \(error.localizedDescription)")
        // [END receive_apns_token_error]
        let userInfo = ["error": error.localizedDescription]
        NSNotificationCenter.defaultCenter().postNotificationName(
            registrationKey, object: nil, userInfo: userInfo)
}


// [START ack_message_reception]
func application( application: UIApplication,
    didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
        print("Notification received: \(userInfo)")
        // This works only if the app started the GCM service
        GCMService.sharedInstance().appDidReceiveMessage(userInfo);
        // Handle the received message
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName("reloadTableEvent", object: nil)
        NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
            userInfo: userInfo)
        // [END_EXCLUDE]
}

func application( application: UIApplication,
    didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
    fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
        print("Notification received: \(userInfo)")
        // This works only if the app started the GCM service
        GCMService.sharedInstance().appDidReceiveMessage(userInfo);
        // Handle the received message
        // Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,
            userInfo: userInfo)
        handler(UIBackgroundFetchResult.NoData);
        // [END_EXCLUDE]
}
// [END ack_message_reception]

func registrationHandler(registrationToken: String!, error: NSError!) {
    if (registrationToken != nil) {
        self.registrationToken = registrationToken
        print("Registration Token: \(registrationToken)")
        NSUserDefaults.standardUserDefaults().setValue(registrationToken, forKey: "registrationToken")
        self.subscribeToTopic()
        let userInfo = ["registrationToken": registrationToken]
        NSNotificationCenter.defaultCenter().postNotificationName(
            self.registrationKey, object: nil, userInfo: userInfo)
    } else {
        print("Registration to GCM failed with error: \(error.localizedDescription)")
        let userInfo = ["error": error.localizedDescription]
        NSNotificationCenter.defaultCenter().postNotificationName(
            self.registrationKey, object: nil, userInfo: userInfo)
    }
}

// [START on_token_refresh]
func onTokenRefresh() {
    // A rotation of the registration tokens is happening, so the app needs to request a new token.
    print("The GCM registration token needs to be changed.")
    GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
        scope: kGGLInstanceIDScopeGCM, options: registrationOptions, handler: registrationHandler)
}
// [END on_token_refresh]

// [START upstream_callbacks]
func willSendDataMessageWithID(messageID: String!, error: NSError!) {
    if (error != nil) {
        // Failed to send the message.
    } else {
        // Will send message, you can save the messageID to track the message
    }
}

func didSendDataMessageWithID(messageID: String!) {
    // Did successfully send message identified by messageID
}
// [END upstream_callbacks]

func didDeleteMessagesOnServer() {
    // Some messages sent to this device were deleted on the GCM server before reception, likely
    // because the TTL expired. The client should notify the app server of this, so that the app
    // server can resend those messages.
}

func applicationWillResignActive(application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

func applicationDidEnterBackground(application: UIApplication) {

    NSUserDefaults.standardUserDefaults().setBool(false, forKey: "APP_RUNNING")

    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    GCMService.sharedInstance().disconnect()
    // [START_EXCLUDE]
    self.connectedToGCM = false
    // [END_EXCLUDE]
}

func applicationWillEnterForeground(application: UIApplication) {

    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "APP_RUNNING")

    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(application: UIApplication) {

    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "APP_RUNNING")

    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

    // Connect to the GCM server to receive non-APNS notifications
    GCMService.sharedInstance().connectWithHandler({(error:NSError?) -> Void in
        if let error = error {
            print("Could not connect to GCM: \(error.localizedDescription)")
        } else {
            self.connectedToGCM = true
            print("Connected to GCM")
            // [START_EXCLUDE]
            self.subscribeToTopic()
            // [END_EXCLUDE]
        }
    })
}

func applicationWillTerminate(application: UIApplication) {

    NSUserDefaults.standardUserDefaults().setBool(false, forKey: "APP_RUNNING")

    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
    if let userInfo = notification.userInfo {
        NSNotificationCenter.defaultCenter().postNotificationName(
            "LoadEventViewController", object: nil, userInfo: userInfo)
    }
}




}

ViewController,彈出本地通知

func scheduleLocal(message: String) {
    let settings = UIApplication.sharedApplication().currentUserNotificationSettings()

    if settings!.types == .None {
        let ac = UIAlertController(title: "Can't schedule", message: "Either we don't have permission to schedule notifications, or we haven't asked yet.", preferredStyle: .Alert)
        ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
        presentViewController(ac, animated: true, completion: nil)
        return
    }

    // create a corresponding local notification
    let notification = UILocalNotification()
    notification.alertBody = message // text that will be displayed in the notification
    notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
    notification.fireDate = NSDate(timeIntervalSinceNow: 0) // todo item due date (when notification will be fired)
    notification.soundName = UILocalNotificationDefaultSoundName // play default sound
    notification.userInfo = ["UUID": 1, ] // assign a unique identifier to the notification so that we can retrieve it later
    notification.category = "TODO_CATEGORY"
    UIApplication.sharedApplication().scheduleLocalNotification(notification)
}

我有兩個問題

  1. 即使應用處於終止狀態,也可以接收和顯示推送通知嗎? 如果是這樣,怎么辦?
  2. 我在代碼中做錯了嗎?

這是您的推送通知JSON?

aps: { "content-available" = 1; }

如果是,則您正在發送靜默推送。 靜默推送意味着用戶不會收到任何視覺通知,只調用應用程序的應用程序委托回調。 刪除內容可用標簽,然后傳遞一條消息文本。

如果應用程序位於前台,則iOS不會顯示推送通知,而只會調用委托。 然后,您可以顯示警報視圖或您喜歡的其他內容。

或者您可以顯示以下內容: https : //github.com/avielg/AGPushNote

關於“被用戶終止”的狀態,此處為蘋果文檔(用於靜默推送):

蘋果文檔

使用此方法可以為您的應用處理傳入的遠程通知。 與application:didReceiveRemoteNotification:方法不同,該方法僅在您的應用程序在前台運行時才調用,而在您的應用程序在前台或后台運行時,系統會調用此方法。 此外,如果啟用了遠程通知后台模式,則系統將啟動您的應用程序(或將其從掛起狀態喚醒),並在遠程通知到達時將其置於后台狀態。 但是,如果用戶強制退出應用程序,系統不會自動啟動您的應用程序。 在這種情況下,用戶必須重新啟動您的應用程序或重新啟動設備,然后系統才會嘗試再次自動啟動您的應用程序。

如果您還沒有這樣做,請在Apple開發人員上注冊並配置您的應用程序以接收推送通知。 您必須為此付費(每年99美元)。

GCM在前台運行時將消息直接發送到您的應用程序,但在后台運行時,GCM依靠APN(Apple Push Notification服務)到達您的設備。

因此,必須精確格式化服務器發送到GCM的消息的格式, 這最終對我有用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM