1

Our application should have the functionality to save Application files to Google Drive. Of course, using the local configured account.

From Android API i tried to figure out some clue. But android API with Xamarin implementation seems very tough for me.

I have installed Google Play Services- Drive from Xamarin Components but there are no examples listed from which we can refer the flow and functionality.

UnableToGoogle
  • 99
  • 2
  • 12

1 Answers1

3

The basic steps (see the link below for full details):

  • Create GoogleApiClient with the Drive API and Scope

  • Try to connect (login) the GoogleApiClient

  • The first time you try to connect it will fail as the user has not selected a Google Account that should be used

    • Use StartResolutionForResult to handle this condition
  • When GoogleApiClient is connected

    • Request a Drive content (DriveContentsResult) to write the file contents to.

    • When the result is obtained, write data into the Drive content.

    • Set the metadata for the file

    • Create the Drive-based file with the Drive content

Note: This example assumes that you have Google Drive installed on your device/emulator and you have registered your app in Google's Developer API Console with the Google Drive API Enabled.

C# Example:

[Activity(Label = "DriveOpen", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity, GoogleApiClient.IConnectionCallbacks, IResultCallback, IDriveApiDriveContentsResult
{
    const string TAG = "GDriveExample";
    const int REQUEST_CODE_RESOLUTION = 3;

    GoogleApiClient _googleApiClient;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.Main);

        Button button = FindViewById<Button>(Resource.Id.myButton);
        button.Click += delegate
        {
            if (_googleApiClient == null)
            {
                _googleApiClient = new GoogleApiClient.Builder(this)
                  .AddApi(DriveClass.API)
                  .AddScope(DriveClass.ScopeFile)
                  .AddConnectionCallbacks(this)
                  .AddOnConnectionFailedListener(onConnectionFailed)
                  .Build();
            }
            if (!_googleApiClient.IsConnected)
                _googleApiClient.Connect();
        };
    }

    protected void onConnectionFailed(ConnectionResult result)
    {
        Log.Info(TAG, "GoogleApiClient connection failed: " + result);
        if (!result.HasResolution)
        {
            GoogleApiAvailability.Instance.GetErrorDialog(this, result.ErrorCode, 0).Show();
            return;
        }
        try
        {
            result.StartResolutionForResult(this, REQUEST_CODE_RESOLUTION);
        }
        catch (IntentSender.SendIntentException e)
        {
            Log.Error(TAG, "Exception while starting resolution activity", e);
        }
    }

    public void OnConnected(Bundle connectionHint)
    {
        Log.Info(TAG, "Client connected.");
        DriveClass.DriveApi.NewDriveContents(_googleApiClient).SetResultCallback(this);
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_RESOLUTION)
        {
            switch (resultCode)
            {
                case Result.Ok:
                    _googleApiClient.Connect();
                    break;
                case Result.Canceled:
                    Log.Error(TAG, "Unable to sign in, is app registered for Drive access in Google Dev Console?");
                    break;
                case Result.FirstUser:
                    Log.Error(TAG, "Unable to sign in: RESULT_FIRST_USER");
                    break;
                default:
                    Log.Error(TAG, "Should never be here: " + resultCode);
                    return;
            }
        }
    }

    void IResultCallback.OnResult(Java.Lang.Object result)
    {
        var contentResults = (result).JavaCast<IDriveApiDriveContentsResult>();
        if (!contentResults.Status.IsSuccess) // handle the error
            return;
        Task.Run(() =>
        {
            var writer = new OutputStreamWriter(contentResults.DriveContents.OutputStream);
            writer.Write("Stack Overflow");
            writer.Close();
            MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                   .SetTitle("New Text File")
                   .SetMimeType("text/plain")
                   .Build();
            DriveClass.DriveApi
                      .GetRootFolder(_googleApiClient)
                      .CreateFile(_googleApiClient, changeSet, contentResults.DriveContents);
        });
    }

    public void OnConnectionSuspended(int cause)
    {
        throw new NotImplementedException();
    }

    public IDriveContents DriveContents
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public Statuses Status
    {
        get
        {
            throw new NotImplementedException();
        }
    }
}

Ref: https://developers.google.com/drive/android/create-file

SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • Thanks for your reply. This results opening a drive popup asking user to select/download file from/to drive. Can we do it in background? Without any drive UI? – UnableToGoogle Jul 18 '16 at 11:00
  • 1
    @UnableToGoogle This code only calls the `REQUEST_CODE_RESOLUTION` code path, I'll remove the other section, that was example code for allowing the user to select a file to download/open . The only UI that pops up is for the user to select which Account to use – SushiHangover Jul 18 '16 at 11:03
  • @UnableToGoogle Great to hear it... Happy Xammie Coding ;-) – SushiHangover Jul 18 '16 at 11:22
  • Hi, is there anything for xamarin.forms available? I mean is it not possible to do achieve this for WP UWP and ios? It would be nice to have this on PCL side – Emil Nov 11 '16 at 12:41
  • 1
    @batmaci Google has a full Rest API, that is what all their higher level API for Drive use (they always use a Rest layer for all their API/Services), and it works fine in Forms/PCL, Personally I prefer using it as it removes a lot of weight in implementation (memory/performance/app size) : https://developers.google.com/drive/v3/web/about-sdk – SushiHangover Nov 11 '16 at 12:50
  • I wish there were examples on how to list the children of a folder and how to read a text file. – Dpedrinha Aug 08 '17 at 06:23
  • @Dpedrinha Post a question of the code that you have that is not working – SushiHangover Aug 08 '17 at 06:26
  • @SushiHangover here it is: https://stackoverflow.com/questions/45561179/how-to-list-all-children-in-google-drives-appfolder-and-read-file-contents-with – Dpedrinha Aug 08 '17 at 15:47
  • @SushiHangover Is it really possible to use Rest layer Api Services in share code like .net standard 2.0 without going into android, ios or uwp level? Is there any sample code for that? – Emil Mar 19 '18 at 12:30
  • @batmaci Certainly is, the Rest api is, well, a Rest api ;-) Works fine with HttpClient (via the Xamarin's platform native handlers of course). At this time I can not share the code that I've written, but once you have the OAuth2 token with the proper scope applied, using the Rest api is just a bunch of GET, POST, PATCH, & DELETE HTTPS-based calls. – SushiHangover Mar 20 '18 at 21:16
  • @SushiHangover so if I understand correctly, you dont use any xamarin.auth or similar package, but simply authenticate user with http request, dont you need a web api or service in between to get auth code back to your app? – Emil Mar 20 '18 at 21:41
  • @batmaci It depends upon how your system is designed, if you are using OAuth2 explicit flow or not. But if you are **not** injecting your own server/middleware in the process, then yes, you *could* use `Xamarin.Auth` to handle the user login process and return you a scoped token that you will now use via the rest apis... – SushiHangover Mar 20 '18 at 21:51
  • @SushiHangover one last question when using http get request to fetch access token, we should open it in web browser, not within the app using webview as google policy. how to achieve this? does it work with httpclient get request? – Emil Mar 20 '18 at 22:06
  • @batmaci In that case, the user needs to be involved in the direct login to Google via ChromeCustomtabs / SFSafariViewController.... you could use Xamarin.Auth as it provides those interfaces. – SushiHangover Mar 20 '18 at 22:25
  • Is there any updated version of this in 2023? – Pavlos Mavris Jan 03 '23 at 20:54