Comment ajouter programmatically un compte personnalisé dans android?

j'essaie de créer un compte pour mon application, où je pourrai avoir mes contacts contre mon compte comme facebook, viber, whatsapp etc. Je veux que mon compte soit visible dans la section compte des paramètres aussi. Des idées? J'ai beaucoup cherché sur Google, mais je n'ai pas trouvé la bonne réponse par où commencer. S'il vous plaît aider. Ce que j'ai essayé de créer un compte ci-dessous. Ce qui m'amène à une erreur.

Account account = new Account("Title", "com.package.nom");
               String password = "password";

               AccountManager accountManager =
                       (AccountManager) MainPanel.this.getSystemService(
                               ACCOUNT_SERVICE);
               accountManager.addAccountExplicitly(account, password, null);
27
demandé sur ben75 2014-06-15 10:56:39

3 réponses

vous devez configurer plusieurs composants pour pouvoir créer un compte de façon programmatique. Vous avez besoin de:

  • un account Authenticator
  • un Service pour fournir l'accès au account Authenticator
  • certaines autorisations

L'authentificateur

l'authentificateur est un objet qui va faire la correspondance entre le type de Compte et l'autorité (c'est-à-dire l'utilisateur linux) qui a le droit de gérer il.

déclaration d'un authentificateur est fait en xml:

  • créer un fichier res/xml/authenticator.xml

avec le contenu suivant :

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
                   android:accountType="com.company.demo.account.DEMOACCOUNT"
                   android:icon="@drawable/ic_launcher"
                   android:smallIcon="@drawable/ic_launcher"
                   android:label="@string/my_custom_account"/>

Notez le type de compte: il doit être réutilisé en code lorsque vous créez le compte. Les icônes et le label seront utilisés par L'Application "Settings" pour afficher les comptes de ce type.

implémentation du Accountenauthenticator

Vous devez s'étend AbstractAccountAuthenticator pour le faire. Cette application sera utilisée par une tierce partie pour accéder aux données du compte.

l'échantillon suivant ne permet aucun accès à l'application tierce partie et donc la mise en œuvre de chaque méthode est triviale.

public class CustomAuthenticator extends AbstractAccountAuthenticator {

    public CustomAuthenticator(Context context) {
        super(context);
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse, String s, String s2, String[] strings, Bundle bundle) throws NetworkErrorException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse, String s) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, Bundle bundle) throws NetworkErrorException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public String getAuthTokenLabel(String s) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String[] strings) throws NetworkErrorException {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }
}

Le Service d'exposer le Type de Compte

créer un Service pour manipuler les comptes de ce type:

public class AuthenticatorService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        CustomAuthenticator authenticator = new CustomAuthenticator(this);
        return authenticator.getIBinder();
    }
}

déclarez le service dans votre manifeste :

<service android:name="com.company.demo.account.AuthenticatorService" android:exported="false">
        <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator"/>
        </intent-filter>
        <meta-data
            android:name="android.accounts.AccountAuthenticator"
            android:resource="@xml/authenticator"/>
    </service>

Ici, le filtre et les méta-données relatives à la ressource xml déclarant l'authentificateur sont les points clés.

Les autorisations

Dans votre manifeste, assurez-vous de déclarer les autorisations suivantes

<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>

(pas tous nécessaires pour l'exemple de code présenté dans ce post, mais vous aurez probablement avoir un peu plus de code sur la gestion du compte et à la fin, ils seront tous utiles)

Créer un compte dans le code

Maintenant que tout est prêt, vous créer un compte avec le code suivant. Remarque boolean retournée par addAccountExplicitly vous informer du succès ou de l'échec.

    AccountManager accountManager = AccountManager.get(this); //this is Activity
    Account account = new Account("MyAccount","com.company.demo.account.DEMOACCOUNT");
    boolean success = accountManager.addAccountExplicitly(account,"password",null);
    if(success){
        Log.d(TAG,"Account created");
    }else{
        Log.d(TAG,"Account creation failed. Look at previous logs to investigate");
    }

derniers conseils

Ne pas installer votre application sur un stockage externe

si votre application est installée sur un stockage externe, il y a de bonnes chances que Android supprime vos données de compte lorsque sdcard est non monté (depuis l'authentificateur pour ce compte ne plus être accessible). Donc, pour éviter cette perte (à chaque redémarrage !!!), vous devez installer l'Application déclarant l'authentificateur sur le stockage interne seulement :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      android:installLocation="internalOnly"
      ...

En cas de problème

lisez attentivement les logs, le comptable débite de nombreux logs pour vous aider à déboguer votre code.

79
répondu ben75 2014-07-03 11:09:58

voici un code coupé je le fais (désolé pour les commetns allemands ) n'oubliez pas de définir les permissions propper dans le fichier manifest.

/**
 * ueberprueft, ob es den account fuer diese app schon gibt und legt ihn
 * gegebenenfalls an.
 * 
 * @param none
 * @return void
 */
public void verifyAccount() {
    if (debug)
        Log.i(TAG, "verifyAccount() ");

    boolean bereitsAngelegt = false;
    String accountType;
    accountType = this.getPackageName();

    AccountManager accountManager = AccountManager
            .get(getApplicationContext());
    Account[] accounts = accountManager.getAccounts();
    for (int i = 0; i < accounts.length; i++) {
        if (debug)
            Log.v(TAG, accounts[i].toString());
        if ((accounts[i].type != null)
                && (accounts[i].type.contentEquals(accountType))) {
            bereitsAngelegt = true;
            if (debug)
                Log.v(TAG, "verifyAccount(): bereitsAngelegt "
                        + accounts[i].type);
        }
    }

    if (!bereitsAngelegt) {
        if (debug)
            Log.v(TAG, "verifyAccount(): !bereitsAngelegt ");

        // This is the magic that addes the account to the Android Account
        // Manager

        AccountManager accMgr = AccountManager.get(this);

        String password = "some_password";

        if (debug)
            Log.d(TAG, "verifyAccount(): ADD: accountName: "
                    + Konst.accountName + " accountType: " + accountType
                    + " password: " + password);

        final Account account = new Account(Konst.accountName, accountType);
        if (debug)
            Log.v(TAG, "verifyAccount(): nach final Account account ");
        try {
            accMgr.addAccountExplicitly(account, password, null);
        } catch (Exception e1) {
            if (debug)
                Log.v(TAG, "verifyAccount(): Exception e1 " + e1.toString());
            this.finish();
        }
        if (debug)
            Log.v(TAG,
                    "verifyAccount(): nach accMgr.addAccountExplicitly() ");
    } else {
        if (debug)
            Log.v(TAG, "verifyAccount(): bereitsAngelegt ");
    }
} // end of public void verifyAccount()

j'espère que cela aide un peu.

3
répondu 2014-06-15 08:38:55

j'ai écrit un bibliothèque pour cela, ce qui vous permet de ne pas effectuer les tâches nécessaires à la gestion des comptes android, telles que la définition d'un service lié, authentificateur xml, etc. Qui est en 5 étapes simples:

Etape 1

ajouter ceci aux dépendances pour construire.gradle de l'application:

compile 'com.digigene.android:account-authenticator:1.3.0'

Etape 2

Définissez votre type de Compte d'authentification comme une chaîne de caractères dans strings.xml:

<string name="auth_account_type">DigiGene</string>

remplacer "DigiGene" par votre propre type de Compte. C'est ce qui apparaît dans les comptes Android dans cette capture d'écran.

Etape 3

Concevez votre schéma d'enregistrement pour enregistrer les utilisateurs (par exemple cette image):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.digigene.authenticatortest.MainActivity">

    <EditText
        android:id="@+id/account_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:hint="User Name"
        />

    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/account_name"
        android:gravity="center_horizontal"
        android:hint="Password"
        android:inputType="textPassword"
        />

    <Button
        android:id="@+id/register"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/password"
        android:text="register"
        android:onClick="startAuthentication"/>

</RelativeLayout>

et une nouvelle classe, dire MyRegistrationActivity.java avec le code suivant:

import com.digigene.accountauthenticator.activity.RegistrationActivity;

public class MyRegistrationActivity extends RegistrationActivity {
    private EditText accountNameEditText, passwordEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.registration_layout);
        accountNameEditText = (EditText) findViewById(R.id.account_name);
        passwordEditText = (EditText) findViewById(R.id.password);
    }

    public void startAuthentication(View view) {
        register(accountNameEditText.getText().toString(), passwordEditText.getText().toString(),
                null, null);
    }
}

Etape 4

Faire un grille de saisie comme suit:ici:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.digigene.authenticatortest.MainActivity">

    <EditText
        android:id="@+id/account_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:hint="User Name"
        />

    <Button
        android:id="@+id/register"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/account_name"
        android:text="Sign in"
        android:onClick="signIn"/>

    <Button
        android:id="@+id/add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/register"
        android:text="Add user"
        android:onClick="addUser"/>

</RelativeLayout>

cette mise en page va avec la classe suivante:

import com.digigene.accountauthenticator.AuthenticatorManager;

public class MainActivity extends Activity {
    EditText accountNameEditText;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        accountNameEditText = (EditText) findViewById(R.id.account_name);
    }

    public void signIn(View view) {
        AuthenticatorManager authenticatorManager = new AuthenticatorManager(MainActivity.this,
                getString(R.string.auth_account_type), this, MyRegistrationActivity.class,
                MyInterfaceImplementation.class);
        String authTokenType = "REGULAR_USER";
        AuthenticatorManager.authenticatorManager = authenticatorManager;
        authenticatorManager.getAccessToken(accountNameEditText.getText().toString(),
                authTokenType, null);
    }

    public void addUser(View view) {
        AuthenticatorManager authenticatorManager = new AuthenticatorManager(MainActivity.this,
                getString(R.string.auth_account_type), this, MyRegistrationActivity.class,
                MyInterfaceImplementation.class);
        String authTokenType = "REGULAR_USER";
        AuthenticatorManager.authenticatorManager = authenticatorManager;
        authenticatorManager.addAccount(authTokenType, null, null);
    }
}

Etape 5

il s'agit de la dernière étape au cours de laquelle les méthodes nécessaires pour se connecter au serveur aux fins d'inscription et de connexion et après celle-ci sont mises en œuvre. Dans ce qui suit, contrairement à un cas réel, les connexions de serveur sont moquées, juste pour démontrer la fonctionnalité de la bibliothèque. Vous pouvez remplacer les suivantes implémentation avec votre propre vrai.

import com.digigene.accountauthenticator.AbstractInterfaceImplementation;
import com.digigene.accountauthenticator.AuthenticatorManager;
import com.digigene.accountauthenticator.result.RegisterResult;
import com.digigene.accountauthenticator.result.SignInResult;
import com.digigene.accountauthenticator.result.SignUpResult;

public class MyInterfaceImplementation extends AbstractInterfaceImplementation {
    public static int accessTokenCounter = 0;
    public static int refreshTokenCounter = 0;
    public static int demoCounter = 0;
    public static int accessTokenNo = 0;
    public static int refreshTokenNo = 0;
    public final int ACCESS_TOKEN_EXPIRATION_COUNTER = 2;
    public final int REFRESH_TOKEN_EXPIRATION_COUNTER = 5;
    public final int DEMO_COUNTER = 15;

    @Override
    public String[] userAccessTypes() {
        return new String[]{"REGULAR_USER", "SUPER_USER"};
    }

    @Override
    public void doAfterSignUpIsUnsuccessful(Context context, Account account, String
            authTokenType, SignUpResult signUpResult, Bundle options) {
        Toast.makeText(context, "Sign-up was not possible due to the following:\n" + signUpResult
                .errMessage, Toast.LENGTH_LONG).show();
        AuthenticatorManager.authenticatorManager.addAccount(authTokenType, null, options);
    }

    @Override
    public void doAfterSignInIsSuccessful(Context context, Account account, String authTokenType,
                                          String authToken, SignInResult signInResult, Bundle
                                                  options) {
        demoCounter = demoCounter + 1;
        Toast.makeText(context, "User is successfully signed in: \naccessTokenNo=" +
                accessTokenNo + "\nrefreshTokenNo=" + refreshTokenNo +
                "\ndemoCounter=" + demoCounter, Toast.LENGTH_SHORT).show();
    }

    @Override
    public SignInResult signInToServer(Context context, Account account, String authTokenType,
                                       String accessToken, Bundle options) {
        accessTokenCounter = accessTokenCounter + 1;
        SignInResult signInResult = new SignInResult();
        signInResult.isSuccessful = true;
        synchronized (this) {
            try {
                this.wait(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if ((accessTokenCounter > ACCESS_TOKEN_EXPIRATION_COUNTER || demoCounter > DEMO_COUNTER)) {
            signInResult.isSuccessful = false;
            signInResult.isAccessTokenExpired = true;
            if (demoCounter < DEMO_COUNTER) {
                signInResult.errMessage = "Access token is expired";
                return signInResult;
            }
        }
        return signInResult;
    }

    @Override
    public SignUpResult signUpToServer(Context context, Account account, String authTokenType,
                                       String refreshToken, Bundle options) {
        SignUpResult signUpResult = new SignUpResult();
        synchronized (this) {
            try {
                this.wait(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        refreshTokenCounter = refreshTokenCounter + 1;
        signUpResult.isSuccessful = true;
        signUpResult.accessToken = "ACCESS_TOKEN_NO_" + accessTokenNo;
        signUpResult.refreshToken = "REFRESH_TOKEN_NO_" + refreshTokenNo;
        if (demoCounter > DEMO_COUNTER) {
            signUpResult.isSuccessful = false;
            signUpResult.errMessage = "You have reached your limit of using the demo version. " +
                    "Please buy it for further usage";
            return signUpResult;
        }
        if (refreshTokenCounter > REFRESH_TOKEN_EXPIRATION_COUNTER) {
            refreshTokenCounter = 0;
            signUpResult.isSuccessful = false;
            signUpResult.errMessage = "User credentials have expired, please login again";
            return signUpResult;
        }
        if (accessTokenCounter > ACCESS_TOKEN_EXPIRATION_COUNTER) {
            accessTokenCounter = 0;
            accessTokenNo = accessTokenNo + 1;
            signUpResult.accessToken = "ACCESS_TOKEN_NO_" + accessTokenNo;
        }
        return signUpResult;
    }

    @Override
    public RegisterResult registerInServer(Context context, Account account, String password,
                                           String authTokenType, String[] requiredFeatures,
                                           Bundle options) {
        RegisterResult registerResult = new RegisterResult();
        registerResult.isSuccessful = false;
        synchronized (this) {
            try {
                this.wait(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (true) {  // password is checked here and, if true, refresh token is generated for the
            // user
            refreshTokenNo = refreshTokenNo + 1;
            accessTokenNo = accessTokenNo + 1;
            registerResult.isSuccessful = true;
            registerResult.refreshToken = "REFRESH_TOKEN_NO_" + refreshTokenNo;
        }
        return registerResult;
    }

    @Override
    public boolean setDoesCallbackRunInBackgroundThread() {
        return false;
    }
}

Résultats

ce qui suit montre la bibliothèque en action. Vous pouvez trouver le tutoriel complet ici et sur la façon AccountManager dans android fonctionne dans ces trois messages de mon site web:partie 1,partie 2,partie 3.

A sample app using the library

3
répondu Ali Nem 2016-09-25 11:42:10