use*_*503 28 java account android synchronization
我正在尝试为我的应用创建一个帐户,在那里我可以将我的联系人设置为我的帐户,例如facebook,viber,WhatsApp等.我希望我的帐户也可以在设置的帐户部分中显示.有任何想法吗?我搜索了很多,但找不到正确的答案从哪里开始.请帮忙.我试图创建一个帐户的内容如下.这导致我出错.
Account account = new Account("Title", "com.package.nom");
String password = "password";
AccountManager accountManager =
(AccountManager) MainPanel.this.getSystemService(
ACCOUNT_SERVICE);
accountManager.addAccountExplicitly(account, password, null);
Run Code Online (Sandbox Code Playgroud)
ben*_*n75 90
您需要设置多个组件才能以编程方式创建帐户.你需要:
验证器是一个对象,它将在帐户类型和具有管理权限的autority(即linux用户)之间进行映射.
声明身份验证器是在xml中完成的:
res/xml/authenticator.xml 具有以下内容:
<?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"/>
Run Code Online (Sandbox Code Playgroud)
请注意accountType:创建帐户时必须在代码中重复使用它."设置"应用程序将使用图标和标签显示该类型的帐户.
实施AccountAuthenticator
你必须延伸AbstractAccountAuthenticator这样做.这将由第三方应用程序用于访问帐户数据.
以下示例不允许任何对第三方应用程序的访问,因此每种方法的实现都是微不足道的.
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.
}
}
Run Code Online (Sandbox Code Playgroud)
创建服务以操作该类型的帐户:
public class AuthenticatorService extends Service {
@Override
public IBinder onBind(Intent intent) {
CustomAuthenticator authenticator = new CustomAuthenticator(this);
return authenticator.getIBinder();
}
}
Run Code Online (Sandbox Code Playgroud)
在清单中声明服务:
<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>
Run Code Online (Sandbox Code Playgroud)
这里,过滤器和指向认证者的xml资源的元数据是关键点.
在您的清单中,请务必声明以下权限
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
Run Code Online (Sandbox Code Playgroud)
(并非所有本文中提供的示例代码都需要,但您可能会有更多关于帐户管理的代码,最后所有代码都会有用)
现在一切准备就绪,您可以使用以下代码创建一个帐户.请注意boolean返回时addAccountExplicitly通知您成功或失败.
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");
}
Run Code Online (Sandbox Code Playgroud)
不要在外部存储上安装您的应用程序
如果您的应用程序安装在外部存储设备上,则卸载SD卡时Android很可能会删除您的帐户数据(因为该帐户的身份验证器将不再可访问).因此,为了避免这种损失(每次重启!!!),您必须安装仅在内部存储上声明身份验证器的应用程序:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
...
Run Code Online (Sandbox Code Playgroud)
遇到麻烦
仔细阅读日志,AccountManger输出许多日志以帮助您调试代码.
我为此编写了一个库,它可以让您免于执行管理 android 帐户所需的琐事,例如定义绑定服务、身份验证器 xml 等。 使用它只需 5 个简单步骤:
第1步
将此添加到应用程序的 build.gradle 的依赖项中:
compile 'com.digigene.android:account-authenticator:1.3.0'
Run Code Online (Sandbox Code Playgroud)
第2步
将您的身份验证帐户类型定义为字符串strings.xml:
<string name="auth_account_type">DigiGene</string>
Run Code Online (Sandbox Code Playgroud)
将“DigiGene”替换为您自己的帐户类型。这就是出现在此屏幕截图中的 Android 帐户中的内容。
第 3 步
设计用于注册用户的注册布局(例如此图像):
<?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>
Run Code Online (Sandbox Code Playgroud)
并MyRegistrationActivity.java使用以下代码创建一个新类,例如:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
第四步
做一个条目的布局在这里:
<?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>
Run Code Online (Sandbox Code Playgroud)
此布局与以下类一起使用:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
第 5 步
这是为了注册和登录目的而连接到服务器所需的方法的最后一步,然后实现。在下面,与实际情况相反,模拟服务器连接,只是为了演示库的功能。您可以用自己的真实实现替换以下实现。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
结果
下面显示了正在运行的库。你可以在这里找到完整的教程,以及AccountManager在我网站的这三篇文章中关于android如何工作的内容:第 1部分、第 2部分、第 3 部分。
| 归档时间: |
|
| 查看次数: |
24515 次 |
| 最近记录: |