Data BackupData RestoreExpo bareExpo RouterReact NativeReact Native Paper

【ReactNative】スマホの機種変更前のデータ引き継ぎ機能を実装する〜アプリ実装済み〜

abundance Data Backup
スポンサーリンク

暗号化+バックアップ版Apollo ClientReactive variables データと SQLite のデータを暗号化し バックアップ ➡︎ リストア する方法をご紹介しています。

開発環境(Expo Bare)

  • “typescript”: “^5.2.2”
  • “expo”: “~49.0.13”,
  • “react”: “18.2.0”,
  • “react-native”: “0.72.6”,
  • “expo-router”: “^2.0.0”,
  • “react-native-paper”: “^5.10.6”,
  • @apollo/client: “^3.8.5”,
  • expo-sqlite”: “~11.3.3”,
  • crypto-js: “^4.2.0”,
  • expo-sharing: “~11.5.0”,
  • expo-file-system”: “~15.4.5”,

※24/02/13 追記

Expo SDK@50 にアップグレードして node_modules/expo-router/_ctx.ios.tsx: Expected fromDir to be of type string, got undefined エラーが発生した場合は使い方がほぼ同じである rn-crypto-js を代わりに使っても良いと思います。

セットアップする

@apollo/client (フロントエンド ONLY)

// _layout.tsx

export default function RootLayout() {
  const client = useApolloNoPersistClient();
...

  return (
    <SafeAreaProvider>
        <ApolloProvider client={client}>
          <PaperProvider theme={paperTheme}>
            <RootLayoutNav />
            <StatusBar style={preferredTheme === 'dark' ? 'light' : 'dark'} />
          </PaperProvider>
        </ApolloProvider>
    </SafeAreaProvider>
  );
}

// useApolloNoPersistClient.tsx

import {useState, useEffect} from 'react';
import {ApolloClient, InMemoryCache, NormalizedCacheObject} from '@apollo/client';

export const useApolloNoPersistClient = () => {
  const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>(
    {} as ApolloClient<NormalizedCacheObject>,
  );

  useEffect(() => {
    async function init() {
      setClient(new ApolloClient({cache: new InMemoryCache(), connectToDevTools: true}));
    }

    init().catch(err => {
      console.log(err);
    });
  }, []);

  return client;
};

expo-sqlite

詳細は下記をご参考ください。

crypto-js (暗号化ライブラリ)

inlineRequires: true 設定を追加する

// metro.config.js

...

module.exports = {
  ...config,
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

react-native-get-random-values を追加する

yarn add react-native-get-random-values

crypto-jsをインポートする前に react-native-get-random-valuesをインポートする

// _layout.tsx

import 'react-native-get-random-values';  // <-- 追加する (Line1)
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {LogBox, AppState, Platform} from 'react-native';
。。。

crypto-jsを追加する

npm install crypto-js

プロジェクトをリビルドする

# For iOS
npx pod-install
npx react-native run-ios

# For Android
npx react-native run-android

expo-sharing / expo-file-system

割愛します。(expo-sharingexpo-file-system)

バックアップする

  • Step1
    データを抽出する
    // Reactive Variables
    const backupRVLists = [
          {rvCommon: {userId:'123456', preferredTheme: 'light', point: 0, ...}
        ]; 
    
    // SQLite
    const backupDBLists = [{items: items}];
    
    const backupLists = [...backupRVLists, ...backupDBLists];

    ※ items 抽出方法(例)

  • Step2
    暗号化する
    const ciphertextOfBackuped = CryptoJS.AES.encrypt(
      JSON.stringify(backupLists),
      'secret key 123',
    ).toString();
  • Step3
    プラットフォーム別バックアップする

    自身の iCound・Dropbox・Google Drive など外部の媒体に保存します。

    if (Platform.OS === 'ios') {
      jcommonMapper.backupIOS(ciphertextOfBackuped);
    } else if (Platform.OS === 'android') {
      jcommonMapper.backupAndroid(ciphertextOfBackuped);
    }
  • Step3-1
    jcommonMapper.backupAndroid()
    import {Share} from 'react-native';
    import * as FileSystem from 'expo-file-system';
    import * as Sharing from 'expo-sharing';
    
    export const jcommonMapper = {
    ...
    backupAndroid: async (jsonData: string) => {
        const fileUrl =
          FileSystem.documentDirectory + `kotango.xxxxxxxx.json`;
        FileSystem.writeAsStringAsync(fileUrl, jsonData).then(async () => {
          if (await Sharing.isAvailableAsync()) {
            try {
              Sharing.shareAsync(fileUrl, {
                UTI: '.json',
                dialogTitle: 'Kotango | データバックアップ',
                mimeType: 'application/json',
              });
            } catch (err) {
              console.log('!@# backup/err:', err);
            }
          }
        });
      },
    ...
    }
  • Step3-2
    jcommonMapper.backupIOS()
    export const jcommonMapper = {
    ...
    backupIos: async (jsonData: string) => {
        const fileUrl =
          FileSystem.documentDirectory + `kotango.xxxxxxxx.json`;
        FileSystem.writeAsStringAsync(fileUrl, jsonData).then(async () => {
          try {
            const result = await Share.share({url: fileUrl});
            if (result.action === Share.sharedAction) {
              console.log('成功しました!');
            } else if (result.action === Share.dismissedAction) {
              // iOS only
              console.log('キャンセルされました!!');
            }
          } catch (error: any) {
            console.log('!@# error:', error);
          }
        });
      },
    ...
    }
  • Step4
    バックアップファイル(最終版)を確認する

    復元時に暗号化キーを使って復号化しますので、大事に保管してください。

    kotango.xxxxxxxx.json
    暗号化済みのバックアップファイル

動作デモ

Android
iOS

復元する

リリースする

※上記の詳細は以下のアプリに実装されています!

コメント

タイトルとURLをコピーしました