본문 바로가기
Swift

GCM ios에 적용하기

by 루에 2015. 9. 8.
반응형

GCM이 IOS를 공식적으로 지원하기 시작하면서, 크로스 플랫폼 개발에 있어 푸시 서비스를 단일화 할 수 있게 되었다. 굳이 GCM을 사용할 필요가 있는가? 라고 하면, 가장 큰 장점은 3.0에 와서 푸시 서버를 따로 만들 필요가 없어진 점을 가장 큰 장점이라고 말 할 수 있다.


GCM을 적용하기 위한 사전 준비는, 기존의 APNS와 같다.


인증서를 만들고, 푸시를 사용할 앱을 애플 개발자 사이트에 등록하고 키체인을 만든다. 그 중 필요한 것은 p12파일이다.


해당 과정은 다른 곳에 많이 나와있으니 지금은 생략하고 나중에 시간이 날 때 천천히 정리할 예정이다.


우선 이 곳에서는 실제로 코드에 적용시키는 부분을 살펴보자.


GCM 사이트에서 iOS 등록을 진행하다보면 GoogleServices-Info.plist 파일을 받게 된다. 그 파일이 위치할 곳은 프로젝트의 루트이다.


그리고 cocoapods가 필요하다. 없는 경우 설치해주고

Set up your CocoaPods dependencies

Google Cloud Messaging uses CocoaPods to install and manage dependencies. Open a terminal window and navigate to the location of the Xcode project for your application. If you have not already created a Podfile for your application, create one now:

pod init

Open the Podfile created for your application and add the following:

pod 'Google/CloudMessaging'

Save the file and run:

pod install

This creates an .xcworkspace file for your application. Use this file for all future development on your application.

프로젝트의 루트 위치로 이동해서 위 과정처럼 init -> 'Google/CloudMessaging' -> install 해주자. 그러면 GCM관련 파일들이 설치된다.


그리고 아래 코드를 기술한다.


ViewController.swift


{

class ViewController: UIViewControllerUIWebViewDelegate {

    @IBOutlet weak var mainWebView: UIWebView!

    

    var appJavascriptDelegate : AppJavascriptDelegate?

    var webViewDelegate : WebViewDelegate?

    

    var request : NSURLRequest!

    

    required init(coder aDecoder: NSCoder) {

        super.init(coder: aDecoder)

    }

    

    override func viewDidAppear(animated: Bool) {

        //regist notification

        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateRegistrationStatus:",

            name: appDelegate.registrationKey, object: nil)

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "showReceivedMessage:",

            name: appDelegate.messageKey, object: nil)

        println("registed observer")

        

        if let url = NSBundle.mainBundle().URLForResource("index", withExtension: "html", subdirectory: "web"){

            

        }

    }

 func updateRegistrationStatus(notification: NSNotification) {

//        registrationProgressing.stopAnimating()

        if let info = notification.userInfo as? Dictionary<String,String> {

            if let error = info["error"] {

                NSLog("Error registering!", "error")

//                registeringLabel.text = "Error registering!"

                showAlert("Error registering with GCM", message: error)

            } else if let registrationToken = info["registrationToken"] {

                //                registeringLabel.text = "Registered!"

                NSLog("Registered!", "error")

                let message = "Check the xcode debug console for the registration token that you " +

                " can use with the demo server to send notifications to your device"

                showAlert("Registration Successful!", message: message)

            }

        } else {

            println("Software failure. Guru meditation.")

        }

    }

    

    

    func showReceivedMessage(notification: NSNotification) {

        println("showReceivedMessage \(notification.userInfo)")

        if let info = notification.userInfo as? Dictionary<String,AnyObject> {

            if let title = info["title"] as? String {

                if let body = info["body"] as? String {

                    showNotification(title, message: body)

                }

            }

            if let aps = info["aps"] as? Dictionary<String, String> {

//                showAlert("Message received", message:"showAlert message")

//                showNotification("message received", message: "message inside")

            }

        } else {

            println("Software failure. Guru meditation.")

        }

        if let info = notification.userInfo as? Dictionary<String, AnyObject>{

            println("run run")

//            var url = info["gcm.notification.url"] as! String

//

//            setUrl(url)

//            loadUrl(request)

//            var badge = UIApplication.sharedApplication().applicationIconBadgeNumber;

//            if badge > 0 {

//                badge--;

//            }

        }

//        showNotification("message received", message:"message outside")

    }


중요한 부분은 NSNotificationCenter에 옵저버를 등록하는 것이다. 이를 등록하면, 푸시 알람이 들어왔을 때 해당 옵저버 태그에 해당하는 이름으로 post하면 그 함수가 실행된다. 해당 함수는 ViewController.swift에 기술하면 된다.


 AppDelegate.swift

//  AppDelegate.swift

//  webviewtest

//

//  Created by Myungwoo Park on 2015. 8. 18..

//  Copyright (c) 2015 ygkwon. All rights reserved.

//


import UIKit


@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {


    var window: UIWindow?

    

    var connectedToGCM = false

    var subscribedToTopic = false

    var gcmSenderID: String?

    var registrationToken: String?

    var registrationOptions = [String: AnyObject]()

    

    let registrationKey = "onRegistrationCompleted"

    let messageKey = "onMessageReceived"

    let subscriptionTopic = "/topics/global"

    

    // [START register_for_remote_notifications]

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions:

        [NSObject: AnyObject]?) -> Bool {

            // [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

            NSLog("sender id : " + gcmSenderID!, "sender")

            // [END_EXCLUDE]

            // Register for remote notifications

            var types: UIUserNotificationType = UIUserNotificationType.Badge |

                UIUserNotificationType.Alert |

                UIUserNotificationType.Sound

            var settings: UIUserNotificationSettings =

            UIUserNotificationSettings( forTypes: types, categories: nil )

            application.registerUserNotificationSettings( settings )

            application.registerForRemoteNotifications()

            // [END register_for_remote_notifications]

            // [START start_gcm_service]

            var gcmConfig = GCMConfig.defaultConfig()

            gcmConfig.receiverDelegate = self

            GCMService.sharedInstance().startWithConfig(gcmConfig)

            // [END start_gcm_service]

            

            return true

    }

    

    func subscribeToTopic() {

        // If the app has a registration token and is connected to GCM, proceed to subscribe to the

        // topic

        if(registrationToken != nil && connectedToGCM) {

            GCMPubSub.sharedInstance().subscribeWithToken(self.registrationToken, topic: subscriptionTopic,

                options: nil, handler: {(NSError error) -> Void in

                    if (error != nil) {

                        // Treat the "already subscribed" error more gently

                        if error.code == 3001 {

                            println("Already subscribed to \(self.subscriptionTopic)")

                        } else {

                            println("Subscription failed: \(error.localizedDescription)");

                        }

                    } else {

                        self.subscribedToTopic = true;

                        NSLog("Subscribed to \(self.subscriptionTopic)");

                    }

            })

        }

    }

    

    // [START connect_gcm_service]

    func applicationDidBecomeActive( application: UIApplication) {

        // Connect to the GCM server to receive non-APNS notifications

        GCMService.sharedInstance().connectWithHandler({

            (NSError error) -> Void in

            if error != nil {

                println("Could not connect to GCM: \(error.localizedDescription)")

            } else {

                self.connectedToGCM = true

                println("Connected to GCM")

                // [START_EXCLUDE]

                self.subscribeToTopic()

                // [END_EXCLUDE]

            }

        })

        

        NSLog("foreground")

    }

    // [END connect_gcm_service]

    

    // [START disconnect_gcm_service]

    func applicationDidEnterBackground(application: UIApplication) {

        GCMService.sharedInstance().disconnect()

        // [START_EXCLUDE]

        self.connectedToGCM = false

        // [END_EXCLUDE]

    }

    // [END disconnect_gcm_service]

    

    // [START receive_apns_token]

    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.

            NSLog("START get_gcm_reg_token", "getToken")

            var 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 ) {

            println("(in error)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]) {

            println("Notification received1: \(userInfo)")

            // This works only if the app started the GCM service

            GCMService.sharedInstance().appDidReceiveMessage(userInfo);

            // Handle the received message

            // [START_EXCLUDE]

            NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,

                userInfo: userInfo)

            // [END_EXCLUDE]

    }

    

    func application( application: UIApplication,

        didReceiveRemoteNotification userInfo: [NSObject : AnyObject],

        fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {

            println("Notification received2: \(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]

    }

    

    func registrationHandler(registrationToken: String!, error: NSError!) {

        if (registrationToken != nil) {

            self.registrationToken = registrationToken

            println("Registration Token: \(registrationToken)")

            self.subscribeToTopic()

            let userInfo = ["registrationToken": registrationToken]

            NSNotificationCenter.defaultCenter().postNotificationName(

                self.registrationKey, object: nil, userInfo: userInfo)

        } else {

            println("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.

        println("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.

    }

}



중간에

NSNotificationCenter.defaultCenter().postNotificationName(messageKey, object: nil,

                userInfo: userInfo)

구문을 볼 수 있다. 이런 식으로 포스트 하는 것으로 함수를 연결시킨다. 연결된 함수에서 notification이나 alert 등을 수행하면 된다.

반응형

댓글