3

我是 Android 编程的初学者。我一直在尝试让 Dropbox 集成到我正在编写的应用程序的 [开端] 中。我按照说明查看了 Dropbox API 附带的基本示例 DBRoulette。

我一直遇到的问题是我登录到 Dropbox(通过网络浏览器),然后确认该应用程序可以使用其 Dropbox 应用程序文件夹......对于那个会话它工作正常,但是当我完全关闭应用程序并打开它时再次,我被要求再次登录!我绝对不想再次重新输入我所有的保管箱登录内容,即使这只是为了调试目的。有趣的是,DBRoulette 运行良好,我不必每次都登录!我复制粘贴了该示例中的大部分功能代码。

当我们这样做时,AccessTokens 究竟包含/做什么?他们是否存储信息以创建授权会话?此信息与我从 Dropbox 开发者网站获得的应用程序密钥/秘密组合不同吗?我认为这是我的错误所在,但我不确定。

这是活动:

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;
}
}

任何帮助表示赞赏!

4

2 回答 2

5

使用 DropboxApi 的主要思想是:第一次连接时必须获取密钥,下次必须使用这些密钥进行访问,无需通过浏览器确认。

即在 onResume 方法中你应该使用这一行

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

其中 DropboxAPI mDBApi;

然后你需要保存数据

AccessTokenPair tokens 

在 sqlite 或 SharedPrefs 中。

然后你应该使用这样的方法:

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 是我通过 ORMLite 存储密钥的类:

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

最后一件事:当你拿到所有钥匙时,你不应该跑

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

只需将 mDBApi 用于您的目标,例如“mDBApi.putFile(some data)”

注意:您只需要执行一次 startAuthentication(),您不需要运行它来从实际登录中授权密钥对。

于 2013-09-30T00:25:41.843 回答
4

我知道这是一个老问题,但要回答它以防万一其他人偶然发现它。

至于主要描述的问题-您每次都必须再次登录 Dropbox,这仅仅是因为您在 onCreate() 末尾附近有这条线

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

startAuthentication() 总是启动一个新的“登录”流程,不管你是否已经有一个有效的会话。因此,您不应该每次都调用它。

接受的答案很好,但您可以通过保存 accessToken 来使用更少的代码。所以首先,在 finishAuthentication() 之后的 onResume() 中,您将像这样保存 accessToken

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

那么@Alexandr 建议的 getDropboxAPI() 方法应该是这样的

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;
}

在将 Dropbox 用于实际工作(如上传或下载文件)之前,创建这样的辅助方法来检查 Dropbox 是否已正确初始化也是一个好主意。

public boolean isDropboxLinked() {
    return mDBApi != null && (mDBApi.getSession().isLinked() || mDBApi.getSession().authenticationSuccessful());
}
于 2015-01-29T22:46:14.597 回答