You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求Android/iOS/Flutter多应用单设备集中登录方案(类Yandex ID)

多应用共享认证账户实现方案(仿Yandex ID)

针对你需要多同认证体系应用共享已登录账户(含Token)、数据随任一应用留存的需求,分平台给出具体实现思路和代码示例:

Android 平台

推荐方案:自定义账户类型的AccountManager

AccountManager是Android系统级的账户管理组件,通过自定义统一账户类型,让所有同体系应用都能操作该类型账户,避免单一应用卸载导致数据丢失。

步骤1:配置权限与账户类型

所有同体系应用的AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

同时定义自定义账户类型(比如com.yourapp.account),并注册Authenticator服务(所有应用可复用相同的Authenticator实现):

<service
    android:name=".AccountAuthenticatorService"
    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>

res/xml/authenticator.xml配置:

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="com.yourapp.account"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name" />

步骤2:Authenticator服务实现

class AccountAuthenticatorService : Service() {
    private lateinit var authenticator: AccountAuthenticator

    override fun onCreate() {
        authenticator = AccountAuthenticator(this)
    }

    override fun onBind(intent: Intent): IBinder {
        return authenticator.iBinder
    }

    inner class AccountAuthenticator(context: Context) : AbstractAccountAuthenticator(context) {
        override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array<out String>?, options: Bundle?): Bundle {
            return Bundle()
        }

        override fun getAuthToken(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle {
            return Bundle()
        }

        // 实现其他必要的抽象方法,返回默认Bundle即可
        override fun confirmCredentials(response: AccountAuthenticatorResponse?, account: Account?, options: Bundle?): Bundle = Bundle()
        override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?): Bundle = Bundle()
        override fun getAuthTokenLabel(authTokenType: String?): String? = null
        override fun hasFeatures(response: AccountAuthenticatorResponse?, account: Account?, features: Array<out String>?): Bundle = Bundle()
        override fun updateCredentials(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle = Bundle()
    }
}

步骤3:账户增查操作

登录成功后保存账户:

val accountManager = AccountManager.get(context)
val account = Account(username, "com.yourapp.account")
// 存储Token到账户的UserData中
accountManager.addAccountExplicitly(account, null, bundleOf("auth_token" to loginToken))

其他应用查询账户列表:

val accounts = accountManager.getAccountsByType("com.yourapp.account")
val accountList = accounts.map { account ->
    val token = accountManager.getUserData(account, "auth_token")
    Pair(account.name, token)
}

iOS 平台

推荐方案:Keychain Groups

iOS的Keychain Groups是官方原生的跨应用敏感数据共享方案,只要所有应用配置相同的Keychain Group,即可共享数据,且数据随任一应用留存。

步骤1:配置Keychain Group

  1. 在Apple开发者后台,为所有同体系应用开启相同的Keychain Group(比如group.com.yourapp.accounts)
  2. 在每个应用的Info.plist中添加配置:
<key>keychain-access-groups</key>
<array>
    <string>group.com.yourapp.accounts</string>
</array>

步骤2:封装Keychain操作工具类

import Security

class SharedAccountManager {
    static let shared = SharedAccountManager()
    private let groupIdentifier = "group.com.yourapp.accounts"
    
    // 保存账户与Token
    func saveAccount(username: String, token: String) {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrAccount: username,
            kSecAttrService: groupIdentifier,
            kSecValueData: token.data(using: .utf8)!,
            kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
        ]
        // 先删除旧数据再新增
        SecItemDelete(query as CFDictionary)
        SecItemAdd(query as CFDictionary, nil)
    }
    
    // 获取所有账户列表
    func getAllAccounts() -> [(username: String, token: String)] {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: groupIdentifier,
            kSecReturnAttributes: kCFBooleanTrue!,
            kSecReturnData: kCFBooleanTrue!,
            kSecMatchLimit: kSecMatchLimitAll
        ]
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        
        guard status == errSecSuccess, let items = result as? [[String: Any]] else {
            return []
        }
        
        return items.compactMap { item in
            guard let username = item[kSecAttrAccount as String] as? String,
                  let tokenData = item[kSecValueData as String] as? Data,
                  let token = String(data: tokenData, encoding: .utf8) else {
                return nil
            }
            return (username, token)
        }
    }
}

步骤3:业务层调用

登录成功保存:

SharedAccountManager.shared.saveAccount(username: "user123", token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")

其他应用获取账户:

let accounts = SharedAccountManager.shared.getAllAccounts()
for account in accounts {
    print("用户名:\(account.username),Token:\(account.token)")
}

Flutter 跨平台方案

通过MethodBridge桥接原生实现,实现跨平台账户共享:

Flutter端代码

import 'package:flutter/services.dart';

class SharedAccountManager {
  static const MethodChannel _channel = MethodChannel('com.yourapp/shared_account');

  /// 保存账户
  static Future<void> saveAccount(String username, String token) async {
    await _channel.invokeMethod(
      'saveAccount',
      {'username': username, 'token': token},
    );
  }

  /// 获取账户列表
  static Future<List<Map<String, String>>> getAccounts() async {
    final List<dynamic> result = await _channel.invokeMethod('getAccounts');
    return result.map((item) => {
          'username': item['username'] as String,
          'token': item['token'] as String,
        }).toList();
  }
}

原生端适配

分别在Android和iOS端实现MethodChannel的方法回调,对应上述原生平台的代码逻辑即可。

云端同步补充(可选)

如果需要跨设备同步账户(如Yandex ID),可结合认证服务器实现:

  • 无需依赖设备ID,首次启动时生成随机UUID存储在本地,将UUID与账户信息绑定存储到服务器
  • 应用重装后,通过用户登录行为关联新UUID,拉取该用户的登录记录
  • 云端存储需加密敏感数据,仅在客户端解密使用

内容的提问来源于stack exchange,提问作者Djakh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:17:51