Skip to content

Android 扫描WiFi,连接WiFi

  • win7
  • Android Studio 3.0.1

概述

在Android应用中扫描WiFi热点。并把搜索到的WiFi热点信息显示出来。
连接、切换到指定的WiFi。

申请权限

申请网络和WiFi相关的权限

    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

需要动态申请定位权限,否则获取不到WiFi的搜索结果

WiFi信息扫描

使用WifiManager.startScan()方法开始搜索WiFi信息。 收取广播WifiManager.SCAN_RESULTS_AVAILABLE_ACTION获得搜索结果。搜索结果是ScanResult类。

private WifiManager mWifiManager;

// 在Fragment中获取WifiManager
mWifiManager = (WifiManager) getActivity().getApplication().getApplicationContext().getSystemService(Context.WIFI_SERVICE);

// 启动搜索
if (!mWifiManager.isWifiEnabled()) {
    mWifiManager.setWifiEnabled(true);
}
mWifiManager.startScan();

注册广播,获取WiFi搜索结果

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
                List<ScanResult> scanResults = mWifiManager.getScanResults();
                // 获取到结果后进行其他操作...
            }
        }
    };

将WiFi搜索结果显示出来

使用RecyclerView显示搜索到的结果。提供选择功能。

/**
 * WiFi搜索
 * Created by Rust on 2018/5/18.
 */
public class WiFiScanFragment extends Fragment {
    private static final String TAG = "WiFiScanFragment";
    public static final String F_TAG = "f_tag_WiFiScanFragment";
    private View mTipLayout;
    private Button mRefreshWiFiBtn;
    private EditText mWiFiPrefixEt;
    private String mWiFiPrefix = "";
    private WifiManager mWifiManager;
    private WiFiReAdapter mWiFiReAdapter;
    private TextView mChosenInfoTv;

    public static WiFiScanFragment newFrag() {
        return new WiFiScanFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mWifiManager = (WifiManager) getActivity().getApplication().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        getActivity().registerReceiver(mBroadcastReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
        Log.d(TAG, "onCreate: 注册广播");
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.frag_numbers_upgrade, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mTipLayout = view.findViewById(R.id.tip_layout);
        mRefreshWiFiBtn = view.findViewById(R.id.refresh_wifi_btn);
        mWiFiPrefixEt = view.findViewById(R.id.wifi_prefix_et);
        mChosenInfoTv = view.findViewById(R.id.chosen_info_tv);
        view.findViewById(R.id.top_back_iv).setOnClickListener(mOnClickListener);
        view.findViewById(R.id.top_end_iv).setOnClickListener(mOnClickListener);
        view.findViewById(R.id.choose_all_btn).setOnClickListener(mOnClickListener);
        view.findViewById(R.id.choose_none_btn).setOnClickListener(mOnClickListener);
        view.findViewById(R.id.choose_revert_btn).setOnClickListener(mOnClickListener);

        mRefreshWiFiBtn.setOnClickListener(mOnClickListener);
        RecyclerView wifiRv = view.findViewById(R.id.wifi_rv);
        mWiFiReAdapter = new WiFiReAdapter();
        wifiRv.setAdapter(mWiFiReAdapter);
        wifiRv.setLayoutManager(new GridLayoutManager(getActivity(), 3));
        mWiFiReAdapter.setOnItemClickListener(mOnItemClickListener);
        mWiFiPrefixEt.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                mWiFiPrefix = s.toString();
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        getActivity().unregisterReceiver(mBroadcastReceiver);
        Log.d(TAG, "onDestroy: 销毁广播");
    }

    private View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.top_back_iv:
                    getActivity().finish();
                    break;
                case R.id.top_end_iv:
                    if (mTipLayout.getVisibility() != View.VISIBLE) {
                        mTipLayout.setVisibility(View.VISIBLE);
                    } else {
                        mTipLayout.setVisibility(View.GONE);
                    }
                    break;
                case R.id.refresh_wifi_btn:
                    if (!mWifiManager.isWifiEnabled()) {
                        mWifiManager.setWifiEnabled(true);
                    }
                    mWifiManager.startScan();
                    mRefreshWiFiBtn.setText("扫描中..");
                    ToastUtil.showShort(getActivity(), "开始扫描");
                    break;
                case R.id.choose_all_btn:
                    mWiFiReAdapter.chooseAll();
                    updateChosenNoteUI();
                    break;
                case R.id.choose_none_btn:
                    mWiFiReAdapter.chooseNone();
                    updateChosenNoteUI();
                    break;
                case R.id.choose_revert_btn:
                    mWiFiReAdapter.chooseRevert();
                    updateChosenNoteUI();
                    break;
            }
        }
    };

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
                List<ScanResult> scanResults = mWifiManager.getScanResults();
                mWiFiReAdapter.clearList();
                String lowerPrefix = mWiFiPrefix.toLowerCase();
                ToastUtil.showShort(getActivity(), "扫描结束");
                mRefreshWiFiBtn.setText("刷新");
                for (ScanResult s : scanResults) {
//                    Log.d(TAG, "onReceive: " + s);
                    if (!TextUtils.isEmpty(s.SSID) && s.SSID.toLowerCase().startsWith(lowerPrefix)) {
                        mWiFiReAdapter.addOrUpdateWiFiScanResult(s);
                    }
                }
                mWiFiReAdapter.notifyDataSetChanged();
                updateChosenNoteUI();
            }
        }
    };

    public void updateChosenNoteUI() {
        mChosenInfoTv.setText(String.format(Locale.CHINA, "已选:%d", mWiFiReAdapter.getChosenWiFi().size()));
    }

    private WiFiAdapterOnItemClickListener mOnItemClickListener = new WiFiAdapterOnItemClickListener() {
        @Override
        public void onItemClick(int pos) {
            mWiFiReAdapter.revertChosen(pos);
            updateChosenNoteUI();
        }
    };

    private class WiFiReAdapter extends RecyclerView.Adapter<WVH> {
        private WiFiAdapterOnItemClickListener onItemClickListener;
        private List<WiFiItem> wifiList;

        WiFiReAdapter() {
            wifiList = new ArrayList<>(20);
        }

        void setOnItemClickListener(WiFiAdapterOnItemClickListener listener) {
            this.onItemClickListener = listener;
        }

        void clearList() {
            wifiList.clear();
        }

        void addOrUpdateWiFiScanResult(ScanResult scanResult) {
            boolean has = false;
            for (WiFiItem item : wifiList) {
                if (item.scanResult.SSID.equals(scanResult.SSID)) {
                    has = true;
                    item.scanResult = scanResult;
                }
            }
            if (!has) {
                wifiList.add(new WiFiItem(scanResult));
            }
        }

        void chooseAll() {
            for (WiFiItem i : wifiList) {
                i.chosen = true;
            }
            notifyDataSetChanged();
        }

        void chooseNone() {
            for (WiFiItem i : wifiList) {
                i.chosen = false;
            }
            notifyDataSetChanged();
        }

        void chooseRevert() {
            for (WiFiItem i : wifiList) {
                i.chosen = !i.chosen;
            }
            notifyDataSetChanged();
        }

        void revertChosen(final int pos) {
            WiFiItem item = wifiList.get(pos);
            item.chosen = !item.chosen;
            notifyItemChanged(pos);
        }

        List<ScanResult> getChosenWiFi() {
            List<ScanResult> res = new ArrayList<>();
            for (WiFiItem item : wifiList) {
                if (item.chosen) {
                    res.add(item.scanResult);
                }
            }
            return res;
        }

        @Override
        public WVH onCreateViewHolder(ViewGroup parent, int viewType) {
            return new WVH(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_wifi, parent, false));
        }

        @Override
        public void onBindViewHolder(WVH holder, final int position) {
            final int pos = position;
            WiFiItem item = wifiList.get(pos);
            holder.ssidTv.setText(item.scanResult.SSID);
            holder.chosenCb.setChecked(item.chosen);
            holder.itemRoot.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (null != onItemClickListener) {
                        onItemClickListener.onItemClick(pos);
                    }
                }
            });
        }

        @Override
        public int getItemCount() {
            return wifiList.size();
        }
    }

    static class WiFiItem {
        boolean chosen = false;
        ScanResult scanResult;

        WiFiItem(ScanResult s) {
            scanResult = s;
        }
    }

    static class WVH extends RecyclerView.ViewHolder {
        View itemRoot;
        CheckBox chosenCb;
        TextView ssidTv;
        TextView noteTv;

        WVH(View itemView) {
            super(itemView);
            itemRoot = itemView;
            chosenCb = itemView.findViewById(R.id.chosen_cb);
            ssidTv = itemView.findViewById(R.id.ssid_tv);
            noteTv = itemView.findViewById(R.id.note_tv);
        }
    }

    public interface WiFiAdapterOnItemClickListener {
        void onItemClick(final int pos);
    }
}

连接WiFi

创建连接WiFi的帮助类;连接WiFi需要WifiManager

检查目标SSID是否已经被保存

    private static WifiConfiguration getExistsCfg(String SSID, final WifiManager wifiManager) {
        List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
        for (WifiConfiguration existingConfig : existingConfigs) {
            if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
                return existingConfig;
            }
        }
        return null;
    }

创建wpa加密的WiFi配置,接下来连接到这个WiFi需要这些信息

    private static WifiConfiguration createWpaWifiInfo(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 + "\"";
        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.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
        config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
        config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
        config.status = WifiConfiguration.Status.ENABLED;
        return config;
    }

连接到指定WiFiWifiConfiguration;如果wifiManager.addNetwork返回值是-1,表示操作失败

如果切换WiFi成功,会在广播中收到WifiManager.NETWORK_STATE_CHANGED_ACTION

    private static void connectToWiFi(WifiConfiguration config, final WifiManager wifiManager) {
        int wcgID = wifiManager.addNetwork(config);
        android.util.Log.d(TAG, LOG_PRE + "connectToWiFi: " + config.SSID + ";  res==" + wcgID);
        if (wcgID == -1) {
            android.util.Log.d(TAG, LOG_PRE + "操作失败");
        }
        boolean enRes = wifiManager.enableNetwork(wcgID, true);
        Log.d(TAG, LOG_PRE + "切换到WiFi: " + config.SSID + "; enable " + enRes);
    }

操作WiFi时,就像操作蓝牙一样,可能会需要自定义一些延时,给系统调用硬件设备一些时间。

public class NUHelper {
    private static final String TAG = "NU";
    private static final String LOG_PRE = "Helper - ";
    private static final String DEF_WIFI_PWD = "88888888";
    public static int mSwitchWiFiWaitMM = 3000; // 切换WiFi时等待的最小时间

    /**
     * 当前正在处理的WiFi
     */
    public static String mCurrSSID = ""; // 没有双引号包围

    /**
     * 连接等待池中的下一个WiFi
     */
    public synchronized static void connectToNext(final ScanResult scanResult, final WifiManager wifiManager) {
        mCurrSSID = scanResult.SSID;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(mSwitchWiFiWaitMM); // 等待WiFi操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                android.util.Log.d(TAG, LOG_PRE + "开始处理 " + mCurrSSID);
                WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                android.util.Log.d(TAG, LOG_PRE + "当前WiFi: " + wifiInfo.getSSID());
                if (wifiInfo.getSSID().equals("\"" + mCurrSSID + "\"")) {
                    android.util.Log.d(TAG, LOG_PRE + "是当前连接的WiFi " + mCurrSSID);
                    // 当前已经连接上了这个目标WiFi
                } else {
                    WifiConfiguration cfg = getExistsCfg(mCurrSSID, wifiManager);
                    if (null == cfg) {
                        android.util.Log.d(TAG, LOG_PRE + "没有连接过这个WiFi - " + mCurrSSID);
                        cfg = createWpaWifiInfo(mCurrSSID, DEF_WIFI_PWD);
                    } else {
                        android.util.Log.d(TAG, LOG_PRE + "之前连接过这个WiFi - " + mCurrSSID);
                    }
                    connectToWiFi(cfg, wifiManager);
                }
            }
        }).start();
    }
}

参考资料