Android之解决Android10.0通过热点名字和密码连接指定热点网络不能通信问题

1 问题

Android10.0设备通过热点名字和密码连接另外一台设置指定热点,但是他们之间依然不能通信,网络不可达。

Android10.0设备通过热点名字和密码连接另外一台设置指定热点,我用的是官方API,可以参考我的这篇博客

Android之通过用户名和密码连接指定wifi热点(兼容Android9.0和Android10.0和addNetwork(wifiNewConfiguration)返回-1问题)

Android10.0连接热点关键代码如下

  boolean isOpenWifi = mWifiManager.isWifiEnabled();
            if (!isOpenWifi) {
                Log.i(TAG, "用户需要打开wifi开关");
                context.startActivity(new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY));
                callBack.connnectResult(false);
                return;
            }
            NetworkSpecifier specifier =
                    new WifiNetworkSpecifier.Builder()
                            .setSsidPattern(new PatternMatcher(wifiApName, PatternMatcher.PATTERN_PREFIX))
                            .setWpa2Passphrase(password)
                            .build();
 
            NetworkRequest request =
                    new NetworkRequest.Builder()
                            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                            .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                            .setNetworkSpecifier(specifier)
                            .build();
 
            ConnectivityManager connectivityManager = (ConnectivityManager)
                    context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
            ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    // do success processing here..
                    Log.i(TAG, "onAvailable success");
                    Log.i(TAG, "network" + network.toString());
                    callBack.connnectResult(true);
                }
 
                @Override
                public void onUnavailable() {
                    // do failure processing here..
                    Log.i(TAG, "onUnavailable fail");
                    callBack.connnectResult(false);
                }
            };
            connectivityManager.requestNetwork(request, networkCallback);

 

 

 

 

 

 

2 分析

我们查看竞品 "茄子快传",发现Android10.0设备通过热点名字和密码连接另外一台设置指定热点,然后连接成功后可以正常通信,我们先用jadx反编译茄子代码,然后搜索上面官方API的关键字WifiNetworkSpecifier

 Android之解决Android10.0通过热点名字和密码连接指定热点网络不能通信问题_第1张图片

 没有搜索到,然后我们用官方的10.0API也会让手机弹出提示,让用户同意,但是竞品没有这个提示,就说明它用的不是这个方式连接指定热点的,但是依然可以连接上后正常通信,我们分析是不是用了其它特殊方式,我们打开竞品扫描二维码,然后抓当前进程打印的日志

adb shell ps | grep share
adb logcat | grep pid

依然没有发现什么线索,然后就全局搜索关键字enableNetwork

Android之解决Android10.0通过热点名字和密码连接指定热点网络不能通信问题_第2张图片

也就只有这几处,然后我们就再到网上找为什么Android10.0设备enableNetwork 返回-1

 Android之解决Android10.0通过热点名字和密码连接指定热点网络不能通信问题_第3张图片

 

这里可以看出把targetSdkVersion调整成28就可以了,我们不用29的API,同时我们也猜测竞品“茄子快传”也是用的这种方式绕过去的

查看AndroidManifest.xml,果不其然。

 

 

 

 

 

3 解决办法

暂时降低targetSdkVersion的本版为28,暂时绕过去,用低版本连接代码连接网络,我自己测试部分Android10.0的手机,的确没问题,但是APP需要谷歌上架,到时候会强制升级到29,到时候再说,说不定Android11出来这个问题就自然而然解决了。

   /**
     * 创建 WifiConfiguration,这里创建的是wpa2加密方式的wifi
     *
     * @param ssid     wifi账号
     * @param password wifi密码
     * @return
     */
    public static WifiConfiguration createWifiInfo(String ssid, String password) {
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + ssid + "\"";
        if(TextUtils.isEmpty(password)) {
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            Log.i(TAG, "password is ''");
            return config;
        }
        config.preSharedKey = "\"" + password + "\"";
        config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
        config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
        config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
        config.status = WifiConfiguration.Status.ENABLED;
        return config;
    }

    public interface CallBack {
        void connnectResult(boolean connectResult);
    }

    /**
     * 通过热点用户名和密码连接热点
     * @param context
     * @param wifiApName
     * @param password
     * @param handler
     */
    public static void connectWifiApByNameAndPwd(Context context, String wifiApName, String password, CallBack callBack) {
        if (context == null || callBack == null) {
            Log.i(TAG, "context == null || callBack == null");
            return;
        }
        if (TextUtils.isEmpty(wifiApName)) {
            Log.i(TAG, "TextUtils.isEmpty(wifiApName)");
            callBack.connnectResult(false);
            return;
        }
        WifiManager mWifiManager = (WifiManager) context.getSystemService(WIFI_SERVICE);
            WifiConfiguration wifiNewConfiguration = createWifiInfo(wifiApName, password);//使用wpa2的wifi加密方式
            int newNetworkId = mWifiManager.addNetwork(wifiNewConfiguration);
            if (newNetworkId == -1) {
                Log.i(TAG, "操作失败,需要您到手机wifi列表中取消对设备连接的保存");
                callBack.connnectResult(false);
                return;
            }
            Log.i(TAG, "newNetworkId is:" + newNetworkId);
            // 如果wifi权限没打开(1、先打开wifi,2,使用指定的wifi
            if (!mWifiManager.isWifiEnabled()) {
                mWifiManager.setWifiEnabled(true);
            }
            boolean enableNetwork = mWifiManager.enableNetwork(newNetworkId, true);
            if (!enableNetwork) {
                Log.i(TAG, "切换到指定wifi失败");
                callBack.connnectResult(false);
                return;
            }
            Log.i(TAG, "切换到指定wifi成功");
            callBack.connnectResult(true);
    }

 

你可能感兴趣的:(Android,进阶)