React Native + Expoのプロジェクトでストアレビューを依頼する

以下のようなユーザーにレビューを依頼するための仕組みを作ります。

ライブラリをインストール

shell
npx expo install expo-store-review expo-linking

日付の比較、次回レビュー日を保存するためのライブラリもインストールします。

shell
npx expo install dayjs @react-native-async-storage/async-storage

レビューを依頼する hooks を作成

useStoreReview.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import dayjs, { type Dayjs } from 'dayjs';
import * as StoreReview from 'expo-store-review';

/** レビュー依頼の頻度(何日おきにレビュー依頼するか) */
const REVIEW_PERIOD_BY_DATE = 3;

/** リセット用のレビュー日を何日前にするか */
const RESET_REVIEW_DATE_BY_DATE = -1;
export default function useStoreReview() {
  /**
   * 次回レビュー日を取得する。取得できなかった場合は初回起動である。
   */
  const getNextReviewDate = async () => {
    return await AsyncStorage.getItem('nextReviewDate');
  };

  /**
   * 次回のレビュー依頼日を取得する
   * @param {number} period 何日後か
   */
  const getNextReviewDateByPeriod = (period: number) => {
    return dayjs().add(period, 'day');
  };

  /**
   * 次回のレビュー依頼日を保存する
   */
  const updateNextReviewDate = async (nextReviewDate: Dayjs) => {
    await AsyncStorage.setItem('nextReviewDate', nextReviewDate.format('YYYY-MM-DD'));
  };

  /**
   * 開発時の動作検証のため、レビュー依頼日をリセットする
   */
  const resetNextReviewDate = async () => {
    const nextReviewDate = getNextReviewDateByPeriod(RESET_REVIEW_DATE_BY_DATE);
    await AsyncStorage.setItem('nextReviewDate', nextReviewDate.format('YYYY-MM-DD'));
  };

  /**
   * 初回起動時にレビュー依頼日を保存する
   */
  const setInitialNextReviewDate = async () => {
    const initialNextReviewDate = getNextReviewDateByPeriod(REVIEW_PERIOD_BY_DATE);
    await updateNextReviewDate(initialNextReviewDate);
  };

  /**
   * 今日がレビュー依頼日に到達しているかどうかを判定する
   */
  const doesReachedNextReviewDate = async () => {
    const nextReviewDate = await getNextReviewDate();
    if (nextReviewDate != null) {
      return dayjs().isAfter(dayjs(nextReviewDate, 'YYYY-MM-DD'));
    }
    return false;
  };

  const developmentRequestReview = async () => {
    try {
      const nextReviewDate = await getNextReviewDate();
      if (nextReviewDate == null) {
        await setInitialNextReviewDate();
        return;
      }
      // 開発用のため、レビュー依頼日をリセットする
      await resetNextReviewDate();

      const reachedNextReviewDate = await doesReachedNextReviewDate();
      const isReviewAvailable = await StoreReview.isAvailableAsync();

      if (isReviewAvailable && reachedNextReviewDate) {
        await StoreReview.requestReview();
        const nextReviewDate = getNextReviewDateByPeriod(REVIEW_PERIOD_BY_DATE);
        await updateNextReviewDate(nextReviewDate);
      }
    } catch (error) {
      console.log(error);
    }
    return `レビューを依頼しました。`;
  };

  const requestReview = async () => {
    try {
      const nextReviewDate = await getNextReviewDate();
      if (nextReviewDate == null) {
        await setInitialNextReviewDate();
        return;
      }

      const reachedNextReviewDate = await doesReachedNextReviewDate();
      const isReviewAvailable = await StoreReview.isAvailableAsync();

      if (isReviewAvailable && reachedNextReviewDate) {
        await StoreReview.requestReview();
        const nextReviewDate = getNextReviewDateByPeriod(REVIEW_PERIOD_BY_DATE);
        await updateNextReviewDate(nextReviewDate);
      }
    } catch (error) {
      console.log(error);
    }
    return `レビューを依頼しました。`;
  };

  return { developmentRequestReview, requestReview };
}

App.tsx で hooks を使う

App.tsx
export default function App() {
  const { requestReview } = useStoreReview();

  useEffect(() => {
    requestReview()
      .then((result) => {
        console.log(result);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  return (
    {/** 省略 */}
  );
}

参考

app.json に appStoreUrl を設定する

ルートディレクトリにある app.jsonappStoreUrl を設定します。以下は iOS の例です。

app.json
    "ios": {
      "supportsTablet": false,
      "appStoreUrl": "https://apps.apple.com/app/id1539375279"
    },

アプリのIDは App Store を開けばわかります。 /us/ のように、USAのリージョンコードが振られているように見えますが、一応、日本で開くと ja にリダイレクトされるっぽかったです。ちょっとここは自信がないので、実際のプロダクトで動作確認後に追記します。

iOS アプリの ID の調べ方の参考リンクは以下です。

5回保存したらレビューを依頼する(レビューのタイミングをイベント契機にする)

この記事では単純に起動回数をトリガにしましたが、「保存を5回実行したらレビュー依頼する」などの方が、より柔軟にレビューを出すユーザーを厳選できます。

以下の記事によりシンプルな方法をまとめました。