Wi-Fi 建议 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实现此功能以符合WBA PPS-MO扩展规范。建议使用需要修饰身份的Passpoint网络的应用程序必须首先调用此API,以确保设备支持此功能。如果设备不支持此功能,则身份将不会被修饰,并且网络身份验证可能会失败。

要创建Passpoint建议,应用程序必须使用PasspointConfigurationCredentialHomeSp类。这些类描述了Passpoint配置文件,该配置文件在Wi-Fi联盟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控制** > 应用名称)稍后授予此批准。