- 名义上,只有authenticator app才可以调用此接口
*/
public boolean addAccountExplicitly(Account account, String password, Bundle extras, Map<String, Integer> visibility)
上述接口要么是用户来选择授权同意,要么是authenticator app给予授权,具体来说android 8.0更加加强了用户的隐私数据安全性
newChooseAccountIntent显示给用户的弹窗样式如下:
从源码的角度分析这几种解决方案
上面说了几种解决方案,为什么这几种方案会有效果呢?
下面让我们一起从源码的角度来解读。
@NonNull
public Account[] getAccountsByType(String type) {
return getAccountsByTypeAsUser(type, Process.myUserHandle());
}
/** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
@NonNull
public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
try {
return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
getAccountsByType 方法里面调用 getAccountsByTypeAsUser 方法,而在 getAccountsByTypeAsUser 方法里面,有调用 mService 的 getAccountsAsUser 方法。
那这个 mService 是什么东东呢?
private final IAccountManager mService;
可以看到其实是一个 AIDl,里面有若干方法
interface IAccountManager {
Account[] getAccounts(String accountType, String opPackageName);
Account[] getAccountsForPackage(String packageName, int uid, String opPackageName);
Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName);
Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features,
String opPackageName);
void getAccountByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
in String[] features, String opPackageName);
void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
in String[] features, String opPackageName);
// 省略了若干方法
}
而这个 AIDL 最终会调用到 AccountManagerService 的相应方法
public class AccountManagerService
extends IAccountManager.Stub
implements RegisteredServicesCacheListener
接下来,我们一起来看一下 AccountManagerService 的 getAccountsAsUser 方法。 getAccountsAsUser 方法里面很简单,只是调用了 getAccountsAsUserForPackage 方法去获取结果。
@Override
@NonNull
public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
mAppOpsManager.checkPackage(callingUid, opPackageName);
return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1,
opPackageName, false /* includeUserManagedNotVisible */);
}
@NonNull
private Account[] getAccountsAsUserForPackage(
String type,
int userId,
String callingPackage,
int packageUid,
String opPackageName,
boolean includeUserManagedNotVisible) {
---- // 省略若干方法
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return getAccountsInternal(
accounts,
callingUid,
opPackageName,
visibleAccountTypes,
includeUserManagedNotVisible);
} finally {
restoreCallingIdentity(identityToken);
}
}
在 getAccountsAsUserForPackage 方法里面,经过一系列的判断,最终又会调用到 getAccountsInternal 方法。
@NonNull
private Account[] getAccountsInternal(
UserAccounts userAccounts,
int callingUid,
String callingPackage,
List visibleAccountTypes,
boolean includeUserManagedNotVisible) {
ArrayList visibleAccounts = new ArrayList<>();
for (String visibleType : visibleAccountTypes) {
Account[] accountsForType = getAccountsFromCache(
userAccounts, visibleType, callingUid, callingPackage,
includeUserManagedNotVisible);
if (accountsForType != null) {
visibleAccounts.addAll(Arrays.asList(accountsForType));
}
}
Account[] result = new Account[visibleAccounts.size()];
for (int i = 0; i < visibleAccounts.size(); i++) {
result[i] = visibleAccounts.get(i);
}
return result;
}
在 getAccountsInternal 方法里面,又会调用 getAccountsFromCache 去获取结果
protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType,
int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) {
Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock),
“Method should not be called with cacheLock”);
if (accountType != null) {
Account[] accounts;
synchronized (userAccounts.cacheLock) {
accounts = userAccounts.accountCache.get(accountType);
}
if (accounts == null) {
return EMPTY_ACCOUNT_ARRAY;
} else {
return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
callingUid, callingPackage, includeManagedNotVisible);
}
} else {
int totalLength = 0;
Account[] accountsArray;
synchronized (userAccounts.cacheLock) {
for (Account[] accounts : userAccounts.accountCache.values()) {
totalLength += accounts.length;
}
if (totalLength == 0) {
return EMPTY_ACCOUNT_ARRAY;
}
accountsArray = new Account[totalLength];
totalLength = 0;
for (Account[] accountsOfType : userAccounts.accountCache.values()) {
System.arraycopy(accountsOfType, 0, accountsArray, totalLength,
accountsOfType.length);
totalLength += accountsOfType.length;
}
}
return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage,
includeManagedNotVisible);
}
}
而在 getAccountsFromCache 里面,不管 accountType 是否为空,最终都会调用到 filterAccounts 方法。
@NonNull
private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
@Nullable String callingPackage, boolean includeManagedNotVisible) {
String visibilityFilterPackage = callingPackage;
if (visibilityFilterPackage == null) {
visibilityFilterPackage = getPackageNameForUid(callingUid);
}
Map<Account, Integer> firstPass = new LinkedHashMap<>();
for (Account account : unfiltered) {
int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts);
if ((visibility == AccountManager.VISIBILITY_VISIBLE
|| visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)
|| (includeManagedNotVisible
&& (visibility
== AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) {
firstPass.put(account, visibility);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
推荐学习资料
- 脑图
由于文章篇幅问题点击链接查看详细文章以及获取学习笔记:GitHub
[外链图片转存中…(img-ejF2wVv4-1711287604743)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-m4QuVxqm-1711287604744)]
推荐学习资料
- 脑图
[外链图片转存中…(img-rYUBDcBB-1711287604744)]
[外链图片转存中…(img-BXkH58UT-1711287604745)]
[外链图片转存中…(img-KFOGhdRX-1711287604745)]
由于文章篇幅问题点击链接查看详细文章以及获取学习笔记:GitHub