SwiftでPush通知

※iOS8でのやり方がわかったので一番下に追記しました

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/

元記事：http://sawapi.hatenablog.com/entry/2014/06/08/230719

## コードの解説
### Push通知を有効にする

```swift
func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary? ) -> Bool {
        
    application.registerForRemoteNotificationTypes(
        UIRemoteNotificationType.Badge |　
        UIRemoteNotificationType.Sound |
        UIRemoteNotificationType.Alert )
        
    return true
}
```

AppDelegate.swiftのapplication didFinishLaunchingWithOptionsにて
application.registerForRemoteNotificationTypesを呼び出し、有効にするものを指定します。

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

上記の処理が成功するとapplication didRegisterForRemoteNotificationsWithDeviceTokenが呼ばれるのでその中でデバイストークンを取得します。

### デバイストークンの取得

```swift
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
<?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 );
```

以下のように通知がきたら成功です。
![screenshot_push.png](https://qiita-image-store.s3.amazonaws.com/0/26955/fb6f5bf0-fba8-bfe2-f987-10bcb566d3b3.png)

## ソースコード
gistにあげました。
https://gist.github.com/sawapi/a7cee65e4ad95578044d

## (´・ω・｀)
ここまで書いて気づいたんですが、registerForRemoteNotificationTypesメソッドは
iOS8からDeprecatedになってるんですね。。。
試しに新しいやり方でやってみましたがうまくいかない、、というか
やり方がよくわかりませんでした。

```swift
var types: UIUserNotificationType = UIUserNotificationType.Badge |
                                   UIUserNotificationType.Alert |
                                   UIUserNotificationType.Sound


var settings: UIUserNotificationSettings = UIUserNotificationSettings.settingsForTypes( types, categories: nil )
application.registerUserNotificationSettings( settings )

application.registerForRemoteNotifications()
```

これでできると思ったんですが、こんなエラーがでます(´・ω・｀)

```
'settingsForTypes' is unavailable: use object construction 'UIUserNotificationSettings(forTypes:categories:)'
UIUserNotificationSettings.settingsForTypes
```

Objective-Cだとこんな感じでうまくいってるみたいなんですが。。
http://stackoverflow.com/questions/24049266/get-the-push-notification-list-on-ios8

やり方わかったら書き直します(´・ω・｀)

※6/13追記
やり方分かりました。
エラーログにちゃんと書いてあるのに気付かなかった。。。

```swift
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
}
```
これでできそうですー！