Skip to content

Instantly share code, notes, and snippets.

@thomashagstrom
Last active April 7, 2024 15:51
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save thomashagstrom/b0856a383bcdcf905c7a774c8c1b0879 to your computer and use it in GitHub Desktop.
Save thomashagstrom/b0856a383bcdcf905c7a774c8c1b0879 to your computer and use it in GitHub Desktop.
Xamarin.Forms DropboxService API v2
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Dropbox.Api;
using Dropbox.Api.Files;
using HLI.Forms.Services;
using Xamarin.Forms;
namespace MyApp
{
public class DropBoxService
{
#region Constants
private const string AppKeyDropboxtoken = "MyDropboxToken";
private const string ClientId = "MyDropboxClientId";
private const string RedirectUri = "https://www.anysite.se/";
#endregion
#region Fields
/// <summary>
/// Occurs when the user was authenticated
/// </summary>
public Action OnAuthenticated;
private string oauth2State;
#endregion
#region Properties
private string AccessToken { get; set; }
#endregion
#region Public Methods and Operators
/// <summary>
/// <para>Runs the Dropbox OAuth authorization process if not yet authenticated.</para>
/// <para>Upon completion <seealso cref="OnAuthenticated"/> is called</para>
/// </summary>
/// <returns>An asynchronous task.</returns>
public async Task Authorize()
{
if (string.IsNullOrWhiteSpace(this.AccessToken) == false)
{
// Already authorized
this.OnAuthenticated?.Invoke();
return;
}
if (this.GetAccessTokenFromSettings())
{
// Found token and set AccessToken
return;
}
// Run Dropbox authentication
this.oauth2State = Guid.NewGuid().ToString("N");
var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Token, ClientId, new Uri(RedirectUri), this.oauth2State);
var webView = new WebView { Source = new UrlWebViewSource { Url = authorizeUri.AbsoluteUri } };
webView.Navigating += this.WebViewOnNavigating;
var contentPage = new ContentPage { Content = webView };
await Application.Current.MainPage.Navigation.PushModalAsync(contentPage);
}
public async Task<IList<Metadata>> ListFiles()
{
try
{
using (var client = this.GetClient())
{
var list = await client.Files.ListFolderAsync(string.Empty);
return list?.Entries;
}
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
return null;
}
}
public async Task<byte[]> ReadFile(string file)
{
try
{
using (var client = this.GetClient())
{
var response = await client.Files.DownloadAsync(file);
var bytes = response?.GetContentAsByteArrayAsync();
return bytes?.Result;
}
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
return null;
}
}
public async Task<FileMetadata> WriteFile(byte[] fileContent, string filename)
{
try
{
var commitInfo = new CommitInfo(filename, WriteMode.Overwrite.Instance, false, DateTime.Now);
using (var client = this.GetClient())
{
var metadata = await client.Files.UploadAsync(commitInfo, new MemoryStream(fileContent));
return metadata;
}
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
return null;
}
}
#endregion
#region Methods
/// <summary>
/// Saves the Dropbox token to app settings
/// </summary>
/// <param name="token">Token received from Dropbox authentication</param>
private static async Task SaveDropboxToken(string token)
{
if (token == null)
{
return;
}
try
{
Application.Current.Properties.Add(AppKeyDropboxtoken, token);
await Application.Current.SavePropertiesAsync();
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
}
}
private DropboxClient GetClient()
{
return new DropboxClient(this.AccessToken);
}
/// <summary>
/// Tries to find the Dropbox token in application settings
/// </summary>
/// <returns>Token as string or <c>null</c></returns>
private bool GetAccessTokenFromSettings()
{
try
{
if (!Application.Current.Properties.ContainsKey(AppKeyDropboxtoken))
{
return false;
}
this.AccessToken = Application.Current.Properties[AppKeyDropboxtoken]?.ToString();
if (this.AccessToken != null)
{
this.OnAuthenticated.Invoke();
return true;
}
return false;
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
return false;
}
}
private async void WebViewOnNavigating(object sender, WebNavigatingEventArgs e)
{
if (!e.Url.StartsWith(RedirectUri, StringComparison.OrdinalIgnoreCase))
{
// we need to ignore all navigation that isn't to the redirect uri.
return;
}
try
{
var result = DropboxOAuth2Helper.ParseTokenFragment(new Uri(e.Url));
if (result.State != this.oauth2State)
{
return;
}
this.AccessToken = result.AccessToken;
await SaveDropboxToken(this.AccessToken);
this.OnAuthenticated?.Invoke();
}
catch (ArgumentException)
{
// There was an error in the URI passed to ParseTokenFragment
}
finally
{
e.Cancel = true;
await Application.Current.MainPage.Navigation.PopModalAsync();
}
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace HLI.Forms.ViewModels
{
/// <summary>
/// Implements DropBoxService
/// </summary>
public class DropBoxViewModel
{
#region Fields
private readonly DropBoxService dropBoxService = new DropBoxService();
#endregion
#region Constructors and Destructors
public DropBoxViewModel()
{
this.DropBoxGetCommand = new DelegateCommand(this.OnDropboxGet);
this.DropBoxSaveCommand = new DelegateCommand(this.OnDropboxSave);
}
#endregion
#region Public Properties
public ICommand DropBoxGetCommand { get; }
public ICommand DropBoxSaveCommand { get; }
public UriImageSource DropboxIcon
=>
new UriImageSource
{
Uri =
new Uri(
new OnPlatform<string>
{
WinPhone = "https://www.dropbox.com/s/affuim5lv2dqcq2/dropbox-windows-8.png?dl=1",
iOS = "https://www.dropbox.com/sh/zcxbhhco5x0bwmm/AAD6Nq7vmOBalRfOOe9oIa_va?dl=1",
Android = "https://www.dropbox.com/s/0l0fpn9yytzb1t7/dropbox-android.png?dl=1"
})
};
#endregion
#region Methods
private async void LoadDatabase()
{
try
{
// Read the database from DropBox folder
var db = await this.dropBoxService.ReadFile("DropBoxDatabasePath");
// Write the database to storage
await this.sqLite.WriteDatabase(db);
AppService.WriteDebug("Drobpox", "Loaded database OK!");
// Go back to origin
// await this.NavigationService.GoBackAsync();
}
catch (Exception ex)
{
}
}
private async void OnDropboxGet()
{
// If the user authenticates - loads database to Dropbox
this.dropBoxService.OnAuthenticated += this.LoadDatabase;
await this.dropBoxService.Authorize();
}
private async void OnDropboxSave()
{
// If the user authenticates - save database to Dropbox
this.dropBoxService.OnAuthenticated += this.SaveDatabase;
await this.dropBoxService.Authorize();
}
private async void SaveDatabase()
{
try
{
// Read the database from app storage
var db = this.sqLite.ReadDatabase();
// Write the database to DropBox folder
await this.dropBoxService.WriteFile(db, "DropBoxDatabasePath");
AppService.WriteDebug("Drobpox", "Saved database OK!");
}
catch (Exception ex)
{
AppService.WriteDebug(ex);
await this.MainPage.DisplayAlert("Dropbox", $"Something went wrong. If the problem persists, please contact us", "OK");
}
}
#endregion
}
}
@PatrickRyder
Copy link

I'm working through this and am extremely grateful but a bit more explanation on your tutorial on medium.com about things like client ID and the redirect URI to use would be extremely useful. I have no idea what either of these things is and Dropbox don't appear to provide much help. Back to Google, I guess...

@shantimohan
Copy link

Hi, Does this code cater to Scoped Develoopment app? I am little confused what to set to AppKeyDropboxtoken and ClientId as I don't see the exact names on creating app on Dropbox portal. Do they respectively mean 'OAuth2 Access Token' and 'App key'?

@thomashagstrom
Copy link
Author

thomashagstrom commented Aug 4, 2020

Hi, Does this code cater to Scoped Develoopment app? I am little confused what to set to AppKeyDropboxtoken and ClientId as I don't see the exact names on creating app on Dropbox portal. Do they respectively mean 'OAuth2 Access Token' and 'App key'?

Can't say it does. It's a 3 years old hack for a platform I don't use any more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment