Nikhil
Nikhil

Reputation: 379

Implementing Dropbox API V2 in Cordova Application

I have a Cordova application with previous Dropbox implementation using rossmartin/phonegap-dropbox-sync-android. Now as the API V1 is going to be deprecated I want to upgrade to Dropbox API V2. I have searched for plugins for Cordova applications using Dropbox API V2 but didn't find any.So I am trying to implement it using dropbox/dropbox-sdk-js.

For Authentication, I am using authenticateWithCordova method which returns me the Access token (Full documentation here).This method returns Access token once the user completes authentication with Dropbox and uses the redirect URL to redirect the user to Cordova application.

This method works perfectly when the user clicks the button for the first time, but when the user clicks the button again calling this method shows a blank screen and return a new access token. How to avoid seeing the blank screen?

This is the method from Dropbox-sdk.js file, which I have called from my application,

 DropboxBase.prototype.authenticateWithCordova = function (successCallback, errorCallback)
    {
      var redirect_url = 'https://www.dropbox.com/1/oauth2/redirect_receiver';
      var url = this.getAuthenticationUrl(redirect_url);
      var browser = window.open(url, '_blank');
      var removed = false;

      var onLoadError = function(event) {
        // Try to avoid a browser crash on browser.close().
        window.setTimeout(function() { browser.close() }, 10);
        errorCallback();
      }

      var onLoadStop = function(event) {
        var error_label = '&error=';
        var error_index = event.url.indexOf(error_label);

        if (error_index > -1) {
          // Try to avoid a browser crash on browser.close().
          window.setTimeout(function() { browser.close() }, 10);
          errorCallback();
        } else { 
          var access_token_label = '#access_token=';
          var access_token_index = event.url.indexOf(access_token_label);
          var token_type_index = event.url.indexOf('&token_type=');
          if (access_token_index > -1) {
            access_token_index += access_token_label.length;
            // Try to avoid a browser crash on browser.close().
            window.setTimeout(function() { browser.close() }, 10);

            var access_token = event.url.substring(access_token_index, token_type_index);
            successCallback(access_token);
          }
        }
      };

Here is my code which I use to call the method,

function authenticateWithCordova()
{
    var dbx = new Dropbox({ clientId: CLIENT_ID });
    dbx.authenticateWithCordova(AuthSuccess,AuthFail);

}

function AuthSuccess(accessToken)
{   
    localStorage.accessToken = accessToken;
}

function AuthFail()
{
alert("Auth Fail"); 
}

Upvotes: 2

Views: 712

Answers (1)

Marco
Marco

Reputation: 86

I have found an analog issue right yesterday. This is the way I solved it. First, I have set var dbx as global. In my index.js I put these lines immediately after app.initialize():

var CLIENT_ID = 'xxxxxxxxxxxxxxx';
var dbxt;
var dbx = new Dropbox({clientId: CLIENT_ID});

Then I check if dbxt is null: if it is, I create a new Dropbox object using accessToken, otherwise I go with the dropbox connection already established:

if (dbxt == null) {
    dbx.authenticateWithCordova(function (accessToken) {
        dbxt = new Dropbox({accessToken: accessToken});
        dbxt.filesUpload({
            path: '/mydump.sql',
            contents: sql,
            mode: 'overwrite',
            mute: true
        }).then(function (response) {
            alert('Your backup has been successfully uploaded to your Dropbox!')
        }).catch(function (error) {
            alert('Error saving file to your Dropbox!')
            console.error(error);
        });
    }, function (e){
        console.log("failed Dropbox authentication");
    }
}else{//dbxt already created
    dbxt.filesUpload... //and the rest
}

This is just to avoid to create a new connection and get a new access token everytime and I confess I'm not sure this is a good practice: I only know that before to apply this code I got a lot of bad requests responses by Dropbox server:)

When I used the above code, after the first login, I started to see the blank page: that's is the inappbrowser page which Dropbox OAuth2 uses as redirect URI (set to https://www.dropbox.com/1/oauth2/redirect_receiver in your Dropbox app page).

So the problem was how to make this page invisible. I found a dirty trick applying a small tweak to inappbrowser.js script. Near the bottom of the script, immediately before this line:

strWindowFeatures = strWindowFeatures || "";

I have put this small block:

if (strUrl.indexOf('dropbox') > -1){
    strWindowFeatures += "location=no,hidden=yes";
}

I would have expected to can just use 'hidden=yes' but surprisingly if I remoce 'location=no' the blkank page appears again.

Notice 1: you don't have to modify the script inappbrowser.js located at plugins\cordova-plugin-inappbrowser\www\ but the one you find in platforms\android\platform_www\plugins\cordova-plugin-inappbrowser\www\

Notice 2: I have found this workaround right now so I'm not 100% sure it works perfectly.

Notice 3: making the inappbrowser page invisible, depending on the Internet connection, it could look like nothing is happening for a while, so you'll have to add some loader to inform your user that the app is working.

Hope this help.

UPDATE I've just realized we can tweak directly the dropbox-sdk instead of inappbrowser.

If you are using Dropbox with browserify you have to open dropbox-base.js and look for authenticateWithCordova() method (it should be at line 107. Then change the line

var browser = window.open(url, '_blank');

to

var browser = window.open(url, '_blank', "location=no,hidden=yes");

If you are using Dropbox-sdk.min.js, you have to look for 'window.open' using the search function of your code editor. It will be easy because 'window.open' is used only once. So you'll have to change the following:

i=window.open(n,"_blank"),

to

i=window.open(n,"_blank","location=no,hidden=yes"),

And this seems to work fine (I prefer to be careful before I get excited).

UPDATE 2 Forgive previous update. My previous check:

if (strUrl.indexOf('dropbox') > -1){
    strWindowFeatures += "location=no,hidden=yes";
}

is wrong because it makes invisible any inappbrowser window which tries to connect to dropbox so it prevent us from even logging into Dropbox. So we need to change it to

if (strUrl == 'https://www.dropbox.com/1/oauth2/redirect_receiver') {
    strWindowFeatures += "location=no,hidden=yes";
}

This way we can do the login correctly and next connections won't show the inappbrowser window, as we want.

So summarizing:

  1. Ignore my first update
  2. Use UPDATE 2 to modify the url check in inappbrowser.js

Forgive me for the confusion...

Upvotes: 1

Related Questions