SwiftでPush通知

SwiftでPush通知を実装してみました。
証明書の取得等はこちらを参考にしています。

iOSでプッシュ通知を実装する方法の超詳細まとめ(前編)】
http://www.lancork.net/2013/08/how-to-ios-push-first/

iOSでプッシュ通知を実装する方法の超詳細まとめ(後編)】
http://www.lancork.net/2013/08/how-to-ios-push-second/

コードの解説

Push通知を有効にする

iOS SDK8.0ではregisterForRemoteNotificationTypesメソッドがDeprecatedになっているため
registerForRemoteNotificationsメソッドを使います。

func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary? ) -> Bool {
        
    var types: UIUserNotificationType = UIUserNotificationType.Badge |
        UIUserNotificationType.Alert |
        UIUserNotificationType.Sound
    
    var settings: UIUserNotificationSettings = UIUserNotificationSettings( forTypes: types, categories: nil )
    
    application.registerUserNotificationSettings( settings )
    application.registerForRemoteNotifications()
        
    return true
}

iOS7以下では、Push通知を有効にするタイミングで有効にするオプションを
設定していましたがiOS8以上では別で設定します。

  • UIUserNotificationType.Badge・・・アイコンバッジ
  • UIUserNotificationType.Sound・・・Push通知時になる音
  • UIUserNotificationType.Alert・・・Push通知時に表示される文字列

UIUserNotificationSettingsのcategoriesはドキュメントが見当たらなかったのでよくわかっていません。。
上記の処理が成功するとapplication didRegisterForRemoteNotificationsWithDeviceTokenが呼ばれるのでその中でデバイストークンを取得します。

ちなみにiOS7以下では以下のように記述します。

func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary? ) -> Bool {
        
    application.registerForRemoteNotificationTypes(
        UIRemoteNotificationType.Badge | 
        UIRemoteNotificationType.Sound |
        UIRemoteNotificationType.Alert )
        
    return true
}
デバイストークンの取得
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData ) {
    
    // <>と" "(空白)を取る
    var characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
    
    var deviceTokenString: String = ( deviceToken.description as NSString )
                                        .stringByTrimmingCharactersInSet( characterSet )
                                        .stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
    
    println( deviceTokenString )
    
}

devideToken.descriptionには、

<00000000 11111111 22222222 33333333 aaaaaaaa bbbbbbbb cccccccc dddddddd>

というような文字列で入っているため、"<"と">"と" (スペース)"を取る必要があります。
Swiftの文字の整形の仕方が分からず、、一旦NSStringに変換し、余分な文字を取り除きました。
( いい方法がありましたら教えて下さい。。。)

上記までを実行するとデバイストークンを取得できるのでメモしておきます。

Push通知が届くかテスト

Push通知がちゃんと届くかテストするために以下のスクリプトでテストしてみました。

<?php
$deviceToken = '************';
 
// 送信する文字列
$alert = 'Push test.';
 
// バッジ
$badge = 1;
 
$body = array();
$body['aps'] = array( 'alert' => $alert );
$body['aps']['badge'] = $badge;
 
// SSL証明書
$cert = '********.pem';
 
$url = 'ssl://gateway.sandbox.push.apple.com:2195'; // 開発用
//$url = 'ssl://gateway.push.apple.com:2195'; // 本番用
 
$context = stream_context_create();
stream_context_set_option( $context, 'ssl', 'local_cert', $cert );
$fp = stream_socket_client( $url, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $context );
 
if( !$fp ) {
 
    echo 'Failed to connect.' . PHP_EOL;
    exit( 1 );
 
}
 
$payload = json_encode( $body );
$message = chr( 0 ) . pack( 'n', 32 ) . pack( 'H*', $deviceToken ) . pack( 'n', strlen($payload ) ) . $payload;
 
print 'send message:' . $payload . PHP_EOL;
 
fwrite( $fp, $message );
fclose( $fp );

以下のように通知がきたら成功です。
https://gist.githubusercontent.com/sawapi/a7cee65e4ad95578044d/raw/c456ba27a7926244375e8b496c9c3c6787e911ce/screenshot_push.png