国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android連接指定Wifi的方法實例代碼

2019-12-12 03:19:05
字體:
來源:轉載
供稿:網友

本篇文章主要記錄一下Android中打開Wifi、獲取Wifi接入點信息及連接指接入點的方法。

自己寫的demo主要用于測試接口的基本功能,因此界面及底層邏輯比較粗糙。

demo的整體界面如下所示:

上圖中的OPEN按鍵負責開啟Wifi;

GET按鍵負責獲取掃描到的接入點信息。

當獲取到接入點信息后,我選取了其中的名稱及信號強度,以列表的形式顯示在主界面下方,如下圖:

當點擊列表中的Item時,就會去連接對應的接入點。
自己的邏輯比較簡單,測試時的代碼,假定連接的是不許要密碼或密碼已知的接入點。

demo的布局文件就不介紹了,就是Button和RecyclerView。
主要記錄一下,使用到的核心代碼。

 ....................  //Open按鍵點擊后的邏輯  mOpenWifiButton.setOnClickListener(new View.OnClickListener() {   @Override   public void onClick(View v) {    //WifiManager的isWifiEnabled接口,用于判斷Wifi開關是否已經開啟    if (!mWifiManager.isWifiEnabled()) {     //setWifiEnabled接口用于開啟Wifi     mWifiManager.setWifiEnabled(true);     mMainHandler.post(mMainRunnable);    }   }  });  ....................

mMainRunnable的代碼如下,主要用于判斷Wifi是否開啟成功。

................ private Runnable mMainRunnable = new Runnable() {  @Override  public void run() {   if (mWifiManager.isWifiEnabled()) {    //開啟成功后,使能Get按鍵    mGetWifiInfoButton.setEnabled(true);   } else {    mMainHandler.postDelayed(mMainRunnable, 1000);   }  } }; ..............

這部分代碼,主要使用了WifiManager的公有接口,開啟Wifi開關及判斷開啟狀態。
這部分操作需要的權限是:

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

Get按鍵被點擊后,對應的代碼如下:

.................  mGetWifiInfoButton.setOnClickListener(new View.OnClickListener() {   @Override   public void onClick(View v) {    if (mWifiManager.isWifiEnabled()) {     //getScanResults接口將返回List<ScanResult>     //ScanResult中保留了每個接入點的基本信息     mScanResultList = mWifiManager.getScanResults();     //多個接入點可能攜帶相同的信息,形成一個整體的Wifi覆蓋網絡     //因此,篩除一些冗余信息     sortList(mScanResultList);     //我使用的是RecyclerView,得到數據后,刷新界面進行顯示     mWifiInfoRecyclerView.getAdapter().notifyDataSetChanged();    }   }  });  .................

上面這部分代碼也比較簡單,主要利用WifiManager的getScanResults接口,獲取終端探索到的接入點信息。
其中,sortList的代碼如下:

 .............. private void sortList(List<ScanResult> list) {  TreeMap<String, ScanResult> map = new TreeMap<>();  //demo中僅按照SSID進行篩選  //實際使用時,還可以參考信號強度等條件  for (ScanResult scanResult : list) {   map.put(scanResult.SSID, scanResult);  }  list.clear();  list.addAll(map.values()); } .............

這部分代碼唯一需要注意的地方是,需要申明權限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

同時,在高版本中還需要主動獲取運行時權限。

權限的要求,是由WifiServiceImpl的實現決定的,我們以Android 7.0為例,看看對應的代碼:

public List<ScanResult> getScanResults(String callingPackage) { //這里要求的是ACCESS_WIFI_STATE enforceAccessPermission(); ............ try {  ...........  if (!canReadPeerMacAddresses && !isActiveNetworkScorer    //在checkCallerCanAccessScanResults中檢查了ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION    //如果沒有這兩個權限,就會返回一個empty List    && !checkCallerCanAccessScanResults(callingPackage, uid)) {   return new ArrayList<ScanResult>();  }  ........... } fianlly {  .......... }}

獲取到信息后,就可以顯示和點擊列表中的Item了。

由于自己使用的是RecyclerView,因此這部分工作全部交給了對應ViewHolder:

 ............... private class ScanResultViewHolder extends RecyclerView.ViewHolder {  private View mView;  private TextView mWifiName;  private TextView mWifiLevel;  ScanResultViewHolder(View itemView) {   super(itemView);   mView = itemView;   mWifiName = (TextView) itemView.findViewById(R.id.ssid);   mWifiLevel = (TextView) itemView.findViewById(R.id.level);  }  void bindScanResult(final ScanResult scanResult) {   //將接入點的名稱和強度顯示到界面上   mWifiName.setText(     getString(R.string.scan_wifi_name, "" + scanResult.SSID));   mWifiLevel.setText(     getString(R.string.scan_wifi_level, "" + scanResult.level));   //點擊Item后,就連接對應的接入點   mView.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {     //createWifiConfig主要用于構建一個WifiConfiguration,代碼中的例子主要用于連接不需要密碼的Wifi     //WifiManager的addNetwork接口,傳入WifiConfiguration后,得到對應的NetworkId     int netId = mWifiManager.addNetwork(createWifiConfig(scanResult.SSID, "", WIFICIPHER_NOPASS));     //WifiManager的enableNetwork接口,就可以連接到netId對應的wifi了     //其中boolean參數,主要用于指定是否需要斷開其它Wifi網絡     boolean enable = mWifiManager.enableNetwork(netId, true);     Log.d("ZJTest", "enable: " + enable);     //可選操作,讓Wifi重新連接最近使用過的接入點     //如果上文的enableNetwork成功,那么reconnect同樣連接netId對應的網絡     //若失敗,則連接之前成功過的網絡     boolean reconnect = mWifiManager.reconnect();     Log.d("ZJTest", "reconnect: " + reconnect);    }   });  } } .................

以上就是連接指定Wifi的基本套路,從代碼中容易看出,關鍵問題是如何創建出有效的WifiConfiguration。
自己測試時,初始創建WifiConfiguration失敗,手機怎么都沒法連接到熱點上,后來修改后,基本功能終于能夠實現:

 .................... private static final int WIFICIPHER_NOPASS = 0; private static final int WIFICIPHER_WEP = 1; private static final int WIFICIPHER_WPA = 2; private WifiConfiguration createWifiConfig(String ssid, String password, int type) {  //初始化WifiConfiguration  WifiConfiguration config = new WifiConfiguration();  config.allowedAuthAlgorithms.clear();  config.allowedGroupCiphers.clear();  config.allowedKeyManagement.clear();  config.allowedPairwiseCiphers.clear();  config.allowedProtocols.clear();  //指定對應的SSID  config.SSID = "/"" + ssid + "/"";  //如果之前有類似的配置  WifiConfiguration tempConfig = isExist(ssid);  if(tempConfig != null) {   //則清除舊有配置   mWifiManager.removeNetwork(tempConfig.networkId);  }  //不需要密碼的場景  if(type == WIFICIPHER_NOPASS) {   config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);  //以WEP加密的場景  } else if(type == WIFICIPHER_WEP) {   config.hiddenSSID = true;   config.wepKeys[0]= "/""+password+"/"";   config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);   config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);   config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);   config.wepTxKeyIndex = 0;  //以WPA加密的場景,自己測試時,發現熱點以WPA2建立時,同樣可以用這種配置連接  } else if(type == WIFICIPHER_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; } ................. private WifiConfiguration isExist(String ssid) {  List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();  for (WifiConfiguration config : configs) {   if (config.SSID.equals("/""+ssid+"/"")) {    return config;   }  }  return null; } .................

自己寫完demo后,以一個手機建立熱點,分別測試了有密碼和無密碼的場景(對應的,需要修改createWifiConfig的傳入參數)。

發現demo運行的手機在兩種場景下,均能夠連接到指定熱點。

Demo地址如下:

https://github.com/ZhangJianIsAStark/Demos/tree/master/wifitest

在本文的最后,補充一下終端作為熱點時的接口。

public boolean isWifiApEnabled()

具有@SystemApi、@hide注解的公有接口,判斷手機的熱點是否開啟。

在Android 5.1之前,這個接口沒有@SystemApi注解,

于是有很多代碼會利用Java發射機制,獲取該方法并判斷手機熱點是否開啟。

現在那些老代碼已經沒法使用了。

現在的做法(以5.1以上為例),應該利用廣播接收器監聽WifiManager中定義的WIFI_AP_STATE_CHANGED_ACTION。

注意到該Action也有@SystemApi注解,所以要直接監聽對應的字符串,示例如下(上面鏈接中的demo也有涉及):

................... private BroadcastReceiver mBroadcastReceiver; private void registerBroadcastReceiver() {  mBroadcastReceiver = new BroadcastReceiver() {   @Override   public void onReceive(Context context, Intent intent) {    //收到廣播后,利用"wifi_state"的字段,得到AP的狀態    int state = intent.getIntExtra("wifi_state", 11);    Log.d("ZJTest", "AP state: " + state);   }  };  IntentFilter intentFilter = new IntentFilter();  //添加Action對應的字符信息  intentFilter.addAction("android.net.wifi.WIFI_AP_STATE_CHANGED");  this.registerReceiver(mBroadcastReceiver, intentFilter); } ......... private void unregisterBroadcastReceiver() {  this.unregisterReceiver(mBroadcastReceiver); } ..........

我暫時沒有深究Wifi模塊開啟AP的流程。

不過從自己的測試結果來看,Wifi開啟或關閉AP時,推測發送的應該是Sticky類型的廣播。

于是,只要APK注冊了廣播監聽器,立馬就會得到回復,明白當前AP的狀態。

例如,我在開啟AP后,再打開自己的測試Demo,立馬會收到如下信息:

//對應WIFI_AP_STATE_ENABLED,定義于WifiManager中,@SystemApi02-20 17:48:52.470 12773-12773/? D/ZJTest: AP state: 13

手動關閉AP后可以得到如下結果:

//WIFI_AP_STATE_DISABLING02-20 17:49:35.803 12773-12773/stark.a.is.zhang.wifitest D/ZJTest: AP state: 10//WIFI_AP_STATE_DISABLED02-20 17:49:36.960 12773-12773/stark.a.is.zhang.wifitest D/ZJTest: AP state: 11
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig)public WifiConfiguration getWifiApConfiguration()

@SystemApi,設置和獲取Wifi-AP的配置信息。

可以看出不論手機作為AP還是STA,在Framework中均利用WifiConfiguration抽象對應的配置信息,包括鑒權算法、密碼、SSID、協議等。

這種設計是符合802.11協議精神的,畢竟在物理設備的角度上,AP和STA是完全對等的。只不過在實際情況中,根據各自的需求,特質化了一些組件。

實際上從底層協議來看,僅在傳輸這個角度上,AP和STA的主要區別僅在于收到數據幀后的處理流程不同。AP收到數據幀后,發現目的地址不是自己,就會進入轉發流程;而STA可能就直接丟棄該數據幀了。當然如果從控制的角度來看,即考慮通信信令,AP和STA還是主從的關系。

public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)

@SystemApi,改變Wifi-AP的開關狀態。開啟的AP,將使用參數定義的WifiConfiguration信息。

可以看出,手機熱點對應接口全部變成了SystemApi,因此在android的高版本上,應用基本上是無法再操作熱點了。

以上所述是小編給大家介紹的Android連接指定Wifi的方法實例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 葫芦岛市| 新丰县| 安化县| 三河市| 张掖市| 寻乌县| 保靖县| 乐安县| 凤翔县| 资源县| 罗平县| 石首市| 丹东市| 隆化县| 策勒县| 南丹县| 昭觉县| 凌海市| 双柏县| 吉木萨尔县| 竹北市| 呼和浩特市| 凤冈县| 林西县| 左权县| 濮阳市| 邵武市| 抚顺市| 团风县| 大渡口区| 土默特左旗| 荣成市| 韶关市| 芦山县| 台江县| 额济纳旗| 琼中| 军事| 黄冈市| 合江县| 星座|