やりたいこと
- iosアプリの通知の処理をAWSにやってもらう。
- iosアプリで通知が来た時、通知内容に基づいて処理を行う。
以前は、通知を自分で構築していたが、届かない端末の処理とかもAmazon先生がかってにやってくれたり、いろいろ良いらしいし、アンドロイド対応した時にもつかえそうだったので。
前提
- iosアプリ開発環境持ってる
- AWSアカウント持ってる
AmazonSNSを使う
参考URL http://tech4403.hatenablog.com/entry/2013/10/15/193214
ありがとうございました。感謝感謝。
iosアプリで通知用トークン作成
iOS8からちょっと変わったので注意。
下記を参考にしました。
http://d.hatena.ne.jp/peccu/20140921/ios8_notification
RemoteNotificationの権限のあるプロビジョニング・プロファイリングをセットしておかないと機能しないのでチェックして下さいね。
AppDelegete.m
// 初回起動時に呼ばれるやつ
// iOS8からちょっと変わったので注意。
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Your Code
// プッシュ通知の要求
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes: (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
// use registerForRemoteNotifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
#else
// use registerForRemoteNotifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
#endif
// END プッシュ通知の要求
// Your Code
}
// 通知用のトークンを発行。
// http://mihyaeru21.hatenablog.com/entry/2013/05/17/174910
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
const char *data = [deviceToken bytes];
NSMutableString *token = [NSMutableString string];
for (int i = 0; i < [deviceToken length]; i++) {
[token appendFormat:@"%02.2hhX", data[i]];
}
NSLog(@"device token: %@", token);
// サーバへの送信が失敗することも想定して保存しておいた方がよいかも。
NSUserDefaults *udefaults = [NSUserDefaults standardUserDefaults];
[udefaults setObject:token forKey:@"deviceToken"];
// トークンをサーバにあげる。
your_upload_method(token); // 適当に書き換えてね。
}
サーバ側の処理
railsを想定。
AWS SDKを用いたら似たようなコードでいけるのかな?
http://www.absolute-keitarou.net/blog/?p=1206 を参考にしました。
push_sample.rb
# -*- coding: utf-8 -*-
require 'aws-sdk'
require 'json'
AWS.config({
access_key_id: 'YOUR_ACCESS_KEY_ID',
secret_access_key: 'YOUR_SECRET_ACCESS_KEY',
region: 'YOUR_REGION' # like this!! 'ap-northeast-1'
})
APPLICATION_ARN = 'YOUR_APPLICTION_ARN' #like this!! 'arn:aws:sns:ap-northeast-1:012345678901:app/APNS_SANDBOX/YourApp'
# メッセージに加えて、custom_idという追加のパラメータを送るメソッド。
# パラメータは複数追加できるので適当に書き換えてね。
def push(token, message, custom_id)
sns = AWS::SNS.new
client = sns.client
# 存在しない場合は作成する
response = client.create_platform_endpoint(
platform_application_arn: APPLICATION_ARN,
token: token
)
# endpointを取得して通知を送る
endpoint_arn = response[:endpoint_arn]
# https://github.com/aws/aws-sdk-ruby/issues/336
apns_payload = { "aps" => { "alert" => message,"sound" => 'default', "custom_id" => custom_id } }.to_json
# これはSANDBOXのとき。本番のときは書き換えてね。
message = { "default" => "ok", "APNS_SANDBOX" => apns_payload }.to_json
client.publish(target_arn: endpoint_arn, message: message, message_structure: 'json')
end
# iosアプリから上がってきたトークンをDBとかに保存しといて使う。
push('TSKSEFWQCYV5MZ5UAWTGT5TPBRDKQ293ZVA3MRXMQZCPA82NAXLPDBRQS9AUFTXD','hello world', 12)
iosアプリの通知時の処理
今回は初回起動時と起動中に通知が来た場合を同じ処理にするため、起動中に通知が来たときにウィンドウを初期化するようにした。
AppDelegate.m
// 初回起動時に呼ばれるやつ
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// プッシュ通知の要求
// ... (上記で書いたコード)
// END プッシュ通知の要求
// ウィンドウの初期化
[self initializeWindow:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
// Your Code
}
// アプリが起動中に通知が来て、通知をタップしたときに呼ばれるやつ
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
// 起動中の画面でなにを表示しているかに関わらず、ここでウィンドウを初期化してしまっている。
// メモリとかはバゲッジコレクションにおまかせだけど、大丈夫かな・・・
[self initializeWindow:userInfo];
}
// 画面を初期化&通知の場合はオプションに基づいて処理
- (void)initializeWindow:(NSDictionary *)options {
NSLog(@"launch options: %@", options);
// application:didFinishLaunchingWithOptions:launchOptionsによく書いてあるウィンドウの初期化処理
// 適当に書き換えてね。
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.mainViewController = [[YourViewController alloc] init];
self.navController = [[UINavigationController alloc]
initWithRootViewController:self.mainViewController];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
// ここまでウィンドウ初期化処理
// ここから通知に基づいた処理
if (options[@"aps"]) {
NSDictionary *apsOptions = options[@"aps"];
// オプションに基づいて処理
// custom_idのところは適当に書き換えてね。
your_method(apsOptions[@"custom_id"]);
// 例えば、得られたIdにもとづいてページを表示。適当に書き換えてね。
// NSNumber *custom_id =apsOptions[@"custom_id"];
// [hogehoge showPage:custom_id];
}
}