Cordova / Phonegap PushNotification tutorial ( iOS限定 )

前言
執行下列monkey step 前, 請先閱讀 Phonegap/Cordova 的 installation guide 建立一個 Project 出來
我用到的 Phonegap Plugin 是 PushNotification, 及加上  EasyAPNS

1. 先產生 CSR.
2. 在 iOS Provisioning Portal 中 new 一個 APP IDs, 然後 configure,  Enable for Development, Enable for Production
3. 下載 aps_development.cer, aps_production.cer, double click 這兩個file 匯進key acess
4. 建立一個 新的 Provisioning profile 選擇剛剛新建的  App IDs.
5. 下載此Provisioning profile.
6. 打開 Xcode, 選擇organizer 把 Provisioning profile 的檔案 拉進去
7. 選擇 Project, 將Build Settings 裡面的Code Signing identity 選擇成 你所建立的 App ID
8. 在Classes 按右鍵選 Add Files to “xxx”, 將這兩個檔案加上去 PushNotification.m, PushNotification.h 這兩個檔案 ( PushNotification 是 Phonegap 的Plugin )
9. 放 PushNotification.js, jquery 及 jquery mobile 的相關檔案 放到 www folder
10. 開啟 Cordova.plist

  • 在 ExternalHosts 加上 一筆 * 的 record , key 用default 的即可。
  • 在 Plugins 加上一筆 key -> PushNotification, value -> PushNotification

11. 打開 AppDelegate.h 加上

#import <AudioToolbox/AudioToolbox.h>
#import "PushNotification.h"

12. 打開 AppDelegate.m

  1. 在 didFinishLaunchingWithOptions 這個 method 裡上方加上
    // Add registration for remote notifications
    [[UIApplication sharedApplication]
    	registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
    
    // Clear application badge when app launches
    application.applicationIconBadgeNumber = 0;
  2. 在 didFinishLaunchingWithOptions 這個 method 裡頭的 [self.window makeKeyAndVisible]; 和 return YES; 中間插
    [self.window makeKeyAndVisible];
    
    /* START BLOCK */
    
    // PushNotification - Handle launch from a push notification
    NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if(userInfo) {
        PushNotification *pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
        NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];
        [mutableUserInfo setValue:@"1" forKey:@"applicationLaunchNotification"];
        [mutableUserInfo setValue:@"0" forKey:@"applicationStateActive"];
        [pushHandler.pendingNotifications addObject:mutableUserInfo];
    }
    
    /* STOP BLOCK */
    
    return YES;
  3. dealloc method and the implementation @end. 中間插入
    - (void) dealloc
    {
    	[super dealloc];
    }
    
    /* START BLOCK */
    
    /**
     * Fetch and Format Device Token and Register Important Information to Remote Server
     */
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    
    #if !TARGET_IPHONE_SIMULATOR
        /* EasyAPNS Start Block */
    
    	// Get Bundle Info for Remote Registration (handy if you have more than one app)
    	NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    	NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    
    	// Check what Notifications the user has turned on.  We registered for all three, but they may have manually disabled some or all of them.
    	NSUInteger rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
    
    	// Set the defaults to disabled unless we find otherwise...
    	NSString *pushBadge = @"disabled";
    	NSString *pushAlert = @"disabled";
    	NSString *pushSound = @"disabled";
    
    	// Check what Registered Types are turned on. This is a bit tricky since if two are enabled, and one is off, it will return a number 2... not telling you which
    	// one is actually disabled. So we are literally checking to see if rnTypes matches what is turned on, instead of by number. The "tricky" part is that the
    	// single notification types will only match if they are the ONLY one enabled.  Likewise, when we are checking for a pair of notifications, it will only be
    	// true if those two notifications are on.  This is why the code is written this way
    	if(rntypes == UIRemoteNotificationTypeBadge){
    		pushBadge = @"enabled";
    	}
    	else if(rntypes == UIRemoteNotificationTypeAlert){
    		pushAlert = @"enabled";
    	}
    	else if(rntypes == UIRemoteNotificationTypeSound){
    		pushSound = @"enabled";
    	}
    	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert)){
    		pushBadge = @"enabled";
    		pushAlert = @"enabled";
    	}
    	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)){
    		pushBadge = @"enabled";
    		pushSound = @"enabled";
    	}
    	else if(rntypes == ( UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)){
    		pushAlert = @"enabled";
    		pushSound = @"enabled";
    	}
    	else if(rntypes == ( UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)){
    		pushBadge = @"enabled";
    		pushAlert = @"enabled";
    		pushSound = @"enabled";
    	}
    
    	// Get the users Device Model, Display Name, Unique ID, Token & Version Number
    	UIDevice *dev = [UIDevice currentDevice];
    	NSString *deviceUuid = dev.uniqueIdentifier;
        NSString *deviceName = dev.name;
    	NSString *deviceModel = dev.model;
    	NSString *deviceSystemVersion = dev.systemVersion;
    
    	// Prepare the Device Token for Registration (remove spaces and < >)
    	NSString *deviceToken = [[[[devToken description]
                                   stringByReplacingOccurrencesOfString:@"<"withString:@""]
                                  stringByReplacingOccurrencesOfString:@">" withString:@""]
                                 stringByReplacingOccurrencesOfString: @" " withString: @""];
    
    	// Build URL String for Registration
    	// !!! CHANGE "www.mywebsite.com" TO YOUR WEBSITE. Leave out the http://
    	// !!! SAMPLE: "secure.awesomeapp.com"
    	NSString *host = @"www.example.com/apns";
    
    	// !!! CHANGE "/apns.php?" TO THE PATH TO WHERE apns.php IS INSTALLED
    	// !!! ( MUST START WITH / AND END WITH ? ).
    	// !!! SAMPLE: "/path/to/apns.php?"
    	NSString *urlString = [@"/apns.php?"stringByAppendingString:@"task=register"];
    
    	urlString = [urlString stringByAppendingString:@"&appname="];
    	urlString = [urlString stringByAppendingString:appName];
    	urlString = [urlString stringByAppendingString:@"&appversion="];
    	urlString = [urlString stringByAppendingString:appVersion];
    	urlString = [urlString stringByAppendingString:@"&deviceuid="];
    	urlString = [urlString stringByAppendingString:deviceUuid];
    	urlString = [urlString stringByAppendingString:@"&devicetoken="];
    	urlString = [urlString stringByAppendingString:deviceToken];
    	urlString = [urlString stringByAppendingString:@"&devicename="];
    	urlString = [urlString stringByAppendingString:deviceName];
    	urlString = [urlString stringByAppendingString:@"&devicemodel="];
    	urlString = [urlString stringByAppendingString:deviceModel];
    	urlString = [urlString stringByAppendingString:@"&deviceversion="];
    	urlString = [urlString stringByAppendingString:deviceSystemVersion];
    	urlString = [urlString stringByAppendingString:@"&pushbadge="];
    	urlString = [urlString stringByAppendingString:pushBadge];
    	urlString = [urlString stringByAppendingString:@"&pushalert="];
    	urlString = [urlString stringByAppendingString:pushAlert];
    	urlString = [urlString stringByAppendingString:@"&pushsound="];
    	urlString = [urlString stringByAppendingString:pushSound];
    
    	// Register the Device Data
    	// !!! CHANGE "http" TO "https" IF YOU ARE USING HTTPS PROTOCOL
    	NSURL *url = [[NSURL alloc] initWithScheme:@"http" host:host path:urlString];
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    	NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    	NSLog(@"Register URL: %@", url);
    	NSLog(@"Return Data: %@", returnData);
    
        /* EasyAPNS End Block */
    
        /* PushNotification Start Block */
        PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
        [pushHandler didRegisterForRemoteNotificationsWithDeviceToken:devToken];
        /* PushNotification End Block */
    
    #endif
    }
    
    - (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
    {
        PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
        [pushHandler didFailToRegisterForRemoteNotificationsWithError:error];
    }
    
    - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
    {
        PushNotification* pushHandler = [self.viewController getCommandInstance:@"PushNotification"];
        NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];
    
        // Get application state for iOS4.x+ devices, otherwise assume active
        UIApplicationState appState = UIApplicationStateActive;
        if ([application respondsToSelector:@selector(applicationState)]) {
            appState = application.applicationState;
        }
    
        [mutableUserInfo setValue:@"0" forKey:@"applicationLaunchNotification"];
        if (appState == UIApplicationStateActive) {
            [mutableUserInfo setValue:@"1" forKey:@"applicationStateActive"];
            [pushHandler didReceiveRemoteNotification:mutableUserInfo];
        } else {
            [mutableUserInfo setValue:@"0" forKey:@"applicationStateActive"];
            [mutableUserInfo setValue:[NSNumber numberWithDouble: [[NSDate date] timeIntervalSince1970]] forKey:@"timestamp"];
            [pushHandler.pendingNotifications addObject:mutableUserInfo];
        }
    }
    
    /* STOP BLOCK */
    
    @end

13. Build 在你的 device 上吧, 在emulator 沒辦法測 notification.

14. EasyAPNS Server Side 的部份, 我就沒寫了, 請參考下方 1j2 的連結即可

PS:
1.
這只是我個人的筆記, 寫的有點雜亂 XD
所以請搭配下列 ref 一併服用
未來還會再整理一遍, 目前只是先備忘
2.
產生 .pem
openssl pkcs12 -in Dev_Certificates.p12 -out apns-dev-cert.pem -nodes -clcerts

ref:
http://1j2.com/tutorial-implementing-push-notifications-with-easy-apns/
https://github.com/phonegap/phonegap-plugins/tree/master/iOS/PushNotification
http://www.easyapns.com/apple-delegate

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料