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 également. Des idées? J'ai beaucoup cherché sur Google, mais je n'ai pas trouvé de bonne réponse par où commencer. Veuillez aider. Ce que j'ai essayé de créer un compte est comme 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);
Vous devez configurer plusieurs composants pour pouvoir créer un compte par programme. Vous avez besoin:
L'authentificateur est un objet qui fera le mappage entre le type de compte et l'autorité (c'est-à-dire l'utilisateur linux) qui a le droit de le gérer.
Déclarer un authentificateur se fait en xml:
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 accountType: il doit être réutilisé dans le code lorsque vous créez le compte. Les icônes et l'étiquette seront utilisées par l'application "Paramètres" pour afficher les comptes de ce type.
Implémentation de AccountAuthenticator
Vous devez étendre AbstractAccountAuthenticator
pour ce faire. Cela sera utilisé par une application tierce pour accéder aux données du compte.
L'exemple suivant ne permet aucun accès à une application tierce et l'implémentation de chaque méthode est donc 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.
}
}
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étadonnées faisant référence à la ressource xml déclarant l'authentificateur sont les points clés.
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 requis pour l'exemple de code présenté dans cet article, mais vous aurez probablement un peu plus de code sur la gestion des comptes et à la fin tous seront utiles)
Maintenant que tout est prêt, vous créez un compte avec le code suivant. Notez le boolean
renvoyé par addAccountExplicitly
vous informant 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");
}
N'installez pas votre application sur un stockage externe
Si votre application est installée sur un stockage externe, il y a de fortes chances que Android supprime les données de votre compte lorsque la carte SD n'est pas montée (car l'authentificateur de ce compte ne sera plus accessible). Donc, pour éviter cela perte (à chaque redémarrage !!!) vous devez installer l'application déclarant l'authentificateur uniquement sur le stockage interne:
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:installLocation="internalOnly"
...
En cas de problème
Lisez attentivement les journaux, le AccountManger génère de nombreux journaux pour vous aider à déboguer votre code.
J'ai écrit une bibliothèque pour cela, ce qui vous libère des tâches nécessaires à la gestion des comptes Android, tels que la définition d'un service lié, l'authentificateur xml, etc. Travailler avec cela se fait en 5 étapes simples:
Étape 1
Ajoutez ceci aux dépendances pour build.gradle de l'application:
compile 'com.digigene.Android:account-authenticator:1.3.0'
Étape 2
Définissez votre type de compte d'authentification sous forme de chaîne dans strings.xml
:
<string name="auth_account_type">DigiGene</string>
Remplacez ‘DigiGene’ par votre propre type de compte. C'est ce qui apparaît dans Android Comptes dans cette capture d'écran .
Étape 3
Concevez votre mise en page 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 créez une nouvelle classe, dites 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);
}
}
Étape 4
Faites une mise en page d'entrée comme dans 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 disposition 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);
}
}
Étape 5
Il s'agit de la dernière étape au cours de laquelle les méthodes nécessaires pour se connecter au serveur à des fins d'enregistrement et de connexion et après cela sont mises en œuvre. Dans ce qui suit, contrairement à un cas réel, les connexions au serveur sont simulées, juste pour démontrer la fonctionnalité de la bibliothèque. Vous pouvez remplacer l'implémentation suivante par la vôtre.
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 dont AccountManager
dans Android fonctionne dans ces trois articles de mon site Web: partie 1 , partie 2 , partie .
ici un extrait de code que je fais (désolé pour les commentaires allemands) n'oubliez pas de définir les autorisations propper dans le fichier manifeste.
/**
* 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.