【expo】firebaseでアプリのバージョン管理を実装する方法【コード例】

アプリをリリースしたときに、
旧バージョンを使用している人には、予期せぬエラーが出ないようにするために、アプリのバージョン管理を実装することが必須です。

アプリのバージョンを管理することによって、
ユーザーの状況を制御することができ、要らぬエラーなどによるユーザー離脱を防ぐことができます。

今回は、expoでfirebaseを使用して、バージョン管理を実装します。

実際に私のアプリで実装している内容ですので、テスト済みの内容になります。

あべべ

掲載するコードは、なるべくコピペでできるようにしていますので、

ぜひそのまま使ってやってください!

【前提】firebaseとの接続はできている

では、実装をしていく前に、
まずは前提確認をして行きます。

今回の実装においては、firebaseを利用します。
そのため、firebaseには既に接続できている、データを取り出すことができる状態にしておいてください。

firebaseをまだ実装していない方

以下の記事で、expoを使用したfirebaseとの接続方法を紹介しています。

では、firebaseに接続できた(できている)という方は、expoで実際に実装をして行きましょう。

実装手順

今回の実装の流れを紹介します。

実装の流れ

①firebase/firestoreから最新のバージョン情報を取得

②バージョンを確認する関数を実装

③画面起動時、フォアグラウンドに戻った時に関数が動くように実装

この3つの流れで進めていきます。

firebase/firestoreの方に、現在の最新のバージョン情報を保存しておきます。

アプリは起動時にfirebaseと確認し、今のアプリがそれに等しいかどうかを確認する。

という流れになります。

【コード】①firebase/firestoreから最新のバージョン情報を取得

まず、firebase/firestoreから、データを読み込みます。

この読み込み方は人それぞれ自由に設定していただいて問題ありません。

今回はコレクションからデータを引っ張ってくる方法で行います。

const [sentence, set_sentence] = useState(""); 

const fetch_global_data = async() => {
  let data= {};
  const querySnapshot_global = await getDocs(collection(db, "global_match_data"));
  querySnapshot_global.forEach((doc) => {
    data.android_version=doc.data().android_version;
    data.ios_version=doc.data().ios_version;
  });
  set_sentence(data)
 }

firebase内では以下のように保存してます。

では、このバージョン情報をもとに関数を作成します。

【コード】②バージョンを確認する関数を実装

次に、firebaseから取得した最新のバージョン情報と、
ユーザーが利用しているアプリのバージョン情報を比較して、違っている場合にはストアに遷移させるダイアログを出すようにします。

import { Platform,Alert,Linking } from "react-native";
import Constants from 'expo-constants';

const checkVersionAndUpdateIfNeeded = async () => {
    const currentVersion = Platform.OS === 'android' ? Constants.expoConfig.android.versionCode : Constants.expoConfig.ios.buildNumber;
    const latestVersion = Platform.OS === 'android' ? sentence.android_version : sentence.ios_version;
    const storeUrl = Platform.OS === 'android'
      ? 'https://play.google.com/store/games'
      : 'https://www.apple.com/jp/app-store/';
  
    if (currentVersion !== latestVersion) {
      Alert.alert(
        "新しいバージョンが利用可能です",
        "最新の機能を利用するには、ストアからアップデートしてください。",
        [{ text: "ストアへ遷移", onPress: () => Linking.openURL(storeUrl) }],
        { cancelable: false }
      );
    }
  };

Platformでは、ユーザーが利用しているデバイスの種類を判別できます。

今回は、iOS,Androidのみだと想定しているので、androidかどうかを判定しています。

if文の中で、currentVersion(現在のユーザーが利用しているアプリのバージョン)と、

latestVersion(firebase上に保存してあるバージョン)を比較して、違っている場合にはモーダルを出すようにしています。

あべべ

今設定しているリンクは、仮のものですので、あなたのアプリのストアページをそれぞれ書き換えてあげてください!

【コード】③画面起動時、フォアグラウンドに戻った時に関数が動くように実装

先ほど準備した関数を適当な時に動かします。

動かしたいのは、以下の2つです。

  1. 画面起動時
  2. バックグラウンドからフォアグラウンドに戻った時

それぞれのコードを書いていきます。

画面起動時に実行するコード

useEffect(() => {
    if(sentence.ios_version&&sentence.android_version){
      checkVersionAndUpdateIfNeeded();
    }
  },[sentence])

こちらは、特別なことはなくuseEffectを使用して、関数を動かしています。

もし、firebaseにバージョン情報がなかったら実行しないようにif文を組んでいます。

バックグラウンド→フォアグラウンドに戻った時実行するコード

アプリがバックグラウンドからフォアグラウンドに戻った時にも、アプリのバージョンチェックが必要になります。

あべべ

例えば、
アプリ起動時に、バージョンが違くてストアに遷移します。
しかし、ストアではアップデートせずにアプリに戻ってきた場合などが考えられます。

そのような場合をカバーするために、バックグラウンドからフォアグラウンドになった時にも関数を実行します。

import { AppState } from 'react-native';
const [appState, setAppState] = useState(AppState.currentState);

useEffect(() => {
    const subscription = AppState.addEventListener("change", nextAppState => {
      if (appState.match(/inactive|background/) && nextAppState === "active") {
        console.log("アプリがフォアグラウンドに戻りました!");
        // ここに実行したい関数を呼び出す
        checkVersionAndUpdateIfNeeded();
      }
      setAppState(nextAppState);
    });

    return () => {
      subscription.remove();
    };
  }, [appState]);

上記のコードをコピペして、import文なども書けば動かせます。

他にも実行したい関数がある場合には、コメントアウトしている箇所に複数の関数を書き加えればOKです。

あべべ

ここのコードの内容を詳しく知りたい方は以下の記事を参考にしてくださいね!

コードの全体像

上記で書いたコードをそれぞれまとめて書くと以下の様になります。

import { Platform,Alert,Linking } from "react-native";
import Constants from 'expo-constants';
import { AppState } from 'react-native';


const [sentence, set_sentence] = useState(""); 
const [appState, setAppState] = useState(AppState.currentState);


const fetch_global_data = async() => {
  let data= {};
  const querySnapshot_global = await getDocs(collection(db, "global_match_data"));
  querySnapshot_global.forEach((doc) => {
    data.android_version=doc.data().android_version;
    data.ios_version=doc.data().ios_version;
  });
  set_sentence(data)
 }


const checkVersionAndUpdateIfNeeded = async () => {
    const currentVersion = Platform.OS === 'android' ? Constants.expoConfig.android.versionCode : Constants.expoConfig.ios.buildNumber;
    const latestVersion = Platform.OS === 'android' ? sentence.android_version : sentence.ios_version;
    const storeUrl = Platform.OS === 'android'
      ? 'https://play.google.com/store/games'
      : 'https://www.apple.com/jp/app-store/';
  
    if (currentVersion !== latestVersion) {
      Alert.alert(
        "新しいバージョンが利用可能です",
        "最新の機能を利用するには、ストアからアップデートしてください。",
        [{ text: "ストアへ遷移", onPress: () => Linking.openURL(storeUrl) }],
        { cancelable: false }
      );
    }
  };

useEffect(() => {
    if(sentence.ios_version&&sentence.android_version){
      checkVersionAndUpdateIfNeeded();
    }
  },[sentence])


useEffect(() => {
    const subscription = AppState.addEventListener("change", nextAppState => {
      if (appState.match(/inactive|background/) && nextAppState === "active") {
        console.log("アプリがフォアグラウンドに戻りました!");
        // ここに実行したい関数を呼び出す
        checkVersionAndUpdateIfNeeded();
      }
      setAppState(nextAppState);
    });

    return () => {
      subscription.remove();
    };
  }, [appState]);

これで実装完了になります。
シミュレーターなどでテストしてみてくださいね。

まとめ

今回は、expoでアプリのバージョン管理を実装する方法について紹介して行きました。

バージョンを適切に管理することで、ユーザーのクラッシュを回避することができます。
ぜひ早期に実装していただけると良いかと思います!

では、また!

(Visited 64 times, 1 visits today)