1. 程式人生 > >IOS推送通知開發流程

IOS推送通知開發流程

最近開發IOS的推送通知,現把流程及遇到的問題整理一下:

一、證書的準備工作

1.在開發電腦MAC上申請證書

開啟鑰匙串訪問

選擇從證書頒發機構請求證書

這裡的郵箱賬號寫你自己的,常用名稱可以隨便寫

選擇儲存到磁碟

這裡最好新建一個資料夾 用來專門儲存這些檔案

2、在蘋果開發平臺生成開發證書或者生產證書

登入開發者賬號

https://idmsa.apple.com/IDMSWebAuth/login?appIdKey=891bd3417a7776362562d2197f89480a8547b108fd934911bcbea0110d07f757&path=%2Faccount%2F&rv=1

選擇Development 點選'+'按鈕新增,我這裡有證書在試用中

Development下面有兩個選項 第一個是不帶Push Notification,如果你選的是這個那你後期需要使用推送的時候,修改即可;第二種是帶有Push Notification,所以我們選擇第二個即可;頁面下方點選continue

這裡要注意,如果你在上一步選擇的是沒有Push Notification的,就不會出現下面這個頁面;這個頁面是要求你選擇APP ID;

這裡一定要看清楚,不要選錯了,否則到時候推送通知推送不了,就是證書不匹配的問題

continue;

continue;

這裡選擇我們第一步到處的證書申請檔案:CertificateSigningRequest.certSigningRequest

continue;

最後點選下載,下載完成以後雙擊安裝該證書到鑰匙串當中,一樣的這個檔案不能亂放等下會用到的,同csr檔案放在一個目錄中最好;這裡需要在xcode 更換一下開發證書

3、匯出開發證書格式為p12個人資訊交換

展開開發證書,右擊選單選擇匯出

證書名字這裡儲存為Push,儲存位置與上面一樣;檔案格式一定要p12

點選儲存

 

這裡需要輸入證書的驗證密碼 這裡就設定簡單點:123456

到這裡我們需要的檔案都已經齊了,因為這個證書是新的證書,還需要修改一下描述檔案

在開發平臺 選擇Provisioning Profiles,點選 Development,選擇Edit;這裡你選擇的欄目必須是你專案中的APP ID,不要弄錯了

在選擇Certificates選擇剛剛新建的開發證書 注意APP ID

點選Generate

將該描述檔案下載下來,這個你可以放在其他位置,不用存放在上面的目錄;

開啟xcode開啟專案替換一下描述檔案即可

4.處理證書

進入終端,我這裡是獲取了root許可權了

進入上面的目錄

生成一個PushChatCert.pem檔案

openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem

把私鑰Push.p12檔案轉化為.pem檔案:

openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12

對生成的這兩個pem檔案再生成一個p12檔案,來把證書和私鑰整合到一個檔案裡:

openssl pkcs12 -export -in PushChatCert.pem  -inkey PushChatKey.pem  -certfile CertificateSigningRequest.certSigningRequest -name "aps_developer_identity" -out aps_developer_identity.p12

注意在這裡有可能會報錯,我這裡是有錯誤:

命令列提示unable to load certificates

刪除 -certfile CertificateSigningRequest.certSigningRequest,再次執行命令,需要你輸入之前在鑰匙串匯出p12檔案設定的密碼

最後成功生成檔案aps_developer_identity.p12 

5.開啟xcode專案,新增Push Notification程式碼

在AppDelegate.m中新增一下程式碼:


- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

……

  	
	//訊息推送註冊
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
        //iOS 10 later
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        //必須寫代理,不然無法監聽通知的接收與點選事件
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (!error && granted) {
                //使用者點選允許
                NSLog(@"註冊成功");
            }else{
                //使用者點選不允許
                NSLog(@"註冊失敗");
            }
        }];
        
        // 可以通過 getNotificationSettingsWithCompletionHandler 獲取許可權設定
        //之前註冊推送服務,使用者點選了同意還是不同意,以及使用者之後又做了怎樣的更改我們都無從得知,現在 apple 開放了這個 API,我們可以直接獲取到使用者的設定資訊了。注意UNNotificationSettings是隻讀物件哦,不能直接修改!
        [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            NSLog(@"========%@",settings);
        }];
        
        [application registerForRemoteNotifications];
    }else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0){
        //iOS 8 - iOS 10系統
        //UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        //[application registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings
                                                                             settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge)
                                                                             categories:nil]];
        
        
        [application registerForRemoteNotifications];
    }else{
        //iOS 8.0系統以下
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
    }
    
    
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:@"" forKey:@"token"];

   return YES;

}

 

- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {

  	NSString *token = [NSString stringWithFormat:@"%@", deviceToken];
    //獲取終端裝置標識,這個標識需要通過介面傳送到伺服器端,伺服器端推送訊息到APNS時需要知道終端的標識,APNS通過註冊的終端標識找到終端裝置。
    NSLog(@"My token is:%@", token);
    
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:token forKey:@"token"];

}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{

    // 處理推送訊息

    NSLog(@"userinfo:%@",userInfo);

   

    NSLog(@"收到推送訊息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);

}

- (void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error {

   NSLog(@"Registfail%@",error); 

}

五、服務端新增javapns程式碼

將第3步生成的p12檔案傳送到服務端,我是在windows下測試的,

String certificatePath = "D:/aps_developer_identity.p12";
public class IOSBgNotice {

    private static final Logger log = LogManager.getLogger(IOSBgNotice.class);

    public static String certificatePath = "";

    public static void notice(String deviceToken, String alert, int badge) {

        /************************************************
         測試的伺服器地址:gateway.sandbox.push.apple.com /埠2195
         產品推送伺服器地址:gateway.push.apple.com / 2195
         ***************************************************/
        //為了相容開發測試 所以推送需要傳送兩次
        sendNotice(deviceToken, alert, badge, "gateway.sandbox.push.apple.com");//developer
        sendNotice(deviceToken, alert, badge, "gateway.push.apple.com");//distribution
    }

    private static void sendNotice(String deviceToken, String alert, int badge, String host) {
        try {
            deviceToken = deviceToken.replaceAll(" ", "");
            PushNotificationPayload payload = new PushNotificationPayload();
            payload.addAlert(alert);//push的內容
            payload.addBadge(badge);//圖示小紅圈的數值
            payload.addSound("default");//鈴音

            PushNotificationManager pushManager = new PushNotificationManager();
            pushManager.addDevice("iPhone", deviceToken);

            //Connect to APNs
            int port = 2195;
            String certificatePath = "D:/aps_developer_identity.p12";//匯出的證書
            String certificatePassword = "123456";//此處注意匯出的證書密碼不能為空因為空密碼會報錯
//            pushManager.initializeConnection(host,port, certificatePath,certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
            pushManager.initializeConnection(new AppleNotificationServerBasicImpl(
                    certificatePath, certificatePassword, "PKCS12", host, port));
            List<PushedNotification> notifications = new ArrayList<PushedNotification>();
            // 開始推送訊息
            // Send Push
            Device client = pushManager.getDevice("iPhone");

            log.debug("推送訊息: " + client.getToken() + "\n" + payload.toString() + " ");
            PushedNotification notification = pushManager.sendNotification(client, payload);
            notifications.add(notification);
            List<PushedNotification> failedNotification = PushedNotification
                    .findFailedNotifications(notifications);
            List<PushedNotification> successfulNotification = PushedNotification
                    .findSuccessfulNotifications(notifications);
            int failed = failedNotification.size();
            int successful = successfulNotification.size();
            log.debug("功數:" + successful);
            log.debug("失敗數:" + failed);
            pushManager.stopConnection();
            pushManager.removeDevice("iPhone");
            log.debug("訊息推送完畢");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

我這裡傳送兩次是因為程式碼打包以後,生成伺服器也會使用

6、測試

IOS需要在真機上測試,因為要獲取token

執行程式碼以後,手機上收到推送通知

最重要的就是p12檔案的製作,最開始在測試的時候一直報下面的異常:

javax.net.ssl.SSLException: Received fatal alert: internal_error
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1991)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1104)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:728)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at java.io.OutputStream.write(OutputStream.java:75)
at Push_1.main(Push_1.java:62)

出現這種情況,有兩種原因:

第一、你IOS打包時的環境和p12證書不匹配,有可能你匯出的時候不仔細,用的是生產的證書:

gateway.sandbox.push.apple.com

第二、Push Notification時,如果是開發環境就要使用開發蘋果的開發伺服器去推送;如果是生產環境就要使用生產伺服器去推送:

gateway.push.apple.com

一定要注意這兩點,必須要匹配才行

其他連結:

https://segmentfault.com/q/1010000000452323

https://blog.csdn.net/showhilllee/article/details/8631734​​​​​​​