简体   繁体   中英

Android Dropbox API not saving login

I'm sort of a beginner at Android programming. I've been trying to get Dropbox to integrate into [the beginnings of] an app I'm writing. I've followed the instructions and looked at the basic example DBRoulette that comes with the Dropbox API.

The problem I keep running into is that I log into Dropbox (through web browser) and then confirm that the app can use its Dropbox App folder... For that session it works fine, but then when I close the app fully and open it again, I get asked to log in again! I definitely don't want to have to retype all my dropbox login stuff again even if this is just for debugging purposes. The interesting thing is that DBRoulette works fine, I don't have to log in each time! And I copy pasted much of the functional code from that example.

While we're at it, what exactly do the AccessTokens contain/do? Do they store the information to create an authorized session? Is this information different from the App key/secret combo I get from the Dropbox developer site? I think this is where my error is but I am not sure.

Here is the activity:

package com.JS.music;


import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.session.AccessTokenPair;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.TokenPair;
import com.dropbox.client2.session.Session.AccessType;



public class MainActivity extends Activity {

private static String TAG = "MainActivity";

private Button gotoRecordingButton;
private Button libraryButton;

//Dropbox
final static private String APP_KEY = "xxxxxxxxxxxxx";
final static private String APP_SECRET = "xxxxxxxxxxxxxx"; 
final static private AccessType ACCESS_TYPE = AccessType.APP_FOLDER; 
private DropboxAPI<AndroidAuthSession> mDBApi; 
final static public String ACCOUNT_PREFS_NAME = "MusicDBPrefs";
final static public String ACCESS_KEY_NAME = "Music_DB_ACCESS_KEY";
final static public String ACCESS_SECRET_NAME = "Music_DB_ACCESS_SECRET";

private boolean mIsLoggedIn = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    gotoRecordingButton = (Button) findViewById(R.id.goto_recording_button);
    gotoRecordingButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(MainActivity.this, RecordActivity.class);
            startActivity(intent);
        }
    });

    libraryButton = (Button) findViewById(R.id.library_button);
    libraryButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

        }
    });

    AndroidAuthSession session = buildSession();
    mDBApi = new DropboxAPI<AndroidAuthSession>(session);
    mDBApi.getSession().startAuthentication(MainActivity.this);

    setLoggedIn(mDBApi.getSession().isLinked());

    Toast msg = Toast.makeText(this, "logged in: " + isLoggedIn(), Toast.LENGTH_LONG);
    msg.show();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


//-------------Dropbox stuff  for testing and debugging---------

@Override
protected void onResume() {
    super.onResume();
    AndroidAuthSession session = mDBApi.getSession();

    // The next part must be inserted in the onResume() method of the
    // activity from which session.startAuthentication() was called, so
    // that Dropbox authentication completes properly.
    if (session.authenticationSuccessful()) {
        try {
            // Mandatory call to complete the auth
            session.finishAuthentication();

            // Store it locally in our app for later use
            TokenPair tokens = session.getAccessTokenPair();
            storeKeys(tokens.key, tokens.secret);
            setLoggedIn(true);
        } catch (IllegalStateException e) {
            Log.i(TAG, "Error authenticating", e);
        }
    }
}


//copied from dropbox API
private void storeKeys(String key, String secret) {
    // Save the access key for later
    SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
    Editor edit = prefs.edit();
    edit.putString(ACCESS_KEY_NAME, key);
    edit.putString(ACCESS_SECRET_NAME, secret);
    edit.commit();
}


private String[] getKeys() {
    SharedPreferences prefs = getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
    String key = prefs.getString(ACCESS_KEY_NAME, null);
    String secret = prefs.getString(ACCESS_SECRET_NAME, null);
    if (key != null && secret != null) {
        Log.i(TAG,"Got keys");
        String[] ret = new String[2];
        ret[0] = key;
        ret[1] = secret;
        return ret;
    } else {
        return null;
    }
}

private AndroidAuthSession buildSession() {
    AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, APP_SECRET);
    AndroidAuthSession session;

    String[] stored = getKeys();
    if (stored != null) {
        AccessTokenPair accessToken = new AccessTokenPair(stored[0], stored[1]);
        session = new AndroidAuthSession(appKeyPair, ACCESS_TYPE, accessToken);
    } else {
        session = new AndroidAuthSession(appKeyPair, ACCESS_TYPE);
    }

    return session;
}

public void setLoggedIn(boolean loggedIn) {
    mIsLoggedIn = loggedIn;
}

public boolean isLoggedIn() {
    return mIsLoggedIn;
}
}

Any help appreciated!

The main idea when you use DropboxApi is: in the 1st time when you connected you must get secret keys, next time you must use these keys for access without confirming via browser.

ie in onResume method you should use this line

AccessTokenPair tokens = mDBApi.getSession().getAccessTokenPair();

where DropboxAPI mDBApi;

Then you need to save data of

AccessTokenPair tokens 

in sqlite or SharedPrefs.

Then you should use method like this:

private DropboxAPI <AndroidAuthSession> getDropboxAPI(){
    AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
    AndroidAuthSession session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
    mDBApi = new DropboxAPI<AndroidAuthSession>(session);
    AccessKeys keys = dm.getAccessKeys(APP_KEY); //dm is DatabaseManager of ORMLite
    if (keys == null) return null;
    AccessTokenPair access = new AccessTokenPair(keys.getAccessKey(), keys.getAccessSecret());
    mDBApi.getSession().setAccessTokenPair(access);
    return mDBApi;
}

...

AccessKeys is class where I stored keys via ORMLite:

@DatabaseTable
public class AccessKeys {
... 
    @DatabaseField private String accessKey;
    @DatabaseField private String accessSecret;
    @DatabaseField private String appKey;
    @DatabaseField private String appSecret;
...}

And last one thing: when you got all keys you should not run

mDBApi.getSession().startAuthentication(MainActivity.this);

just use mDBApi for your goals, like "mDBApi.putFile(some data)"

Note: You only need to do startAuthentication() once, You don't need to run it to authorize the key pair from the actual login.

I know it's an old question, but answering it just in case someone else stumbles upon it.

As for the main described problem - that you have to login into Dropbox again each time, that's simply because you have this line near the end of onCreate()

mDBApi.getSession().startAuthentication(MainActivity.this);

startAuthentication() always starts a new "login" flow, no matter if you already have a valid session or not. For this reason you should NOT call it every time.

The accepted answer is good, but you can get away with using less code, by saving the accessToken. So first, in onResume() after finishAuthentication() you'd save the accessToken like this

String accessToken = mDBApi.getSession().getOAuth2AccessToken();
// save accessToken to SQLite or SharedPrefs or whatever

Then the getDropboxAPI() method suggested by @Alexandr should look like this

private DropboxAPI <AndroidAuthSession> getDropboxAPI() {
    AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
    AndroidAuthSession session = new AndroidAuthSession(appKeys, ACCESS_TYPE);
    mDBApi = new DropboxAPI<AndroidAuthSession>(session);

    String savedAccessToken = // get previously saved accessToken

    if (!TextUtils.isEmpty(savedAccessToken)) {
        mDBApi.getSession().setOAuth2AccessToken(savedAccessToken);
    }

    return mDBApi;
}

It's also a good idea to create a helper method like this to check if Dropbox is properly initialised before using it for real work, like uploading or downloading files.

public boolean isDropboxLinked() {
    return mDBApi != null && (mDBApi.getSession().isLinked() || mDBApi.getSession().authenticationSuccessful());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM