ExpoのPush Notificationsを使う


## 更新（2019年9月22日）

2019年9月22日現在、expoでPermissionを呼び出す方法が変更されているようです。
末尾に新規コードを載せておきます。

（以下はでは動きません）。

## 手順

* Tokenを取得する（これがしんどかった）
* Tokenを使ってpushを送る

## ハマったこと

Tokenの取得に際し、ずっと下記のようなエラーに悩まされた。
promiseうんぬんはawaitにtry{}catchを入ればよい。が、後者は？？？という感じ。実機にてExpoアプリを削除し、再度「許可」することで復活した。エミュレータで許可しないように注意。

```bash
[Unhandled promise rejection: Error: The Expo push notification service is supported only for Expo projects. Ensure you are logged in to your Expo developer account on the computer from which you are loading your project.]
```

## Tokenの取得

本家サイト含め、ネット上のサンプルコードが動かない。2018年11月10日時点で、下記のコードで取得できた。

```js:App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Permissions, Notifications } from 'expo';

//取得のためのコード
async function registerForPushNotificationsAsync() {

  //warningがでるのを防ぐためにtry catchを入れる
  try {

    const { status: existingStatus } = await Permissions.getAsync(
      Permissions.NOTIFICATIONS
    );
    let finalStatus = existingStatus;

    if (existingStatus !== 'granted') {
      const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
      finalStatus = status;
    }

    if (finalStatus !== 'granted') {
      return;
    }

    let token = await Notifications.getExpoPushTokenAsync();

    //コンソールに出力
    console.log(token);

  } catch (error) {
    console.log(error);
  }
}


export default class App extends React.Component {
  componentDidMount() {
    //呼び出し
    registerForPushNotificationsAsync();
  }
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Open up App.js to start working on your app!</Text>
      </View>
    );
  }
}

```

下記のようなTokenが表示される（はず）。

```bash
[16:54:07] ExponentPushToken[gicUyxNQ23PxCexxxxxxxx]
```

Tokenが取得できればpushのテストが下記サイトで可能。

* https://expo.io/dashboard/notifications

## PHPから送る

[ここ](https://github.com/Alymosul/exponent-server-sdk-php)にやり方が書いてある。

```php:index.php
<?php

require_once __DIR__.'/vendor/autoload.php';
  

// インスタンス作成
$expo = \ExponentPhpSDK\Expo::normalSetup();

// 設定
$expo->subscribe(
    'unique_identifier',
    'ExponentPushToken[gicUyxNQ23PxCexxxxxxxx]'
);

// 電文作成
$notification = ['body' => 'Hello World!', 'data' => '{"name":"hoge", "age":"33"}'];

// 送信
$expo->notify('unique_identifier', $notification);

```

詳細は[本家サイト](https://docs.expo.io/versions/latest/guides/push-notifications)を見る。

## 受け取ったデータの処理

フォワグラウンド（アプリ起動中）は通知がでないので、アプリで表示等の処理をする必要があります。

```php:index.php
import React from 'react';
import { StyleSheet, Text, View, Alert } from 'react-native';
import { Permissions, Notifications } from 'expo';


export default class App extends React.Component {
  componentDidMount() {

	//リスナー登録
    this._notificationSubscription = Notifications.addListener(this._handleNotification);

    //badge消したり
    Notifications.getBadgeNumberAsync().then(badgeNumber => {
      if(badgeNumber !==0){
        Notifications.setBadgeNumberAsync(badgeNumber - 1);
      }
    })

  }

  _handleNotification = (notification) => {
    if(notification.origin === 'selected'){
      //バックグラウンドで通知
    }else if(notification.origin === 'received'){
      //フォアグラウンドで通知
      Alert.alert('通知が来ました:' + notification.data.name);
      console.log(notification.data.name);
    }
  }

  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Open up App.js to start working on your app!</Text>
      </View>
    );
  }
}

```

## 参考サイト

* https://tech.maricuru.com/entry/2018/04/23/185331

## 更新：サンプル（2019年9月22日）

```js:App.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { Notifications } from 'expo';
import  * as Permissions from 'expo-permissions'; //呼び出し方変わってる

export default class App extends React.Component {

    registerForPushNotificationsAsync = async () => {

        try {
            //現在のNotificationパーミッション状況取得
            const { status: existingStatus } = await Permissions.getAsync(
                Permissions.NOTIFICATIONS
            );
            let finalStatus = existingStatus;

            //statusが許可じゃなければ（許可済みなら何もしない）
            if (existingStatus !== 'granted') {
                //許可を尋ねる
                const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
                finalStatus = status;
            }

            //それでも許可されてなかったら何もしない
            if (finalStatus !== 'granted') {
                return;
            }

            const token = await Notifications.getExpoPushTokenAsync();

            alert("token=" + token);
            console.log(token);
        } catch (e) {
            console.log(e);
        }
    }


    render() {
        return (
            <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
                <Text>App</Text>
                <Button
                    title="get Notification token"
                    onPress={this.registerForPushNotificationsAsync}
                />
            </View>
        );
    }
}
```