运行 Android 10(API 级别 29)及更高版本的设备允许您的应用为设备添加网络凭据,以便自动连接到 Wi-Fi 接入点。您可以使用 WifiNetworkSuggestion
提供要连接的网络建议。平台最终会根据您的应用和其他应用的输入选择要接受的接入点。
在 Android 11(API 级别 30)及更高版本上
- 建议 API 支持预配
PasspointConfiguration
。在 Android 11 之前,预配PasspointConfiguration
需要使用addOrUpdatePasspointConfiguration()
API。 - 框架对基于 TLS 的企业网络建议(EAP-TLS、EAP-TTLS 和 EAP-PEAP)强制执行安全要求;对此类网络的建议必须设置
根 CA 证书
和服务器域名
。
- 框架对基于 EAP-SIM 的企业网络建议(EAP-SIM、EAP-AKA、EAP-AKA-PRIME)强制执行所有权要求;此类建议仅允许由运营商签名应用提供。
- 对于由运营商签名应用提供的建议,框架会自动为其分配一个与应用 运营商签名 对应的运营商 ID。如果从设备中移除相应的 SIM 卡,此类建议会自动停用。
在 Android 12(API 级别 31)及更高版本上
可以通过非持久性 MAC 随机化来启用额外的隐私保护,该功能会定期重新随机化随机 MAC 地址。使用
setMacRandomizationSetting
指定网络的随机化级别。isPasspointTermsAndConditionsSupported()
:条款和条件是一项 Passpoint 功能,它允许网络部署用安全的 Passpoint 网络替代使用开放网络的不安全强制门户。当需要接受条款和条件时,会向用户显示通知。建议受条款和条件限制的 Passpoint 网络的应用程序必须首先调用此 API,以确保设备支持该功能。如果设备不支持该功能,将无法连接到此网络,并且必须建议备用或旧版网络。isDecoratedIdentitySupported()
:在使用前缀装饰进行网络身份验证时,装饰身份前缀允许网络运营商更新网络访问标识符 (NAI),以通过 AAA 网络内的多个代理执行显式路由(有关更多信息,请参阅 RFC 7542)。Android 12 实现了此功能,以符合 WBA PPS-MO 扩展规范。建议需要装饰身份的 Passpoint 网络的应用程序必须首先调用此 API,以确保设备支持该功能。如果设备不支持该功能,身份将不会被装饰,并且网络身份验证可能会失败。
要创建 Passpoint 建议,应用必须使用 PasspointConfiguration
、Credential
和 HomeSp
类。这些类描述了 Passpoint 配置文件,该配置文件在 Wi-Fi Alliance Passpoint 规范中定义。
以下代码示例展示了如何为开放网络、WPA2 网络、WPA3 网络和 Passpoint 网络提供凭据
Kotlin
val suggestion1 = WifiNetworkSuggestion.Builder() .setSsid("test111111") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); val suggestion2 = WifiNetworkSuggestion.Builder() .setSsid("test222222") .setWpa2Passphrase("test123456") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); val suggestion3 = WifiNetworkSuggestion.Builder() .setSsid("test333333") .setWpa3Passphrase("test6789") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); val passpointConfig = PasspointConfiguration(); // configure passpointConfig to include a valid Passpoint configuration val suggestion4 = WifiNetworkSuggestion.Builder() .setPasspointConfig(passpointConfig) .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); val suggestionsList = listOf(suggestion1, suggestion2, suggestion3, suggestion4); val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager; val status = wifiManager.addNetworkSuggestions(suggestionsList); if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { // do error handling here } // Optional (Wait for post connection broadcast to one of your suggestions) val intentFilter = IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION); val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) { return; } // do post connect processing here } }; context.registerReceiver(broadcastReceiver, intentFilter);
Java
final WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder() .setSsid("test111111") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); final WifiNetworkSuggestion suggestion2 = new WifiNetworkSuggestion.Builder() .setSsid("test222222") .setWpa2Passphrase("test123456") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); final WifiNetworkSuggestion suggestion3 = new WifiNetworkSuggestion.Builder() .setSsid("test333333") .setWpa3Passphrase("test6789") .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); final PasspointConfiguration passpointConfig = new PasspointConfiguration(); // configure passpointConfig to include a valid Passpoint configuration final WifiNetworkSuggestion suggestion4 = new WifiNetworkSuggestion.Builder() .setPasspointConfig(passpointConfig) .setIsAppInteractionRequired(true) // Optional (Needs location permission) .build(); final List<WifiNetworkSuggestion> suggestionsList = new ArrayList<WifiNetworkSuggestion> {{ add(suggestion1); add(suggestion2); add(suggestion3); add(suggestion4); }}; final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); final int status = wifiManager.addNetworkSuggestions(suggestionsList); if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { // do error handling here… } // Optional (Wait for post connection broadcast to one of your suggestions) final IntentFilter intentFilter = new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION); final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals( WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) { return; } // do post connect processing here... } }; context.registerReceiver(broadcastReceiver, intentFilter);
应用首次提出建议后,用户会立即收到通知。通知类型取决于设备上运行的 Android 版本
- 在 Android 11(API 级别 30)及更高版本上,如果应用在前台运行,用户会看到对话框;如果应用在后台运行,用户会看到通知。
- 在 Android 10(API 级别 29)上,无论应用是在前台还是后台运行,用户都会看到通知。
当平台连接到其中一个网络建议时,设置会显示文本,将网络连接归因于相应的建议应用。
处理用户断开连接
如果用户在使用 Wi-Fi 选择器连接到某个网络建议时明确断开连接,则当该网络仍在范围内时,该网络将被忽略。在此期间,即使应用删除并重新添加与该网络对应的网络建议,也不会考虑自动连接该网络。如果用户使用 Wi-Fi 选择器明确连接到之前已断开连接的网络,则将立即考虑自动连接该网络。
更改应用的批准状态
用户拒绝网络建议通知会移除应用的 CHANGE_WIFI_STATE
权限。用户以后可以通过进入 Wi-Fi 控制菜单授予此权限(设置 > 应用和通知 > 特殊应用访问 > Wi-Fi 控制 > 应用名称)。