在AccountManager

时间:2015-12-27 09:08:29

标签: xmpp openfire smack asmack accountmanager

我正在开发基于XMPP的Android聊天客户端。它适用于Socket连接,并且要保持连接有效,需要定期ping服务器。为此我使用后台运行android服务。

在此服务中创建连接实例。此服务永远存在于后台,并执行ping和接收消息的工作。

一个问题是当聊天客户端从任务管理器,后台服务RESTARTS中被杀死时(它仍然继续运行,因为我已将其声明为START-STICKY)。

服务重新启动后,清除连接实例。这会导致我的问题,因为连接实例被清除,相当于连接丢失。

所以如果on on onStartCommand of service,我正在重新建立连接。

但要建立连接,我需要用户名和密码。我想将这些凭据保存在Android的AccountManager中。 (我认为在AccountManager中存储密码比使用SharedPreferrence或SQLite或FileSystem更安全)

1。由于我没有存储任何身份验证令牌,在我的情况下使用AccountManager是正确的选择吗?它真的比其他存储更安全吗?

2。有没有办法以身份管理器中存储身份验证令牌的方式存储连接实例?

在我关于客户经理的阅读中,我已经实施了AuthenticationService,AccountAuthenticator和AccountAuthenticator Activity,如下所示 -

AuthenticatationService:

public class AuthenticatationService extends Service {

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return new AccountAuthenticator(this).getIBinder();
}
}

帐户身份验证员:

public class AccountAuthenticator extends AbstractAccountAuthenticator {
Context mContext;
public AccountAuthenticator(Context context) {
    super(context);
    mContext=context;
}

@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
    return null;
}

@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {

    Log.d("Mymsg", "AccountAuthenticator > addAccount() called with " + "response = [" + response + "], accountType = [" + accountType + "], authTokenType = [" + authTokenType + "], requiredFeatures = [" + requiredFeatures + "], options = [" + options + "]" + "---->START");

    final Intent intent = new Intent(mContext, LoginActivity.class);

    intent.putExtra(mContext.getString(R.string.intentdatakey_accounttype), accountType);
    intent.putExtra(mContext.getString(R.string.intentdatakey_authtype), authTokenType);
    intent.putExtra(mContext.getString(R.string.intentdatakey_isaddingnewaccount), true);

    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);

    Log.d("Mymsg", "AccountAuthenticator > addAccount() returned [bundle: " + bundle + "----> STOP");
    return bundle;
}

@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
    return null;
}

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {

    Log.d("Mymsg", "AccountAuthenticator > getAuthToken() called with " + "response = [" + response + "], account = [" + account + "], authTokenType = [" + authTokenType + "], options = [" + options + "]" + "---->START");
    // Extract the username and password from the Account Manager, and ask
    // the server for an appropriate AuthToken.
    final AccountManager am = AccountManager.get(mContext);

    String authToken = am.peekAuthToken(account, authTokenType);

    // Lets give another try to authenticate the user
    if (TextUtils.isEmpty(authToken)) {
        final String password = am.getPassword(account);
        if (password != null) {
            authToken = password;
        }
    }

    // If we get an authToken - we return it
    if (!TextUtils.isEmpty(authToken)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
        result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
        return result;
    }

    // If we get here, then we couldn't access the user's password - so we
    // need to re-prompt them for their credentials. We do that by creating
    // an intent to display our AuthenticatorActivity.
    final Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    intent.putExtra(mContext.getString(R.string.intentdatakey_accounttype), account.type);
    intent.putExtra(mContext.getString(R.string.intentdatakey_authtype), authTokenType);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);

    Log.d("Mymsg", "AccountAuthenticator > getAuthToken() returned [bundle: " + bundle + "----> STOP");
    return bundle;
}

@Override
public String getAuthTokenLabel(String authTokenType) {
    return null;
}

@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
    return null;
}

@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
    return null;
}
}

登录活动:

public class LoginActivity extends AccountAuthenticatorActivity implements View.OnClickListener {

private EditText txtUsername;
private Button btnLogin;
private String username;

private ProgressDialog progressDialog;

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

    txtUsername = (EditText) findViewById(R.id.txtUsername);

    btnLogin = (Button) findViewById(R.id.btnLogin);
    btnLogin.setOnClickListener(this);

    progressDialog = new ProgressDialog(this);

    // Connection and Login Response events
    LocalBroadcastManager.getInstance(this).registerReceiver(connectionSuccessfulReceiver,
            new IntentFilter(getString(R.string.broadcastmessage_connectionsuccessful)));
    LocalBroadcastManager.getInstance(this).registerReceiver(connectionFailureReceiver,
            new IntentFilter(getString(R.string.broadcastmessage_connectionfailure)));
}

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btnLogin:

            Log.d("Mymsg", "LoginActivity > onClick() called with " + "v = [" + v + "]" + "---->START");

            username = txtUsername.getText().toString();

            if (username.isEmpty()) {
                Toast.makeText(this, "Please enter username", Toast.LENGTH_LONG);
                return;
            }

            progressDialog.setMessage("Logging In...");
            progressDialog.setCancelable(false);
            progressDialog.show();

            final Intent res = new Intent();
            res.putExtra(AccountManager.KEY_ACCOUNT_NAME, username);
            res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, getString(R.string.accounttype));
            res.putExtra(AccountManager.KEY_AUTHTOKEN, username);
            res.putExtra(AccountManager.KEY_PASSWORD, username);

            final Account account = new Account(username, getString(R.string.accounttype));
            if (getIntent().getBooleanExtra(getString(R.string.intentdatakey_isaddingnewaccount), false)) {
                String authtoken = username;
                String authtokenType = getString(R.string.authtype);
                // Creating the account on the device and setting the auth token we got
                // (Not setting the auth token will cause another call to the server to authenticate the user)
                AccountManager.get(this).addAccountExplicitly(account, username, null);
                AccountManager.get(this).setAuthToken(account, authtokenType, authtoken);
            } else {
                AccountManager.get(this).setPassword(account, username);
            }
            setAccountAuthenticatorResult(res.getExtras());
            setResult(RESULT_OK, res);

            Log.d("Mymsg", "LoginActivity > onClick() ----> STOP");

            break;
        default:
            break;
    }
}

/**
 * On Connection Successful
 */
public void onConnectionSuccessful() {
    Log.d("Mymsg", "LoginActivity > onConnectionSuccessful() called with " + "" + "---->START");

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }
        }
    });

    finish();
    Log.d("Mymsg", "LoginActivity > onConnectionSuccessful() ----> STOP");
}

/**
 * On Connection Failure
 *
 * @param message- error message
 */
public void onConnectionFailure(final String message) {
    Log.d("Mymsg", "LoginActivity > onConnectionFailure() called with " + "message = [" + message + "]" + "---->START");
    runOnUiThread(new Runnable() {
        @Override
        public void run() {

            if (progressDialog.isShowing()) {
                progressDialog.dismiss();
            }

            Toast.makeText(LoginActivity.this, "Failed connecting: " + message, Toast.LENGTH_LONG).show();
        }
    });

    Log.d("Mymsg", "LoginActivity > onConnectionFailure() ----> STOP");
}


/*
* Recievers for Connection Events
 */
private BroadcastReceiver connectionSuccessfulReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("Mymsg", "LoginActivity > connectionSuccessfulReceiver > onReceive() called with " + "context = [" + context + "], intent = [" + intent + "]" + "---->START");
        onConnectionSuccessful();
        Log.d("Mymsg", "LoginActivity > connectionSuccessfulReceiver > onReceive() returned void ----> STOP");
    }
};

private BroadcastReceiver connectionFailureReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("Mymsg", "LoginActivity > connectionFailureReceiver > onReceive() called with " + "context = [" + context + "], intent = [" + intent + "]" + "---->START");
        onConnectionFailure(intent.getStringExtra(getString(R.string.intentdatakey_failuremessage)));
        Log.d("Mymsg", "LoginActivity > connectionFailureReceiver > onReceive() ----> STOP");
    }
};
}

关于我检查的每个活动的恢复,如果连接为空,如果是,我已经启动了后台服务(我之前提到过维护连接并定期ping)。如果AccountManager中存在Account并且提供回调服务,则此服务将建立连接。

第3。我面临的问题是AccountManager中尚未出现用户名和密码。根据我的理解,getAuthToken是Authenticator中的入口点,如果auth令牌不存在则调用登录活动。但是,如果不存在用户名,则如何调用getAuthToken。需要建议。

以下是我的后台服务 -

 public class XMPPListener extends Service implements ChatMessageListener, ChatManagerListener, ConnectionListener {

private static XMPPListener instance;
private NotificationCompat.Builder mBuilder;
private NotificationManager mNotificationManager;
private Context mContext;
private AbstractXMPPConnection connection;
private static boolean isConnected = false;
private static boolean isLoggedIn = false;
private User user;

public XMPPListener() {
    Log.d("Mymsg", "XMPPListener > XMPPListener() called with " + "" + "---->START");
    mContext = this;
    instance = this;
    Log.d("Mymsg", "XMPPListener > XMPPListener() > this: " + this);

    //To show notification when app is not foreground
    mBuilder = new NotificationCompat.Builder(mContext);

    Log.d("Mymsg", "XMPPListener > XMPPListener() ----> STOP");
}

/**
 * Get Singleton instance
 *
 * @return instance
 */
public static XMPPListener getInstance(Context context) {

    return instance;
}

@Override
public void processMessage(Chat chat, Message message) {
    Log.d("Mymsg", "XMPPListener > processMessage() called with " + "message = [" + message + "]" + "---->START");

    try {
        // Make entry of message in local database
        makeEntryOfMessageInLocalDatabase(chat, message);

        // Show Notification
        showNotification(chat, message);

        // Broadcast message that new message received
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(new Intent(getString(R.string.localbroadcastaction_messagereceived)));
    } catch (SQLException e) {
        e.printStackTrace();
    }

    Log.d("Mymsg", "XMPPListener > processMessage() returned void ----> STOP");
}

/**
 * Show Notification
 *
 * @param chat
 * @param message
 */
private void showNotification(Chat chat, Message message) {
    mBuilder.setSmallIcon(R.drawable.notification_icon);
    mBuilder.setContentTitle("@" + chat.getParticipant() + " messaged");
    mBuilder.setContentText(message.getBody());

    Intent resultIntent = new Intent(mContext, ChatWindowActivity.class);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
    stackBuilder.addParentStack(ChatWindowActivity.class);

    // Adds the Intent that starts the Activity to the top of the stack
    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(resultPendingIntent);

    // notificationID allows you to update the notification later on.
    mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(1, mBuilder.build());
}

/**
 * Make entry of message in Local Database
 *
 * @param chat
 * @param message
 * @throws SQLException
 */
private void makeEntryOfMessageInLocalDatabase(Chat chat, Message message) throws SQLException {

    Log.d("Mymsg", "XMPPListener > makeEntryOfMessageInLocalDatabase() called with " + "chat = [" + chat + "], message = [" + message + "]" + "---->START");

    ChatMessage chatMessage = new ChatMessage();

    // This is received message
    chatMessage.setSent(false);

    chatMessage.setThreadId(chat.getThreadID());
    chatMessage.setChatmessage(message.getBody());
    chatMessage.setTimeStamp(new Date());
    chatMessage.setIsRead(false);

    ChatThread chatThread = new ChatThread();
    chatThread.setThreadId(chat.getThreadID());
    chatThread.setUsername(chat.getParticipant());
    chatThread.setLastChatmessage(message.getBody());
    chatThread.setLastMessageTimeStamp(new Date());
    chatThread.setLastMessageSent(false);
    chatThread.setUnreadMessageCount(SampleChatClientAppDataOperations.getInstance(mContext).getUnReadMessageCountInThread(chat.getThreadID()));

    // Make database entry
    SampleChatClientAppData sampleChatClientAppData = new SampleChatClientAppData(mContext);

    // Update messages table
    sampleChatClientAppData.getChatMessageDao().create(chatMessage);

    // Update Chat list table
    sampleChatClientAppData.getChatThreadDao().update(chatThread);

    Log.d("Mymsg", "XMPPListener > makeEntryOfMessageInLocalDatabase() returned void ----> STOP");
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    Log.d("Mymsg", "XMPPListener > onCreate() called with " + "" + "---->START");
    super.onCreate();

    Log.d("Mymsg", "XMPPListener > onCreate() ----> STOP");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("Mymsg", "XMPPListener > onStartCommand() called with " + "intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]" + "---->START");

    if (connection == null || !connection.isConnected() || !connection.isAuthenticated()) {
        new GetAuthToken().execute();
    }

    int returnValue = super.onStartCommand(intent, flags, startId);
    Log.d("Mymsg", "XMPPListener > onStartCommand() returned [returnValue: " + returnValue + "----> STOP");
    return returnValue;
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    Log.d("Mymsg", "XMPPListener > onTaskRemoved() called with " + "rootIntent = [" + rootIntent + "]" + "---->START");
    super.onTaskRemoved(rootIntent);
    Log.d("Mymsg", "XMPPListener > onTaskRemoved() ----> STOP");
}

@Override
public void onDestroy() {
    Log.d("Mymsg", "XMPPListener > onDestroy() called with " + "" + "---->START");
    super.onDestroy();
    Log.d("Mymsg", "XMPPListener > onDestroy() ----> STOP");
}

/**
 * Getter for connection
 *
 * @return instance of connection
 */
public AbstractXMPPConnection getConnection() {
    return connection;
}

@Override
public void chatCreated(final Chat chat, boolean createdLocally) {

    Log.d("Mymsg", "XMPPListener > chatCreated() called with " + "chat = [" + chat + "], createdLocally = [" + createdLocally + "]" + "---->START");

    if (!createdLocally) {

        // Register listener
        chat.addMessageListener(XMPPListener.getInstance(this));


        checkIfChatThreadExistForUser(chat.getParticipant(), new Handler() {
            @Override
            public void handleMessage(android.os.Message msg) {
                Log.d("Mymsg", "XMPPListener > checkIfChatThreadExistForUser > handleMessage() called with " + "msg = [" + msg + "]" + "---->START");
                super.handleMessage(msg);
                ArrayList<ChatThread> chatThread;
                try {
                    chatThread = (ArrayList<ChatThread>) msg.obj;

                    Log.d("Mymsg", "chatThread: " + chatThread);

                    if (chatThread.isEmpty()) {
                        // If first time chatting with this user create new thread;
                        createChatThreadInLocalDb(chat);
                    }

                } catch (ClassCastException e) {
                    e.printStackTrace();
                }

                Log.d("Mymsg", "XMPPListener > checkIfChatThreadExistForUser > handleMessage() returned null----> STOP");
            }
        }, new Handler() {
            @Override
            public void handleMessage(android.os.Message msg) {
                super.handleMessage(msg);
            }
        });
    }


    Log.d("Mymsg", "XMPPListener > chatCreated() returned void----> STOP");
}

/**
 * Create chat thread in local db
 *
 * @param chat
 */
public void createChatThreadInLocalDb(Chat chat) {

    Log.d("Mymsg", "XMPPListener > createChatThreadInLocalDb() called with " + "chat = [" + chat + "]" + "---->START");

    ChatThread newChatThread = new ChatThread();
    newChatThread.setUsername(chat.getParticipant());
    newChatThread.setThreadId(chat.getThreadID());

    Datasource.addChatThread(this, newChatThread, new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {

            Log.d("Mymsg", "XMPPListener > addChatThread > createChatThreadInLocalDb > handleMessage() called with " + "msg = [" + msg + "]" + "---->START");
            super.handleMessage(msg);

            Integer newChatThreadCreated = 0;

            try {
                newChatThreadCreated = (Integer) msg.obj;

                if (newChatThreadCreated > 0) {

                    // Broadcast that chat is created
                    LocalBroadcastManager.getInstance(XMPPListener.this).sendBroadcast(new Intent(getString(R.string.localbroadcastaction_chatcreated)));
                }
            } catch (ClassCastException e) {
                e.printStackTrace();
            }

            Log.d("Mymsg", "XMPPListener > addChatThread > handleMessage() ----> STOP");
        }
    }, new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);
        }
    });

    Log.d("Mymsg", "XMPPListener > createChatThreadInLocalDb() returned null----> STOP");
}

/**
 * Checks if thread exist for the username else
 * create new one
 *
 * @param fullUsername
 */
public void checkIfChatThreadExistForUser(final String fullUsername, final Handler successHandler, final Handler failureHandler) {
    Datasource.getChatThreadOfUser(this, fullUsername, successHandler, failureHandler);
}

// Internal sync task for connecting to XMPP server
class ConnectXMPP extends AsyncTask<User, Void, Exception> {

    @Override
    protected Exception doInBackground(User... params) {

        Log.d("Mymsg", "ConnectXMPP > doInBackground() called with " + "params = [" + params + "]" + "---->START");

        User user = params[0];

        Log.d("Mymsg", "user: " + user);

        XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
                .setUsernameAndPassword(user.getUsername(), user.getPassword())
                .setServiceName(mContext.getString(R.string.openfire_host))
                .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
                .setDebuggerEnabled(true)
                .build();

        SASLAuthentication.blacklistSASLMechanism("SCRAM-SHA-1");
        SASLAuthentication.blacklistSASLMechanism("DIGEST-MD5");
        SASLAuthentication.unBlacklistSASLMechanism("PLAIN");

        connection = new XMPPTCPConnection(config);

        try {
            connection.connect();
            isConnected = connection.isConnected();
            Log.d("Mymsg", "isConnected: " + isConnected);

            connection.login();
            isLoggedIn = connection.isAuthenticated();
            Log.d("Mymsg", "isLoggedIn: " + isLoggedIn);

            connection.addConnectionListener(XMPPListener.this);

            // Broadcast message that new message received
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(new Intent(getString(R.string.broadcastmessage_connectionsuccessful)));

        } catch (SmackException e) {
            e.printStackTrace();
            Intent broadcastIntent = new Intent(getString(R.string.broadcastmessage_connectionfailure));
            broadcastIntent.putExtra(getString(R.string.intentdatakey_failuremessage), e.getMessage());
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(broadcastIntent);
        } catch (IOException e) {
            e.printStackTrace();
            Intent broadcastIntent = new Intent(getString(R.string.broadcastmessage_connectionfailure));
            broadcastIntent.putExtra(getString(R.string.intentdatakey_failuremessage), e.getMessage());
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(broadcastIntent);
        } catch (XMPPException e) {
            e.printStackTrace();
            Intent broadcastIntent = new Intent(getString(R.string.broadcastmessage_connectionfailure));
            broadcastIntent.putExtra(getString(R.string.intentdatakey_failuremessage), e.getMessage());
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(broadcastIntent);
        }

        return null;
    }

    @Override
    protected void onPostExecute(Exception e) {
        super.onPostExecute(e);
    }
}

class GetAuthToken extends AsyncTask<Void, Void, Exception> {

    private User user;

    @Override
    protected Exception doInBackground(Void... params) {

        String username = "";
        String password = "";

        AccountManager accountManager = AccountManager.get(XMPPListener.this);
        final Account[] accounts = accountManager.getAccountsByType(getString(R.string.accounttype));

        Account account;
        if (accounts.length <= 0) {
            account = new Account(username, getString(R.string.accounttype));

        } else {
            account = accounts[0];
        }

        try {
            Bundle bundle = accountManager.getAuthToken(account, mContext.getString(R.string.authtype), true, null, null).getResult();
            password = (String) bundle.get(AccountManager.KEY_AUTHTOKEN);
            Log.d("Mymsg", "password: " + password);
            username = password;
        } catch (OperationCanceledException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        }

        if (username.isEmpty() || password.isEmpty()) {
            Intent broadCastIntent = new Intent(getString(R.string.broadcastmessage_connectionfailure));
            broadCastIntent.putExtra(getString(R.string.intentdatakey_failuremessage), getString(R.string.errormessage_usercredentialmissing));
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(broadCastIntent);
            return null;
        }

        user = new User();
        user.setUsername(username);
        user.setPassword(password);

        return null;
    }

    @Override
    protected void onPostExecute(Exception e) {
        super.onPostExecute(e);

        if (user != null) {
            // Connect XMPP
            new ConnectXMPP().execute(user);
        }
    }
}
}

1 个答案:

答案 0 :(得分:1)

  

<强> 1。由于我没有存储任何身份验证令牌,在我的情况下使用AccountManager是正确的选择吗?它真的比其他存储更安全吗?

本身并不安全。客户经理只是在SQLite数据库中的“plaintext”中存储用户名,密码和authtokens。 因此,如果您具有root访问权限,则通常可以轻松访问这些值。

如果您打算使用同步适配器机制,或者打算同步到某些内容提供商(如联系人提供商或日历提供商),则需要使用身份验证器。

除此之外,它为多个帐户提供了轻松支持,并提供了一个干净的界面来检索身份验证凭据。后者很好地将帐户管理/身份验证部分与应用程序的其余部分分离。

回答第一个问题:这取决于。如果您不熟悉Authenticators,并且您只是寻求更好的安全性,那么在不使用Authenticator的情况下,您可能会感觉更好。

  

第3。我面临的问题是AccountManager中尚未出现用户名和密码。根据我的理解,getAuthToken是Authenticator中的入口点,如果auth令牌不存在则调用登录活动。但是,如果不存在用户名,则如何调用getAuthToken。需要建议。

这不是它的工作原理。您只能为现有帐户拨打getAuthTokengetAuthToken仅在验证者返回Intent时才调用活动。这样做的一个用例是使用OAuth2和用户撤销了应用的访问权限。在这种情况下,您需要提示用户再次授予访问权限。

请注意,其他应用程序也可能会请求auth-token(因为他们具有所需的权限),因此请确保不要将纯文本密码作为auth-token返回,或确保其他应用程序赢得'从验证者那里收到一个令牌。

因此,在调用Intent时从验证者返回getAuthToken的另一个用例是,如果要提示用户进行许可。

所以这就是它的完成方式:

您的应用应首先检查是否有现有帐户(使用getAccountsByType)。如果有,您可以拨打getAuthToken,如果有多个帐户,您通常会询问用户如果之前没有选择任何帐户,那么您为该帐户拨打getAuthToken,否则请致电addAccount让用户先添加帐户。

如果您不想授予其他应用访问您的纯文本密码的权限,请考虑使用setPasswordgetPassword而不是使用authtoken。密码是您的应用程序专用的密码,其他应用程序无法检索(嗯,至少更难)。或者考虑根本不使用Authenticator。在您的情况下,可能不值得增加复杂性。