适用于互联网连接的 WLAN 建议 API

搭载 Android 10(API 级别 29)及更高版本的设备允许您的应用为设备添加网络凭据,以自动连接到 Wi-Fi 接入点。您可以使用 WifiNetworkSuggestion 提供关于要连接到哪个网络的建议。平台最终会根据您的应用和其他应用的输入来选择要接受的接入点。

在 Android 11(API 级别 30)及更高版本中:

  • 该框架针对基于 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 实现了此功能,以符合 PPS-MO 扩展的 WBA 规范。如果应用建议的 Passpoint 网络需要修饰的身份,应用必须先调用此 API,以确保设备支持该功能。如果设备不支持该功能,身份就不会进行修饰,并且对网络的身份验证可能会失败。

如需创建 Passpoint 建议,应用必须使用 PasspointConfigurationCredentialHomeSp 类。这些类描述了 Wi-Fi Alliance Passpoint 规范中定义的 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 控制 > App name)授予此批准。