安卓Wifi DPP(Wi-Fi轻松连接)



由于Android 10+不再允许您以编程方式连接到wifi网络(您只能向列表中建议/添加网络,但如果您有现有的wifi连接,它们可能永远不会连接(,我想使用wifi轻松连接(https://source.android.com/devices/tech/connect/wifi-easy-connect)我假设这基本上就是qr码扫描选项,可以通过wifi设置访问。

文档中指出,您应该检查它是否受支持:

Public APIs are available in Android 10 for use by apps:
WifiManager#isEasyConnectSupported: Queries the framework to determine whether the device supports Wi-Fi Easy Connect.
Activity#startActivityForResult(ACTION_PROCESS_WIFI_EASY_CONNECT_URI): Allows apps to integrate Wi-Fi Easy Connect into their onboarding/setup flow.

我已经做了:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
if (wifiManager.isEasyConnectSupported)
{
startActivityForResult(Intent(android.provider.Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_URI), 1237)
}
}

然而,由于找不到活动,这会崩溃(我已经在Pixel 4XL和模拟器上进行了测试,两者都运行R(:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: xxx, PID: 8498
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.PROCESS_WIFI_EASY_CONNECT_URI }

这可能被应用程序使用吗?有没有其他方法可以可靠地连接到wifi网络?这是正确的方法吗?或者有没有办法直接启动设置屏幕?

我在安卓清单中发现了这些,但我找不到启动它们的方法:

<activity
android:name=".wifi.dpp.WifiDppConfiguratorActivity">
<intent-filter>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER"/>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.settings.PROCESS_WIFI_EASY_CONNECT_URI"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="DPP"/>
</intent-filter>
</activity>
<activity
android:name=".wifi.dpp.WifiDppEnrolleeActivity">
<intent-filter>
<action android:name="android.settings.WIFI_DPP_ENROLLEE_QR_CODE_SCANNER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

如果您想使用二维码扫描仪连接到Wifi,以下代码将很好地工作

@RequiresApi(api = Build.VERSION_CODES.Q)
private void startWifiQRCodeScanner(Context context)
{
final String INTENT_ACTION_WIFI_QR_SCANNER = "android.settings.WIFI_DPP_ENROLLEE_QR_CODE_SCANNER"; 
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if(wifiManager.isEasyConnectSupported())
{
final Intent intent = new Intent(INTENT_ACTION_WIFI_QR_SCANNER);
startActivityForResult(intent, 5000);
}
}

我在软件包/apps/Settings/AndroidManifest.xml中发现了以下代码:

<activity
android:name=".wifi.dpp.WifiDppEnrolleeActivity">
<intent-filter>
<action android:name="android.settings.WIFI_DPP_ENROLLEE_QR_CODE_SCANNER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

看起来只有在启动此活动时才支持DPP Uri。发送的这些DPP-Uri仅用于引导,而不用于交换有关WiFi网络身份验证的信息。

要在Android 10上连接WiFi网络,谷歌推荐他们的android.provider.Settings.ACTION_WIFI_ADD_NETWORKS方法。根据我的经验,这连接到WiFi。然而,它是在没有互联网连接的情况下完成的。请参阅:https://developer.android.com/guide/topics/connectivity/wifi-bootstrap

还有WifiNetworkSuggestion,它显示一个通知,只建议用户连接到WiFi,这可能是隐藏的,尤其是当你的应用程序在沉浸模式下运行时。请参阅:https://developer.android.com/guide/topics/connectivity/wifi-suggest

Android 11(API 30(将允许您使用WifiManager.addNetworkIntent添加WifiNetworkSuggestions。这类似于旧的WifiNetworkSuggestionAPI。请参阅:https://developer.android.com/guide/topics/connectivity/wifi-save-network-passpoint-config了解更多信息。

目前,Android 10的最佳选择似乎是要求用户通过WiFi设置手动连接,或者扫描二维码或输入WiFi详细信息。或者使用CCD_5 API。

看起来缺少DPP URI字符串,该字符串应该从文档中设置

以下是它应该是什么样子:

dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device>

我把它带到这里

您可以查看协议规范内部,以构建自己的DPP-URI。

希望这能帮助你继续调查。我还在这个问题上。所以,请分享任何更新。

我也在努力实现这一意图,但到目前为止运气不佳。以下是我的发现:

  • 要设置的注册者设备必须支持Wifi Easy Connect(DPP(
  • 您可以将Raspberry Pi 4用作兼容的注册人(请参阅此处如何配置http://w1.fi/cgit/hostap/plain/wpa_supplicant/README-DPP)

对于有效的URI,您需要使用WPA_CLI命令生成的Enrollee mac地址和公钥

final String VALID_WIFI_DPP_QR_CODE = "" +
"DPP:" +
"I:SN=4774LH2b4044;" +
"M:dea6327ee40a;" + //put here the Enrollee mac address
"K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQDDIgADUAQGkdCbThkC1omyOCRX1mCxXZJo8h8yqQ7Jx4WsxFA=;;"; // put here the Enrollee public key
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if(wifiManager.isEasyConnectSupported())
{
final Intent intent = new Intent(INTENT_PROCESS_WIFI_EASY_CONNECT_URI);
intent.setData(Uri.parse(VALID_WIFI_DPP_QR_CODE));
startActivityForResult(intent, 5000);
}

关键参数是可选的,因为当没有提供时,WPA_CLI将为您生成一个

如果您应用其mac地址和公钥,此代码可以到达注册人

<3>DPP-RX src=96:cc:02:1d:5d:ca freq=2412 type=0
<3>DPP-TX dst=96:cc:02:1d:5d:ca freq=2412 type=1
<3>DPP-TX-STATUS dst=96:cc:02:1d:5d:ca freq=2412 result=no-ACK

我被卡住了,Android应用程序没有确认注册人身份验证响应:

private final String LOGTAG = "Connecting Wifi AP";
public boolean OnConnectionInit = true; // is used to prevent multiple api calls with OnAvailable event
public void ConnectToAP(String Ssid, String wifipassword) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
final WifiManager wifiManager = (WifiManager) getActivity().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
final NetworkSpecifier specifier =
new WifiNetworkSpecifier.Builder()
.setSsid(Ssid)
.setWpa2Passphrase(wifipassword)
.build();
final NetworkRequest request =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

final ConnectivityManager connectivityManager = (ConnectivityManager)
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
final String InhomeSSID = wifiManager.getConnectionInfo().getSSID();
Log.d(LOGTAG, "Current SSID: " + InhomeSSID);

Log.d(LOGTAG, "build up Wifi connection");            
final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
// do success processing here..
connectivityManager.bindProcessToNetwork(network);
Log.d(LOGTAG, "Network available");                    
String wifiName = wifiManager.getConnectionInfo().getSSID();
Log.d(LOGTAG, "New SSID: " + wifiName);                    
WifiInfo Info = wifiManager.getConnectionInfo();
String IPAddress = Formatter.formatIpAddress(Info.getIpAddress());
Log.d(LOGTAG, "New IPAddress: " + IPAddress);                    
if (OnConnectionInit) {
// set wifi config request:                        
HttpFetchAndUnregister("http://10.0.0.1/cgi-bin/ui_system.cgi?cmd=get_config", connectivityManager, this);
OnConnectionInit = false;
}
}
public void onUnavailable() {
// do failure processing here..
Log.d(LOGTAG, "Network unavailable");
AlertDialog EndDialog = new AlertDialog.Builder(getActivity()).create();
EndDialog.setTitle("Error connecting");
EndDialog.setMessage("Could not connect to " + Ssid);
EndDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
EndDialog.show();
}
};
connectivityManager.requestNetwork(request, networkCallback);
Log.d(LOGTAG, "Network requested");            
connectivityManager.registerNetworkCallback(request, networkCallback);
Log.d(LOGTAG, "Network registered");           
}
}
private void HttpFetchAndUnregister(String Url, ConnectivityManager connectivityManager, ConnectivityManager.NetworkCallback networkConnectionReceiver) {        
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
Log.d(LOGTAG, "url: " + Url);
StringRequest stringRequest = new StringRequest(Request.Method.GET, Url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//This code is executed if the server responds, whether or not the response contains data.
Log.d(LOGTAG, "Http request response: " + response);                
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(networkConnectionReceiver);
}                
}
}, new Response.ErrorListener() { //Create an error listener to handle errors appropriately.
@Override
public void onErrorResponse(VolleyError error) {
//This code is executed if there is an error.
Log.d(LOGTAG, "error: " + error);                
}
});
requestQueue.add(stringRequest);
}

希望这将引发一些新的想法,使这项工作。

回答您的问题"有没有其他方法可以可靠地连接到wifi网络">

这是我的工作代码,作为Fragment活动的一部分,以编程方式设置与AP的Wifi连接。该代码旨在与接入点建立临时连接,执行一些api操作并注销(断开连接(,这将恢复到原始的Wifi连接。如果您没有注销,Wifi连接将保持活动状态,直到您注销为止。

注意:Android API第29级不支持与互联网的编程Wifi连接!这仅适用于P2P Wifi连接。如果您想要使用接入点的WIFI二维码进行WIFI互联网连接,请使用Intent(Intent_ACTION_WIFI_QR_SCANNER(。

PD_12

最新更新