美文网首页Android知识Android开发手机移动程序开发
《Android wifi系列文章三》核心控制类的编写

《Android wifi系列文章三》核心控制类的编写

作者: TrillGates | 来源:发表于2017-03-02 15:06 被阅读863次

《Android wifi系列文章三》核心控制类的编写

前面的话,我们分析了我们要编写的wifi管理器的业务,而核心的话就是这个wifi控制类了。这里的话,我们需要继续往下分析,继续细化这个 wifi控制器类的功能,具体到方法。我们按这个套路去分析就好!

好,回到我们的类分析上,看看我们这个类要负责什么功能能。这个是WifiController控制类,那么通过面向对象的思想去分析,我们可以知道所有跟wifi相关的业务,都需要封装到这个类里头吧。这样就好办了,我们具体看看这个类要干嘛吧!

  • 打开wifi

  • 关闭wifi

  • 扫描wifi

  • 获取扫描到的wifi列表

  • 判断wifi是否可用

  • 连接wifi

  • 删除wifi配置

然后再由上面的方法再推出别的方法,当然啦,这个需要知道api了。怎么样连接wifi,是吧!我们在连接wifi时,需要判断这个wifi有没有保存过密码呀,是否存在之类的....

其他的方法并不影响编程的思路。我们却敌确定了上面的方法,第一种原则是功能单一,如果有其他的需求是一个单一的功能,那么我们需要进行抽取。第二种则是只要有需要,不在上面主要方法负责范围内的,那么我们就需要进行抽取出来。第三个则是多个地方需要用到的,那么我们要把这些公共代码提取出来!

请看下面的代码吧,这个就是写好了的 WifiController控制类,已经写好了注释,如果后面不够 全的话,我们用到再添加就是了。那么这个类呢,是通用的。所以,在做wifi开发的时候,把这个类读一次,然后你就可以使用啦!

package cn.com.sunofbeaches.wifidemo;

import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
 
import java.lang.reflect.Method;
import java.util.List;
 
import cn.com.sunofbeaches.wifidemo.interfaces.InterfaceProxy;
import cn.com.sunofbeaches.wifidemo.interfaces.OnWifiConnectListener;
 
/**
 * Created by Administrator on 2017/2/27.
 * <p>
 * 这个类负责wifi的扫描,连接,断开
 * 判断wifi是否可用
 */
public class WifiController {
 
    private static final String TAG = "WifiController";
    private final WifiManager mWifiManager;
    private final Context mContext;
    private OnWifiConnectListener mOnWifiConnectListener;
 
    private WifiController(Context context) {
        //拿到wifi管理器
        mWifiManager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
        this.mContext = context;
    }
 
    private static WifiController sInstant = null;
 
    /**
     * 获取 一个单例对象
     *
     * @param context 上下文
     * @return 返回实例对象
     */
    public static WifiController getInstant(Context context) {
        if (sInstant == null) {
            synchronized (WifiController.class) {
                if (sInstant == null) {
                    sInstant = new WifiController(context);
                }
            }
        }
        return sInstant;
    }
 
    /**
     * 这个方法用于扫描周围的wifi
     */
    public void scanWifiAround() {
        if (!isWifiEnable()) {
            Toast.makeText(mContext, "wifi没有打开嘛...", Toast.LENGTH_SHORT).show();
            return;
        }
        mWifiManager.startScan();
    }
 
    /**
     * @return true表示wifi已经打开, false表示wifi没有打开, 状态为:
     * 打开中,或者关闭,或者关闭中...
     */
    public boolean isWifiEnable() {
        return mWifiManager.isWifiEnabled();
    }
 
    /**
     * 这个方法用于打开或关闭wifi
     * 当wifi打开的时候,那么就会关闭wifi
     * 当wifi关闭的时候,那么就会打开wifi
     */
    public void openOrCloseWifi() {
 
        //判断当前wifi的状态,是关闭还是打开
        if (this.isWifiEnable()) {
            mWifiManager.setWifiEnabled(false);
        } else {
            mWifiManager.setWifiEnabled(true);
        }
    }
 
    /**
     * @return 返回扫描的wifi结果, 是一个list集合
     * @call 当收到扫描结果的广播以后就可以调用这个方法去获取扫描结果
     */
    public List<ScanResult> getWifiScanResult() {
        return mWifiManager.getScanResults();
    }
 
    /**
     * @param SSID 这个是wifi的SSID
     * @return true表示已经存在了, 否则表示不存在
     */
 
    /**
     * 判断配置在系统中是否存在
     *
     * @param config 新的配置
     * @return 配置存在就更新配置,把新的配置返回,配置不存在就返回null
     */
    private WifiConfiguration isExists(WifiConfiguration config) {
        List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration existingConfig : existingConfigs) {
            Log.i(TAG, "系统保存配置的 SSID : " + existingConfig.SSID + "  networkId : " + existingConfig.networkId);
            if (existingConfig.SSID.equals(config.SSID)) {
                config.networkId = existingConfig.networkId;
                return config;
            }
        }
        return null;
    }
 
    /**
     * 获取NetworkId
     *
     * @param scanResult 扫描到的WIFI信息
     * @return 如果有配置信息则返回配置的networkId 如果没有配置过则返回-1
     */
    public int getNetworkIdFromConfig(ScanResult scanResult) {
        String SSID = String.format("\"%s\"", scanResult.SSID);
        List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
 
        for (WifiConfiguration existingConfig : existingConfigs) {
            if (existingConfig.SSID.equals(SSID)) {
                return existingConfig.networkId;
            }
        }
 
        return -1;
    }
 
 
    /**
     * 通过密码连接到WIFI
     *
     * @param scanResult 要连接的WIFI
     * @param pwd        密码
     * @param listener   连接的监听
     */
    public void connectionWifiByPassword(@NonNull ScanResult scanResult, @Nullable String pwd, @NonNull OnWifiConnectListener listener) {
        // SSID
        String SSID = scanResult.SSID;
        // 加密方式
        SecurityMode securityMode = getSecurityMode(scanResult);
 
        // 生成配置文件
        WifiConfiguration addConfig = createWifiConfiguration(SSID, pwd, securityMode);
        int netId;
        // 判断当前配置是否存在
        WifiConfiguration updateConfig = isExists(addConfig);
        if (null != updateConfig) {
            // 更新配置
            netId = mWifiManager.updateNetwork(updateConfig);
        } else {
            // 添加配置
            netId = mWifiManager.addNetwork(addConfig);
        }
        // 通过NetworkID连接到WIFI
        connectionWifiByNetworkId(SSID, netId, listener);
    }
 
 
    /**
     * 这个枚举用于表示网络加密模式
     */
    public enum SecurityMode {
        OPEN, WEP, WPA, WPA2
    }
 
 
    /**
     * 获取WIFI的加密方式
     *
     * @param scanResult WIFI信息
     * @return 加密方式
     */
    public SecurityMode getSecurityMode(@NonNull ScanResult scanResult) {
        String capabilities = scanResult.capabilities;
        if (capabilities.contains("WPA")) {
            return SecurityMode.WPA;
        } else if (capabilities.contains("WEP")) {
            return SecurityMode.WEP;
        } else if (capabilities.contains("WPA2")) {
            return SecurityMode.WPA2;
        } else {
            // 没有加密
            return SecurityMode.OPEN;
        }
    }
 
 
    /**
     * 生成新的配置信息 用于连接Wifi
     *
     * @param SSID     WIFI名字
     * @param password WIFI密码
     * @param mode     WIFI加密类型
     * @return 配置
     */
    private WifiConfiguration createWifiConfiguration(String SSID, String password, SecurityMode mode) {
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + SSID + "\"";
        if (mode == SecurityMode.OPEN) {
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        } else if (mode == SecurityMode.WEP) {
            config.hiddenSSID = true;
            config.wepKeys[0] = "\"" + password + "\"";
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;
        } else if (mode == SecurityMode.WPA) {
            config.preSharedKey = "\"" + password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            config.status = WifiConfiguration.Status.ENABLED;
        }
        return config;
    }
 
 
    /**
     * 通过NetworkId连接到WIFI (配置过的网络可以直接获取到NetworkID,从而不用再输入密码)
     *
     * @param SSID      WIFI名字
     * @param networkId NetworkId
     * @param listener  连接的监听
     */
    public void connectionWifiByNetworkId(@NonNull String SSID, int networkId, @NonNull OnWifiConnectListener listener) {
 
        // 连接的回调监听
        mOnWifiConnectListener = listener;
        // 连接开始的回调
        mOnWifiConnectListener.onStart(SSID);
        /*
         * 判断 NetworkId 是否有效
         * -1 表示配置参数不正确,我们获取不到会返回-1.
         */
        if (-1 == networkId) {
            // 连接WIFI失败
            if (null != mOnWifiConnectListener) {
                // 配置错误
                mOnWifiConnectListener.onFailure(SSID);
                // 连接完成
                mOnWifiConnectListener.onFinish();
                mOnWifiConnectListener = null;
            }
            return;
        }
        // 获取当前的网络连接
        WifiInfo wifiInfo = getConnectionInfo();
        if (null != wifiInfo) {
            // 断开当前连接
            boolean isDisconnect = disconnectWifi(wifiInfo.getNetworkId());
            if (!isDisconnect) {
                // 断开当前网络失败
                if (null != mOnWifiConnectListener) {
                    // 断开当前网络失败
                    mOnWifiConnectListener.onFailure(SSID);
                    // 连接完成
                    mOnWifiConnectListener.onFinish();
                    mOnWifiConnectListener = null;
                }
                return;
            }
        }
 
        // 连接WIFI
        boolean isEnable = mWifiManager.enableNetwork(networkId, true);
        if (!isEnable) {
            // 连接失败
            if (null != mOnWifiConnectListener) {
                // 连接失败
                mOnWifiConnectListener.onFailure(SSID);
                // 连接完成
                mOnWifiConnectListener.onFinish();
                mOnWifiConnectListener = null;
            }
        }
    }
 
 
    /**
     * @param ssid 可以理解为是wifi的名字
     * @return 反回的是wifi配置对象
     */
    public WifiConfiguration getConfBySSID(String ssid) {
 
        List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration existingConfig : configuredNetworks) {
            Log.i(TAG, "系统保存配置的 SSID : " + ssid);
            if (existingConfig.SSID.equals(ssid)) {
                return existingConfig;
            }
        }
 
        return null;
    }
 
    /**
     * 获取当前正在连接的WIFI信息
     *
     * @return 当前正在连接的WIFI信息
     */
    public WifiInfo getConnectionInfo() {
        try {
            return mWifiManager.getConnectionInfo();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
 
    /**
     * 断开WIFI
     *
     * @param netId netId
     * @return 是否断开
     */
    public boolean disconnectWifi(int netId) {
        boolean isDisable = mWifiManager.disableNetwork(netId);
        boolean isDisconnect = mWifiManager.disconnect();
        return isDisable && isDisconnect;
    }
 
 
    /**
     * 关闭Wifi
     */
    public void closeWifi() {
        if (mWifiManager.isWifiEnabled()) {
            mWifiManager.setWifiEnabled(false);
        }
    }
 
 
    public void forget(int netId, InterfaceProxy listener) {
 
 
        //有部分码友说这使用删除的方式有时候会出现问题,后来去翻看了一下android设置里的源码。
        //是需是直接掉调用forget方法来删除指写的wifi配置的
 
        //但是这个方法是藏起来的方法,我们可以看到前面会有一个@hide方法
 
        /**
         * Delete the network in the supplicant config.
         *
         * This function is used instead of a sequence of removeNetwork()
         * and saveConfiguration().
         *
         * @param config the set of variables that describe the configuration,
         *            contained in a {@link WifiConfiguration} object.
         * @param listener for callbacks on success or failure. Can be null.
         * @throws IllegalStateException if the WifiManager instance needs to be
         * initialized again
         * @hide
         */
//        public void forget(int netId, ActionListener listener) {
//            if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
//            validateChannel();
//            sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
//        }
 
 
        //那问题又来了,那个ActionListener前面又有一个@hide
        //哈哈哈!
 
        /**
         * Interface for callback invocation on an application action
         * @hide
         */
//        public interface ActionListener {
        /** The operation succeeded */
//            public void onSuccess();
        /**
         * The operation failed
         * @param reason The reason for failure could be one of
         * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
         */
//            public void onFailure(int reason);
//        }
 
 
        //所以这里面我们就要这样子做了
        //这部分代码是通过反射的方法去获取到ActionListener这个类的字节码对象
        Class<?> actionListenerClazz = null;
        try {
            actionListenerClazz = Class.forName("android.net.wifi.WifiManager$ActionListener");
            Log.d(TAG, "name == " + actionListenerClazz.getName());
            Method[] declaredMethods = actionListenerClazz.getDeclaredMethods();
            Log.d(TAG, "method Size == " + declaredMethods.length);
            //这些输出,只是为了验证我们拿到的是对的哦!
            for (int i = 0; i < declaredMethods.length; i++) {
                Log.d(TAG, "mohtod Name == " + declaredMethods[i].getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
 
        if (actionListenerClazz == null) {
            throw new RuntimeException("fail to get ActionListener...");
        }
 
        Class<? extends WifiManager> wifiClazz = mWifiManager.getClass();
        try {
            Method forget = wifiClazz.getDeclaredMethod("forget", int.class, actionListenerClazz);
            Log.d(TAG, "method name == " + forget);
            //执行方法
            forget.invoke(mWifiManager, new Object[]{netId, listener});
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "e == " + e);
        }
 
 
        //如果是直接放在系统中编译的话,那么直接是调用wifiManager里的forget方法即可
 
 
    }
 
 
}

这里面的话,代码比较多。但是逻辑比较简单的,而注释也比较全。如果有什么疑问的话,可以在下面留言。

难点的地方可能就是那个forget那里,如果对反射不熟悉的同学,去补习一下哈!后面我也会写写这方面的文章吧!

如果反馈比较多的话,我可以把wifi管理器整个小Demo录制成一个视频吧。

没完,下面还会继续有,然后是把不有完成的代码写完。之后会给大家代码的哇!

转载请说明出处,本文地址:
http://bbs.sunofbeaches.com/thread-5765-1-1.html

相关文章

网友评论

    本文标题:《Android wifi系列文章三》核心控制类的编写

    本文链接:https://www.haomeiwen.com/subject/nozhgttx.html