編輯:關於Android編程
當有多個APP共用一個賬號系統的時候,在用戶的Android設備上創建一個自定義賬戶用以處理登錄認證會方便很多,比如騰訊的QQ,浏覽器,應用寶系列,360安全衛士、手機助手系列等都是共用一個賬號的,這個賬戶在系統設置頁面的賬戶管理可以看到。
創建自定義賬戶可以分三步:
1、創建認證Activity,這個Activity負責和用戶交互錄入用戶賬戶數據、驗證、保存憑證。 2、繼承實現AbstractAccountAuthenticator類。 3、創建賬戶認證的Serivice,。
下面具體介紹如何一步步創建自己的自定義賬戶:
使用到的權限
因為這個Activity要和系統AccountManager交互所以他就有一些一般activity所沒有的特定需求。為了方便Android框架提供了一個基礎類, AccountAuthenticatorActivity ,通過繼承它你可以專注去創建你自己的自定義身份驗證。 這個類比較簡單,你也可以繼承自普通的Activity,把AccountAuthenticatorActivity裡面的代碼拷貝進去就行。然後就可以和普通Activity一樣處理,界面交互完全取決於你自己。
當如果AbstractAccountAuthenticator需要用一個Activity去處理請求,就可以通過傳遞相應Intent讓系統調用這個Activity來處理,關於AbstractAccountAuthenticator後面再講,先來說說AccountAuthenticatorActivity,查看源碼可知,他內部定義了兩個私有屬性。
private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null; private Bundle mResultBundle = null;
mAccountAuthenticatorResponse是在onCreate中通過getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE) 獲取的。
mResultBundle是需要在finish前手動調用setAccountAuthenticatorResult()方法設置的,作為給啟動此activity請求的結果。示例:
Intent intent = new Intent(); intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); setAccountAuthenticatorResult(intent.getExtras()); setResult(RESULT_OK, intent); finish();
如果沒有設置結果或設置為null,在response中將會被當當做error( ERROR_CODE_CANCELED)。
在LoginActivity中使用下面的方法在系統中創建自定義賬戶
Account account = new Account(name, AccountType); accountManager.addAccountExplicitly(account,passwd,null);
其中的AccountType是你自定義的常量,應該與你在manifest.xml中用於賬戶綁定service裡聲明的一致,service具體後面詳細介紹,如果與聲明的不一致會報權限錯誤。
需要特別注意的是實際使用中不應該把密碼明文保存,官方文檔是這麼說的:
AccountManager 不是一種加密服務。它僅僅按照你傳遞的內容用”’明文”’來存儲。在大部分設備上,這不是問題,因為設備把他們存儲在只有根用戶才能訪問的數據庫中。但是在已經被Root過的設備上,通過adb連接可以讓任何人讀取憑據信息。
因此,你不能直接傳遞用戶的真實密碼給AccountManager.addAccountExplicitly()。 相反,你應該存儲加密的安全令牌來保障限制攻擊者的使用
一般的做法是如果一個設備只能登陸一個賬戶的話,name用來標識應用程序,而真正的用戶名和臨時的訪問Token使用AccountManger.setUserData()保存在account的額外信息中。
繼承AbstractAccountAuthenticator實現AccountAuthenticator,這個類是和系統通信的具體實現,比如在系統設置的賬戶管理中新建賬戶,系統調用的就是這個類中的addAccount方法,通過這個方法可以啟動上面創建的認證Activity。
AbstractAccountAuthenticator內部有幾個抽象方法,這幾個方法分別於AccountManager內部的幾個方法一一對應。
//返回一個bundle,這個bundle可以包含一個用於啟動編輯賬戶Properties的Activity的Intent,對應於accountManager.editProperties() public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) //返回一個bundle, 包含添加賬戶Activity的Intent,對應於 accountManager.addAccountExplicitly() Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) //檢查用戶傳遞過來的憑證 對應於 AccountManager.confirmCredentials() Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) //獲取Token,對應於AccountManager.getAuthToken() 其他進程一般調用這個進行認證 Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) //更新用戶憑證 對應於AccountManager.updateCredentials() Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) //獲取authToken的本地化標簽,具體用處我也沒搞明白 String getAuthTokenLabel(String authTokenType) //檢查驗證account支持的是否支持請求驗證的功能 Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features)
以上各個方法返回的bundled內容的 Key可以包含下面幾種情況:
AccountManager.KEY_INTENT :聲明後面要啟動的intent AccountManager.KEY_ERROR_CODE:請求出錯的錯誤碼 AccountManager.KEY_ERROR_MESSAGE:請求出錯的錯誤信息 AccountManager.KEY_BOOLEAN_RESULT:請求是否成功 AccountManager.KEY_ACCOUNT_NAME AccountManager.KEY_ACCOUNT_TYPE AccountManager.KEY_AUTHTOKEN
等內容或者其他自定義信息。
上面的方法選擇必要的方法實現,不需要的功能返回null即可,下面是兩個方法實現的例子
@Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { final Intent intent = new Intent(mContext, LoginActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, authTokenType); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { final Bundle result = new Bundle(); if(authTokenType.equals(AuthTokenType)){ String authToken = "1111111111";//這裡應該從服務器獲取驗證 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,true); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountType); result.putString(AccountManager.KEY_AUTHTOKEN, authToken); }else{ result.putInt(AccountManager.KEY_ERROR_CODE,-1); result.putString(AccountManager.KEY_ERROR_MESSAGE,"Auth Failed!"); } return result; }
這個服務其實是提供給其他的進程使用的,它的Action為android.accounts.AccountAuthenticator,android系統會通過這個Action找到它,並通過它來把我們自己的賬號注冊到“設置”中,其實這是一個AIDL的使用,它屬於跨進程的調用。
它的實現非常簡單,在onBind()中返回authenticator.getIBinder()即可。
示例代碼:
public class AuthService extends Service { private AccountAuthenticator authenticator; public AuthService() { authenticator = new AccountAuthenticator(this); } @Override public IBinder onBind(Intent intent) { return authenticator.getIBinder(); } }
然後需要在manifest.xml中注冊,注冊需要遵循一些規則:
1、 action必須注冊為android.accounts.AccountAuthenticator,
2、 需要在meta-data中提供具體的的配置信息,這些信息包含在一個xml文件中,
示例如下:
xml/authenticator.xml的內容如下
其中android:accountPreferences=”@xml/account_preferences”並不是必須的,account_preferences是一個PreferenceScreen的布局文件,可以用來寫個跳轉到同步設置頁面的功能。
至此自定義賬戶的創建就完成了,在應用中調用AccountManger的相關方法就可以使用了。
同步適配器框架(SyncAdapter Framework)是Android提供的一套移動端與服務端數據同步的解決方案,它有以下優點
插件化結構 自動執行 自動檢測網絡 省電 有賬戶認證機制最常見的是用於備份,聯系人同步等各種雲同步功能。
SyncAdapter依賴於自定義賬戶、和ContentProvider,即時你的同步功能沒有使用賬戶認證和ContentProvider,也要提供一個虛擬的實現,這是SyncAdapter的必要組件。
下面就來一步步完成一個同步適配器的創建,實現一個SyncAdapter分以下幾步:
需要用到的權限
這個前面已經講過了,按照前面的完成即可。
由於ContentProvider不是本文的重點,所以就不詳細介紹了,如果不熟的話關於他的詳細知識請自行搜索,這裡為了演示同步適配器的功能只是把繼承自ContentProvider的增刪改查方法簡單的返回而已。
public class SyncContentProvider extends ContentProvider { public SyncContentProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public boolean onCreate() { return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
然後在manifest.xml文件中注冊,比普通的provider多了一個android:syncable=”true”的屬性
其中android:authorities的值後面注冊同步服務的時候會用到。
繼承自AbstractThreadedSyncAdapter,並實現其方法。
在構造方法中初始化需要用到的組件,比如初始化一個ContentResolver
除了構造方法外只有一個onPerformSync方法需要實現,這是真正要運行的同步方法,這個方法運行在獨立的線程中,其中可以進行聯網耗時操作。
這個方法是系統負責調用的,需要注意的是:
和自定義賬戶類型一樣,它的實現也非常簡單,在onBind中返回syncAdapter.getSyncAdapterBinder()即可。
代碼示例:
public class SyncService extends Service { private static SyncAdapter syncAdapter; //用於保證SyncAdapter的單例 private static final Object sSyncAdapterLock = new Object(); @Override public void onCreate() { super.onCreate(); synchronized (sSyncAdapterLock){ if(syncAdapter==null) { syncAdapter = new SyncAdapter(this, true); } } } @Override public IBinder onBind(Intent intent) { return syncAdapter.getSyncAdapterBinder(); } }
在manifest.xml中注冊服務:
其中action和meta-data的name屬性都是固定的,meta-data中resource對應的xml文件的寫法配置如下:
android:accountType的值要和自定義賬戶的一致 android:contentAuthority的值要和上面contentProvider注冊的android:authorities的值相一致。 android:allowParallelSyncs當值為true的時候,如果你的賬戶類型支持同時多個不同賬戶存在的話,就可以有多個SyncAdapter的實例,同時運行同步任務,如果不支持多個賬戶的話設置為false就可以。 android:userVisible的作用是指示在在設置的賬戶管理中,同步開關是否可見。 android:isAlwaysSyncable=”true” 系統可以自動同步。
至此同步適配器的配置就完成了,下面講講如何調用SyncAdapter的同步功能:
需要調用運行同步適配器的情況一般有下面這四種:
Bundle settingsBundle = new Bundle(); settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); ettingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
概述類android.graphics.PorterDuffXfermode繼承自android.graphics.Xfermode。在用Android中的Canvas進
接著上次的問題,已經介紹過,在初始化或者說OnCreate方法中獲取加載的布局的寬高,最後說到,調用view.measure(0, 0);然後在調用getMeasur
[Android]仿京東手機端類別頁京東手機端的類別標簽頁, 是一個左側滑動可選擇類別, 右側一個類別明細的列表聯動頁面. 當用戶選擇左側選項, 可在右側顯示更多選項來選
Android jni開發資料--NDK環境搭建 android開發人員注意了 谷歌改良了ndk的開發流程,對於Windows環境下NDK的開發,如果