Android 帐户同步机制
装过Android版的Facebook、lastfm的同学是否对于这些应用的功能感到惊喜,它们可以定期更新朋友的最新信息,将最新近况和心情短语集成入联系人中。这些应用全部是以Android2.0后的账户和同步机制为基础的。Google的例程中给出了名为SampleSyncAdpater的例子,通过分析该例子可以学会Android中的Account验证、同步Adapter的使用。详细例子...
装过Android版的Facebook、lastfm的同学是否对于这些应用的功能感到惊喜,它们可以定期更新朋友的最新信息,将最新近况和心情短语集成入联系人中。这些应用全部是以Android2.0后的账户和同步机制为基础的。Google的例程中给出了名为SampleSyncAdpater的例子,通过分析该例子可以学会Android中的Account验证、同步Adapter的使用。
详细例子代码可以看sdk samples中提供的源码,现在拿2.2中的版本来简要说明。
首先是 class Authenticator extends AbstractAccountAuthenticator ,该类是账户认证类,打开手机的Setting里,有Account&Sync 一项,Authenticator就是实现其中的账号功能的类。
- //inAuthenticator.java
- publicBundleaddAccount(AccountAuthenticatorResponseresponse,
- StringaccountType,StringauthTokenType,String[]requiredFeatures,
- Bundleoptions){
- finalIntentintent=newIntent(mContext,AuthenticatorActivity.class);
- intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE,
- authTokenType);
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
- response);
- finalBundlebundle=newBundle();
- bundle.putParcelable(AccountManager.KEY_INTENT,intent);
- returnbundle;
- }
其中addAccount方法用来定义需要增加账号时的操作,如调用AuthenticatorActivity来进行账号的添加认证。
在AuthenticatorActivity.java中定义了handleLogin(),此方法由login_activity.xml中的android:onClick="handleLogin"定义与ui中的okbutton的关联。
- //inlayout/login_activity.xml
- <Button
- android:id="@+id/ok_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:minWidth="100dip"
- android:text="@string/login_activity_ok_button"
- android:onClick="handleLogin"/>
handleLogin()将ui中的用户名和密码取得,并创建一个试图认证的线程,通过网络去服务端验证。
NetworkUtilities.java中的 public static boolean authenticate(String username, String password, Handler handler, final Context context)方法展示了通过网络验证的具体流程。得到服务端验证结果后,在sendResult()中通过handler.post调用来实现 onAuthenticationResult()在AuthenticatorActivity中的运行。 onAuthenticationResult()判断验证通过则结束AuthenticatorActivity,否则报出用户名密码错,让用户在 AuthenticatorActivity中再次尝试验证。
- //AuthenticatorActivity.java中的handleLogin()方法
- /**
- *HandlesonClickeventontheSubmitbutton.Sendsusername/passwordto
- *theserverforauthentication.
- *
- *@paramviewTheSubmitbuttonforwhichthismethodisinvoked
- */
- publicvoidhandleLogin(Viewview){
- if(mRequestNewAccount){
- mUsername=mUsernameEdit.getText().toString();
- }
- mPassword=mPasswordEdit.getText().toString();
- if(TextUtils.isEmpty(mUsername)||TextUtils.isEmpty(mPassword)){
- mMessage.setText(getMessage());
- }else{
- showProgress();
- //Startauthenticating...
- mAuthThread=
- NetworkUtilities.attemptAuth(mUsername,mPassword,mHandler,
- AuthenticatorActivity.this);
- }
- }
- //NetworkUtilities中的authenticate()方法通过网络访问具体来实现服务端的验证,sendResult()来使调用结果被AuthenticatorActivity的onAuthenticationResult()调用。
- /**
- *ConnectstotheVoiperserver,authenticatestheprovidedusernameand
- *password.
- *
- *@paramusernameTheuser'susername
- *@parampasswordTheuser'spassword
- *@paramhandlerThehanderinstancefromthecallingUIthread.
- *@paramcontextThecontextofthecallingActivity.
- *@returnbooleanThebooleanresultindicatingwhethertheuserwas
- *successfullyauthenticated.
- */
- publicstaticbooleanauthenticate(Stringusername,Stringpassword,
- Handlerhandler,finalContextcontext){
- finalHttpResponseresp;
- finalArrayList<NameValuePair>params=newArrayList<NameValuePair>();
- params.add(newBasicNameValuePair(PARAM_USERNAME,username));
- params.add(newBasicNameValuePair(PARAM_PASSWORD,password));
- HttpEntityentity=null;
- try{
- entity=newUrlEncodedFormEntity(params);
- }catch(finalUnsupportedEncodingExceptione){
- //thisshouldneverhappen.
- thrownewAssertionError(e);
- }
- finalHttpPostpost=newHttpPost(AUTH_URI);
- post.addHeader(entity.getContentType());
- post.setEntity(entity);
- maybeCreateHttpClient();
- try{
- resp=mHttpClient.execute(post);
- if(resp.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"Successfulauthentication");
- }
- sendResult(true,handler,context);
- returntrue;
- }else{
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"Errorauthenticating"+resp.getStatusLine());
- }
- sendResult(false,handler,context);
- returnfalse;
- }
- }catch(finalIOExceptione){
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"IOExceptionwhengettingauthtoken",e);
- }
- sendResult(false,handler,context);
- returnfalse;
- }finally{
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"getAuthtokencompleting");
- }
- }
- }
- /**
- *SendstheauthenticationresponsefromserverbacktothecallermainUI
- *threadthroughitshandler.
- *
- *@paramresultThebooleanholdingauthenticationresult
- *@paramhandlerThemainUIthread'shandlerinstance.
- *@paramcontextThecallerActivity'scontext.
- */
- privatestaticvoidsendResult(finalBooleanresult,finalHandlerhandler,
- finalContextcontext){
- if(handler==null||context==null){
- return;
- }
- handler.post(newRunnable(){
- publicvoidrun(){
- ((AuthenticatorActivity)context).onAuthenticationResult(result);
- }
- });
- }
- //AuthenticatorActivity.java中的onAuthenticationResult,来根据验证结果来选择结束认证或重新尝试。
- /**
- *Calledwhentheauthenticationprocesscompletes(seeattemptLogin()).
- */
- publicvoidonAuthenticationResult(booleanresult){
- Log.i(TAG,"onAuthenticationResult("+result+")");
- //Hidetheprogressdialog
- hideProgress();
- if(result){
- if(!mConfirmCredentials){
- finishLogin();
- }else{
- finishConfirmCredentials(true);
- }
- }else{
- Log.e(TAG,"onAuthenticationResult:failedtoauthenticate");
- if(mRequestNewAccount){
- //"Pleaseenteravalidusername/password.
- mMessage
- .setText(getText(R.string.login_activity_loginfail_text_both));
- }else{
- //"Pleaseenteravalidpassword."(Usedwhenthe
- //accountisalreadyinthedatabasebutthepassword
- //doesn'twork.)
- mMessage
- .setText(getText(R.string.login_activity_loginfail_text_pwonly));
- }
- }
- }
Account的验证完毕后,就生成了账号,可以开始使用同步功能了。同步的主要逻辑在public class SyncAdapter extends AbstractThreadedSyncAdapter中实现。
- //SyncAdapter.java中的OnPerformSync方法,主要的同步逻辑
- @Override
- publicvoidonPerformSync(Accountaccount,Bundleextras,Stringauthority,
- ContentProviderClientprovider,SyncResultsyncResult){
- List<User>users;
- List<Status>statuses;
- Stringauthtoken=null;
- try{
- //usetheaccountmanagertorequestthecredentials
- authtoken=
- mAccountManager.blockingGetAuthToken(account,
- Constants.AUTHTOKEN_TYPE,true/*notifyAuthFailure*/);
- //fetchupdatesfromthesampleserviceoverthecloud
- users=
- NetworkUtilities.fetchFriendUpdates(account,authtoken,
- mLastUpdated);
- //updatethelastsynceddate.
- mLastUpdated=newDate();
- //updateplatformcontacts.
- Log.d(TAG,"CallingcontactManager'ssynccontacts");
- ContactManager.syncContacts(mContext,account.name,users);
- //fetchandupdatestatusmessagesforallthesyncedusers.
- statuses=NetworkUtilities.fetchFriendStatuses(account,authtoken);
- ContactManager.insertStatuses(mContext,account.name,statuses);
- }catch(finalAuthenticatorExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"AuthenticatorException",e);
- }catch(finalOperationCanceledExceptione){
- Log.e(TAG,"OperationCanceledExcetpion",e);
- }catch(finalIOExceptione){
- Log.e(TAG,"IOException",e);
- syncResult.stats.numIoExceptions++;
- }catch(finalAuthenticationExceptione){
- mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
- authtoken);
- syncResult.stats.numAuthExceptions++;
- Log.e(TAG,"AuthenticationException",e);
- }catch(finalParseExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"ParseException",e);
- }catch(finalJSONExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"JSONException",e);
- }
- }
onPerformSync中的执行流程中,使用NetworkUtilities中的fetchFriendUpdates和 fetchFriendStatuses来访问服务端的联系人更新,并使用了例程中自己封装的ContactManager来读取、更新联系人信息。
那Account和SyncAdapter及其Service和xml定义之间是如何关联的呢? AndroidManifest.xml中定义了AccountAuthenticator,SyncAdapter及对应的Service和xml定义的关联。
- <application
- android:icon="@drawable/icon"
- android:label="@string/label">
- <!--Theauthenticatorservice-->
- <service
- android:name=".authenticator.AuthenticationService"
- android:exported="true">
- <intent-filter>
- <action
- android:name="android.accounts.AccountAuthenticator"/>
- </intent-filter>
- <meta-data
- android:name="android.accounts.AccountAuthenticator"
- android:resource="@xml/authenticator"/>
- </service>
- <service
- android:name=".syncadapter.SyncService"
- android:exported="true">
- <intent-filter>
- <action
- android:name="android.content.SyncAdapter"/>
- </intent-filter>
- <meta-data
- android:name="android.content.SyncAdapter"
- android:resource="@xml/syncadapter"/>
- <meta-data
- android:name="android.provider.CONTACTS_STRUCTURE"
- android:resource="@xml/contacts"/>
- </service>
- <activity
- android:name=".authenticator.AuthenticatorActivity"
- android:label="@string/ui_activity_title"
- android:theme="@android:style/Theme.Dialog"
- android:excludeFromRecents="true"
- >
- <!--
- Nointent-filterhere!Thisactivityisonlyeverlaunchedby
- someonewhoexplicitlyknowstheclassname
- -->
- </activity>
- </application>
更详细的代码细节和执行流程,可以去把SDK中的SampleSyncAdapter代码运行起来体会一下,不过要实现整个流程,必须搭建联系人的服务器端,例程中在目录samplesyncadapter_server中也提供了简单的server端python代码,需要搭建在google app engine上。搭建过程遇到一些问题,由于对python不熟我弄了几天才解决好搭建成功,其中遇到的一个model moudle找不到的问题需要你在model中新建一个__init__.py的空文件,来说明是一个python模块,如果你也遇到此问题,希望对你有帮助。
以上是从别人那里看到的一篇不错的文章,以下是自己在源码开发过程中的一些总结:
帐户信息保存在:data/system/account.db
data/system/sync
data/system/registered-services下面
涉到的service包括:
<service
android:name=".myservices.ContactsSyncAdapterService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter_contacts" />
</service>
<service
android:name=".myservices.CalendarSyncAdapterService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter_calendar" />
</service>
<service
android:name=".myservices.SyncManager"
android:enabled="true"
>
</service>
<service
android:name=".service.EasAuthenticatorService"
android:exported="true"
android:enabled="true"
>
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator"
/>
</service>
<service
android:name=".myservices.EasAuthenticatorServiceAlternate"
android:exported="true"
>
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator_alternate"
/>
</service>
装过Android版的Facebook、lastfm的同学是否对于这些应用的功能感到惊喜,它们可以定期更新朋友的最新信息,将最新近况和心情短语集成入联系人中。这些应用全部是以Android2.0后的账户和同步机制为基础的。Google的例程中给出了名为SampleSyncAdpater的例子,通过分析该例子可以学会Android中的Account验证、同步Adapter的使用。
详细例子代码可以看sdk samples中提供的源码,现在拿2.2中的版本来简要说明。
首先是 class Authenticator extends AbstractAccountAuthenticator ,该类是账户认证类,打开手机的Setting里,有Account&Sync 一项,Authenticator就是实现其中的账号功能的类。
- //inAuthenticator.java
- publicBundleaddAccount(AccountAuthenticatorResponseresponse,
- StringaccountType,StringauthTokenType,String[]requiredFeatures,
- Bundleoptions){
- finalIntentintent=newIntent(mContext,AuthenticatorActivity.class);
- intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE,
- authTokenType);
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
- response);
- finalBundlebundle=newBundle();
- bundle.putParcelable(AccountManager.KEY_INTENT,intent);
- returnbundle;
- }
其中addAccount方法用来定义需要增加账号时的操作,如调用AuthenticatorActivity来进行账号的添加认证。
在AuthenticatorActivity.java中定义了handleLogin(),此方法由login_activity.xml中的android:onClick="handleLogin"定义与ui中的okbutton的关联。
- //inlayout/login_activity.xml
- <Button
- android:id="@+id/ok_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:minWidth="100dip"
- android:text="@string/login_activity_ok_button"
- android:onClick="handleLogin"/>
handleLogin()将ui中的用户名和密码取得,并创建一个试图认证的线程,通过网络去服务端验证。
NetworkUtilities.java中的 public static boolean authenticate(String username, String password, Handler handler, final Context context)方法展示了通过网络验证的具体流程。得到服务端验证结果后,在sendResult()中通过handler.post调用来实现 onAuthenticationResult()在AuthenticatorActivity中的运行。 onAuthenticationResult()判断验证通过则结束AuthenticatorActivity,否则报出用户名密码错,让用户在 AuthenticatorActivity中再次尝试验证。
- //AuthenticatorActivity.java中的handleLogin()方法
- /**
- *HandlesonClickeventontheSubmitbutton.Sendsusername/passwordto
- *theserverforauthentication.
- *
- *@paramviewTheSubmitbuttonforwhichthismethodisinvoked
- */
- publicvoidhandleLogin(Viewview){
- if(mRequestNewAccount){
- mUsername=mUsernameEdit.getText().toString();
- }
- mPassword=mPasswordEdit.getText().toString();
- if(TextUtils.isEmpty(mUsername)||TextUtils.isEmpty(mPassword)){
- mMessage.setText(getMessage());
- }else{
- showProgress();
- //Startauthenticating...
- mAuthThread=
- NetworkUtilities.attemptAuth(mUsername,mPassword,mHandler,
- AuthenticatorActivity.this);
- }
- }
- //NetworkUtilities中的authenticate()方法通过网络访问具体来实现服务端的验证,sendResult()来使调用结果被AuthenticatorActivity的onAuthenticationResult()调用。
- /**
- *ConnectstotheVoiperserver,authenticatestheprovidedusernameand
- *password.
- *
- *@paramusernameTheuser'susername
- *@parampasswordTheuser'spassword
- *@paramhandlerThehanderinstancefromthecallingUIthread.
- *@paramcontextThecontextofthecallingActivity.
- *@returnbooleanThebooleanresultindicatingwhethertheuserwas
- *successfullyauthenticated.
- */
- publicstaticbooleanauthenticate(Stringusername,Stringpassword,
- Handlerhandler,finalContextcontext){
- finalHttpResponseresp;
- finalArrayList<NameValuePair>params=newArrayList<NameValuePair>();
- params.add(newBasicNameValuePair(PARAM_USERNAME,username));
- params.add(newBasicNameValuePair(PARAM_PASSWORD,password));
- HttpEntityentity=null;
- try{
- entity=newUrlEncodedFormEntity(params);
- }catch(finalUnsupportedEncodingExceptione){
- //thisshouldneverhappen.
- thrownewAssertionError(e);
- }
- finalHttpPostpost=newHttpPost(AUTH_URI);
- post.addHeader(entity.getContentType());
- post.setEntity(entity);
- maybeCreateHttpClient();
- try{
- resp=mHttpClient.execute(post);
- if(resp.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"Successfulauthentication");
- }
- sendResult(true,handler,context);
- returntrue;
- }else{
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"Errorauthenticating"+resp.getStatusLine());
- }
- sendResult(false,handler,context);
- returnfalse;
- }
- }catch(finalIOExceptione){
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"IOExceptionwhengettingauthtoken",e);
- }
- sendResult(false,handler,context);
- returnfalse;
- }finally{
- if(Log.isLoggable(TAG,Log.VERBOSE)){
- Log.v(TAG,"getAuthtokencompleting");
- }
- }
- }
- /**
- *SendstheauthenticationresponsefromserverbacktothecallermainUI
- *threadthroughitshandler.
- *
- *@paramresultThebooleanholdingauthenticationresult
- *@paramhandlerThemainUIthread'shandlerinstance.
- *@paramcontextThecallerActivity'scontext.
- */
- privatestaticvoidsendResult(finalBooleanresult,finalHandlerhandler,
- finalContextcontext){
- if(handler==null||context==null){
- return;
- }
- handler.post(newRunnable(){
- publicvoidrun(){
- ((AuthenticatorActivity)context).onAuthenticationResult(result);
- }
- });
- }
- //AuthenticatorActivity.java中的onAuthenticationResult,来根据验证结果来选择结束认证或重新尝试。
- /**
- *Calledwhentheauthenticationprocesscompletes(seeattemptLogin()).
- */
- publicvoidonAuthenticationResult(booleanresult){
- Log.i(TAG,"onAuthenticationResult("+result+")");
- //Hidetheprogressdialog
- hideProgress();
- if(result){
- if(!mConfirmCredentials){
- finishLogin();
- }else{
- finishConfirmCredentials(true);
- }
- }else{
- Log.e(TAG,"onAuthenticationResult:failedtoauthenticate");
- if(mRequestNewAccount){
- //"Pleaseenteravalidusername/password.
- mMessage
- .setText(getText(R.string.login_activity_loginfail_text_both));
- }else{
- //"Pleaseenteravalidpassword."(Usedwhenthe
- //accountisalreadyinthedatabasebutthepassword
- //doesn'twork.)
- mMessage
- .setText(getText(R.string.login_activity_loginfail_text_pwonly));
- }
- }
- }
Account的验证完毕后,就生成了账号,可以开始使用同步功能了。同步的主要逻辑在public class SyncAdapter extends AbstractThreadedSyncAdapter中实现。
- //SyncAdapter.java中的OnPerformSync方法,主要的同步逻辑
- @Override
- publicvoidonPerformSync(Accountaccount,Bundleextras,Stringauthority,
- ContentProviderClientprovider,SyncResultsyncResult){
- List<User>users;
- List<Status>statuses;
- Stringauthtoken=null;
- try{
- //usetheaccountmanagertorequestthecredentials
- authtoken=
- mAccountManager.blockingGetAuthToken(account,
- Constants.AUTHTOKEN_TYPE,true/*notifyAuthFailure*/);
- //fetchupdatesfromthesampleserviceoverthecloud
- users=
- NetworkUtilities.fetchFriendUpdates(account,authtoken,
- mLastUpdated);
- //updatethelastsynceddate.
- mLastUpdated=newDate();
- //updateplatformcontacts.
- Log.d(TAG,"CallingcontactManager'ssynccontacts");
- ContactManager.syncContacts(mContext,account.name,users);
- //fetchandupdatestatusmessagesforallthesyncedusers.
- statuses=NetworkUtilities.fetchFriendStatuses(account,authtoken);
- ContactManager.insertStatuses(mContext,account.name,statuses);
- }catch(finalAuthenticatorExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"AuthenticatorException",e);
- }catch(finalOperationCanceledExceptione){
- Log.e(TAG,"OperationCanceledExcetpion",e);
- }catch(finalIOExceptione){
- Log.e(TAG,"IOException",e);
- syncResult.stats.numIoExceptions++;
- }catch(finalAuthenticationExceptione){
- mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
- authtoken);
- syncResult.stats.numAuthExceptions++;
- Log.e(TAG,"AuthenticationException",e);
- }catch(finalParseExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"ParseException",e);
- }catch(finalJSONExceptione){
- syncResult.stats.numParseExceptions++;
- Log.e(TAG,"JSONException",e);
- }
- }
onPerformSync中的执行流程中,使用NetworkUtilities中的fetchFriendUpdates和 fetchFriendStatuses来访问服务端的联系人更新,并使用了例程中自己封装的ContactManager来读取、更新联系人信息。
那Account和SyncAdapter及其Service和xml定义之间是如何关联的呢? AndroidManifest.xml中定义了AccountAuthenticator,SyncAdapter及对应的Service和xml定义的关联。
- <application
- android:icon="@drawable/icon"
- android:label="@string/label">
- <!--Theauthenticatorservice-->
- <service
- android:name=".authenticator.AuthenticationService"
- android:exported="true">
- <intent-filter>
- <action
- android:name="android.accounts.AccountAuthenticator"/>
- </intent-filter>
- <meta-data
- android:name="android.accounts.AccountAuthenticator"
- android:resource="@xml/authenticator"/>
- </service>
- <service
- android:name=".syncadapter.SyncService"
- android:exported="true">
- <intent-filter>
- <action
- android:name="android.content.SyncAdapter"/>
- </intent-filter>
- <meta-data
- android:name="android.content.SyncAdapter"
- android:resource="@xml/syncadapter"/>
- <meta-data
- android:name="android.provider.CONTACTS_STRUCTURE"
- android:resource="@xml/contacts"/>
- </service>
- <activity
- android:name=".authenticator.AuthenticatorActivity"
- android:label="@string/ui_activity_title"
- android:theme="@android:style/Theme.Dialog"
- android:excludeFromRecents="true"
- >
- <!--
- Nointent-filterhere!Thisactivityisonlyeverlaunchedby
- someonewhoexplicitlyknowstheclassname
- -->
- </activity>
- </application>
更详细的代码细节和执行流程,可以去把SDK中的SampleSyncAdapter代码运行起来体会一下,不过要实现整个流程,必须搭建联系人的服务器端,例程中在目录samplesyncadapter_server中也提供了简单的server端python代码,需要搭建在google app engine上。搭建过程遇到一些问题,由于对python不熟我弄了几天才解决好搭建成功,其中遇到的一个model moudle找不到的问题需要你在model中新建一个__init__.py的空文件,来说明是一个python模块,如果你也遇到此问题,希望对你有帮助。
以上是从别人那里看到的一篇不错的文章,以下是自己在源码开发过程中的一些总结:
帐户信息保存在:data/system/account.db
data/system/sync
data/system/registered-services下面
涉到的service包括:
<service
android:name=".myservices.ContactsSyncAdapterService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter_contacts" />
</service>
<service
android:name=".myservices.CalendarSyncAdapterService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter_calendar" />
</service>
<service
android:name=".myservices.SyncManager"
android:enabled="true"
>
</service>
<service
android:name=".service.EasAuthenticatorService"
android:exported="true"
android:enabled="true"
>
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator"
/>
</service>
<service
android:name=".myservices.EasAuthenticatorServiceAlternate"
android:exported="true"
>
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator_alternate"
/>
</service>
更多推荐
所有评论(0)