概要
iOSの機能であるサイレントプッシュを使って、定期的にアプリ側でバックグランドフェッチして情報を収集したいケースがありましたので、Azure Functions を使ってみた!という話です。
通知を送るのに使ったサービスは Firebase Cloud Messaging なのですが、そのFCMをキックするのに Azure Functions を使いました。サーバレスかつ、全部無料で実装できたのでウマウマです。
構成
環境
- Firebase Cloud Messaging
- Azure Functions
- iOSアプリ
サイレントプッシュ通知とは
- iOS7から実装された機能です。サイレントプッシュ通知は名前の通り、アラートや音が出ないのでプッシュを受け取ったことはユーザには分かりません。
- 通知を受け取った端末は 30秒間 だけ処理を実行することが出来るので、その間にアプリはAPIをリクエストしたりして最新の状態にすることが出来ます。
- 注意したいのは、端末やアプリの状態によってはサイレントプッシュ通知を受け取っても処理がされない場合があります。例えば以下のケースでは処理が実行されません。
- マルチタスク機能でユーザ自らアプリをキルした状態の場合
- iOSの設定でアプリのバックグラウンド更新を有効にしていない場合
- iOSの設定でバッテリーの低電力モードを有効にしている場合
Azure Functionsを使うメリット
-
タイマー起動ができる
定期的にサイレントプッシュを送りたいのですが、Azure Functionsならタイマー起動ができるのが魅力的でした。他のAWSやGCP等のFaaSを調べてもタイマー機能があるのはAzureだけでした。 -
Functionsの呼び出しは 月100万リクエストまで無料
サイレントプッシュは30分単位で送りたかったので、余裕で無料枠で出来ることが分かり選択材料の1つとなりました。 -
設定が簡単
実際やってみて短時間で設定が出来ました。サイレントプッシュするだけなら、登録する実行コードはFCMにHttpリクエストするだけです。
iOSアプリ、FCMについて
iOSアプリとFirebase Cloud Messaging の設定ついてはこの記事では割愛します。
代わりに参考にしたリンクを貼っておきます。
- iOS での Firebase Cloud Messaging クライアント アプリの設定
- 【iOS】Firebase の Notifications でプッシュ通知を送る
- 【iOS10】Firebaseでサイレント通知を行う
Azure Functionsの設定
1、Functionを作るためメニューの「リソースの作成」を選び、「Compute」->「Function App」を選びます。
2、作成画面に遷移するので、「アプリ名」に好きな名前を入れます(他はデフォルトのままにしました。また、従来課金プランにしないと無料にならなそうです。)
3、「作成」ボタンをクリックすると、デプロイが始まるので終わるまで待ちます。
4、デプロイが終わると通知が来ますので、「リソースへ移動」を選びます。
5、次にメニューの関数の横にある「+」ボタンを選びます。すると。シナリオと言語を選ぶ画面が表示されるのですが、下部に「カスタム関数」を選択します。
6、テンプレートが表示されるので、「Time trigger」を選択します。
7、言語、関数名、タイマースケジュールの設定が表示されるので好きな設定に変更します。(ここでは言語はjavascriptで、タイマーを30分周期にしたかったので以下のように設定をしました)
8、ここまで出来たら次はHTTPリクエストを簡単に実装するため、Node.jsのパッケージをインストールします。https://{function_app_name}.scm.azurewebsites.net
にブラウザでアクセスします。自分の場合だと https://silentpushtest.scm.azurewebsites.net になります。(ここについて詳しく知りたい方はAzure Functions の JavaScript 開発者向けガイドが参考になるかと思います。)
9、すると、以下の画面になると思うので、メニューの「Debug Console」-> 「CMD」を選択します。
10、コンソール画面に遷移するので、D:\home\site\wwwroot
までディレクトリを下っていきます。そしたら npm init
を実行します。質問の回答はデフォルトのままにしました(ひたすらEnter)
D:\home\site\wwwroot> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (wwwroot)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to D:\home\site\wwwroot\package.json:
{
"name": "wwwroot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this ok? (yes)
11、package.jsonが作られていればOKです。次に request
パッケージをインストールします。
D:\home\site\wwwroot> npm install request --save
wwwroot@1.0.0 D:\home\site\wwwroot
`-- request@2.87.0
(省略)
12、さて、Functionの設定に戻ります。先ほど作成したFunctionを選ぶとソースコードを実装する画面になります。
13、ソースコードを以下にようにします。ServerKey
はFirebaseの設定画面から取得することができます。TopicName
はアプリ側で購読させたTopic名を指定してください。
module.exports = function (context, myTimer) {
var timeStamp = new Date().toISOString();
if (myTimer.isPastDue) {
context.log('JavaScript is running late!');
}
var request = require('request');
var options = {
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'key={ServerKey}'
},
json: {
to: '/topics/{TopicName}',
priority: 'high',
content_available: true
}
};
request.post(options, function (error, response, body) {
context.log("Response Code : "+response.statusCode);
});
context.log('JavaScript timer trigger function ran!:', timeStamp);
context.done();
};
14、「実行」ボタンを押すことで試しにサイレントプッシュが送れるか確認することができます。実行してみて問題がなければ「保存」ボタンを押して Functionの設定は以上で終わりです!
最後に
説明が長くなってしまいましたが、やってることはほぼGUI操作で終わるのでとても楽でした。
なりより、サーバを持たないかつ、無料で実装出来たのが非常に良かったです!