kuatsu / react-native-cloud-storage

☁️ Save to & read from iCloud and Google Drive using React Native
https://react-native-cloud-storage.oss.kuatsu.de/docs/intro
MIT License
141 stars 10 forks source link

Uploading files or creating folders to Google Drive on Android Error #33

Closed archie-wu-lb closed 6 months ago

archie-wu-lb commented 6 months ago

CleanShot 2024-05-28 at 16 37 22

I'm trying to write some data to Google Drive. When I was adding a new file, I encountered this issue. Uploading to iCloud on iOS works fine, but uploading to Google Drive on Android causes this issue.

This is my code When i call startSyncDataToCloud

I will get this error return Could not get file id for path

import {
  GoogleSignin,
  isErrorWithCode,
  statusCodes,
} from '@react-native-google-signin/google-signin';
import Config from 'react-native-config';
import {
  CloudStorage,
  CloudStorageError,
  CloudStorageErrorCode,
  useIsCloudAvailable,
} from 'react-native-cloud-storage';
import { useEffect, useState } from 'react';
import { Platform } from 'react-native';
import * as AesCrypto from '@/utils/aesCrypto';

  const cloudAvailable = useIsCloudAvailable();
  const [loading, setLoading] = useState(false);

  GoogleSignin.configure({
    scopes: [
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/drive.appdata',
    ],
    webClientId: Config.GOOGLE_WEB_ID, // Different environments
    offlineAccess: true,
  });

  /**
   * Get Google Token
   * @returns Whether obtaining Google Token is successful
   */
  const getGoogleToken = async () => {
    try {
      await GoogleSignin.hasPlayServices();
      await GoogleSignin.signIn();
      const token = await GoogleSignin.getTokens();
      CloudStorage.setGoogleDriveAccessToken(
        token?.accessToken?.length ? token?.accessToken : null,
      );
      return true;
    } catch (error) {
      console.log('error', error);
      if (isErrorWithCode(error)) {
        switch (error.code) {
          case statusCodes.SIGN_IN_CANCELLED:
            // user cancelled the login flow
            break;
          case statusCodes.IN_PROGRESS:
            // operation (eg. sign in) already in progress
            break;
          case statusCodes.PLAY_SERVICES_NOT_AVAILABLE:
            // play services not available or outdated
            break;
          default:
          // some other error happened
        }
      } else {
        // an error that's not related to google sign in occurred
      }
      return false;
    }
  };

  /**
   * Check if directory exists
   * @param parentDirectory Directory path
   * @returns Whether it exists
   */
  const handleCheckDirectoryExists = async (parentDirectory: string) => {
    setLoading(true);
    let exists = false;
    try {
      exists = await CloudStorage.exists(parentDirectory);
    } catch (e) {
      console.warn(e);
    } finally {
      setLoading(false);
      return exists;
    }
  };

  const handleCreateDirectory = async (parentDirectory: string) => {
    setLoading(true);
    let exists = false;
    try {
      exists = await handleCheckDirectoryExists(parentDirectory);
      if (exists) {
        return exists;
      }
      console.log('handle Create Directory');
      console.log('parentDirectory', parentDirectory);
      await CloudStorage.mkdir(parentDirectory);
      console.log('Create directory success');
      exists = true;
    } catch (e) {
      console.warn(e);
      exists = false;
    } finally {
      setLoading(false);
      return exists;
    }
  };

  const handleCreateFile = async (params: {
    parentDirectory: string;
    filename: string;
    data: string;
  }) => {
    const { parentDirectory, filename, data } = params;
    let result = false;
    setLoading(true);
    try {
      await CloudStorage.writeFile(parentDirectory + '/' + filename, data);
      result = true;
    } catch (e) {
      console.warn(e);
    } finally {
      setLoading(false);
      return result;
    }
  };

  /**
   * Start syncing data to the cloud
   * @param data Text data
   * @param name File name
   */
  const startSyncDataToCloud = async (params: {
    data: string;
    name: string;
    password: string;
  }) => {
    const { data, name, password } = params;
    const parentDirectory = '/backup';
    const filename = `${name}.txt`;

    if (!cloudAvailable) {
      if (Platform.OS === 'android') {
        const getTokenSuccess = await getGoogleToken();
        if (!getTokenSuccess) {
          return false;
        }
      } else {
        return false;
      }
    }
    const exists = await handleCreateDirectory(parentDirectory);
    console.log('exists', exists);
    if (!exists) {
      return exists;
    }
    const encryptedData = encodeData(data, password);
    return await handleCreateFile({
      parentDirectory,
      filename,
      data: encryptedData,
    });
};
minhkwan commented 4 months ago

Can you share how you solve this? I have the same problem. Tks!

archie-wu-lb commented 4 months ago

It would help if you saw more detailed error messages. My situation is that some permissions of my project are not enabled.

timmyjose commented 1 month ago

It would help if you saw more detailed error messages. My situation is that some permissions of my project are not enabled.

@archie-wu-lb Do you mean in the app or on Google Cloud Console/Firebase Console? Could you please elaborate?

timmyjose commented 1 month ago

It would help if you saw more detailed error messages. My situation is that some permissions of my project are not enabled.

@archie-wu-lb Do you mean in the app or on Google Cloud Console/Firebase Console? Could you please elaborate?

In case it helps someone else with a similar issue.

In my case, the issue was with the Google Cloud configuration for the project. In the working prototype, I had enabled "Google Drive API' in the project settings in the Google Cloud dashboard. For the main app, I'd forgotten to do this. So the issue was from the react-native-google-signin generating an access token without the necessary permissions (so to speak) of accessing Google Drive via react-native-cloud-storage.

Once I enabled the Google Drive API for the main app, it started working as expected.

archie-wu-lb commented 1 month ago

@timmyjose Yes, I also encountered the same problem. I didn't enable enough permissions in Firebase, but I saw the error message in the application itself. However, I remember the error message wasn't very complete. I found a related solution on Stack Overflow, but your approach should be correct. The Google Cloud Console/Firebase Console should have more detailed error messages, but at the time, I didn't have permission to view them.