您的位置:首页 > 移动开发 > Android开发

android6.0 wifi连接

2016-07-07 20:48 393 查看
Android6.0Wifi连接过程基本和之前的版本一致,但是,在获取附近热点的时候,却出现了一些差别,这差别主要包括获取权限的方式发生了改变,以及getScanResults这个函数有点怪异的行为...

1.android6.0之前的版本获取附近的wifi热点

1.1打开和关闭wifi

setWifiEnabled(true/false);

1.2扫描附近热点

startScan();之后,接受WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的广播会触发,在这个广播中调用getScanResults()方法可以获得一个List<ScanResult>,它里面的每一个条目就是一个可连接的热点。

1.3代码

<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">public class MainActivity extends AppCompatActivity {
WifiManager wifi;
int size = 0;
List<ScanResult> results;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifi.isWifiEnabled() == false)
{
Toast.makeText(getApplicationContext(), "wifi is disabled..making it enabled", Toast.LENGTH_LONG).show();
wifi.setWifiEnabled(true);
Log.d("hello","wifi enabled");
}
wifi.startScan();
registerReceiver(new BroadcastReceiver()
{
@Override
public void onReceive(Context c, Intent intent)
{
results = wifi.getScanResults();
size = results.size();
for(int i=0;i<size;i++){
Log.d("hello",results.get(i).toString());
}
}
}, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
}</span>这样就可以打印出所有的可连接wifi信息。
总结来说第一步:setWifiEnabled(true);第二步:startScan();

2.android6.0获取wifi热点

然而同样的问题在android6.0中确实不可以的。原因有两个:

第一:没有权限

android6.0访问wifi新增了两个权限:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /></span>

android6.0之前,这两个权限在AndroidMenifest文件中声明就可以了,但是android6.0中,又增加了运行时权限。运行是权限这里不多说,总之,这两个权限是要运行时获取的,在Menifest文件中声明是行不通的。当然,为了不那么麻烦,你可以把targetSdkVersion 改为23以下,这样就不存在运行时权限的问题了。如果你不想这么做,那么不妨试试android6.0的运行时权限:
首先,检查有没有该权限:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> final int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 111;
private boolean checkPermission() {
Log.d("hello","checkPermission");
List<String> permissionsList = new ArrayList<String>();
String[] permission = new String[2];
if (checkSelfPermission( Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permission[0] = Manifest.permission.ACCESS_FINE_LOCATION;
}
if (checkSelfPermission( Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permission[1] = Manifest.permission.ACCESS_COARSE_LOCATION;
}
if(permission[0] != null || permission[1] != null){
Log.d("hello","regist Permission");
requestPermissions(permission,REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}</span>这个方法中使用checkSelfPermisson方法检查有没有对应权限,最后使用requestPermissions方法请求运行时权限。这会导致界面弹出一个询问框,问你要不要允许什么什么权限。最终请求对导致一个回调方法被调用:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
Log.d("hello","onRequestPermissionsResult");
switch (requestCode) {
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
if (permissions.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED ||
(permissions.length == 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&
grantResults[1] == PackageManager.PERMISSION_GRANTED)){
wifi.startScan();
Log.d("hello","permission allow");
Toast.makeText(this, "permission allow", Toast.LENGTH_LONG).show();
//list is still empty
}
else {
// Permission Denied
Toast.makeText(this, "permission deny", Toast.LENGTH_LONG).show();
Log.d("hello","permission deny");
}
break;
}
}</span>在这个方法中你可以知道你是不是获得了对应的权限。这两个文法之间有个纽带就是REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS,你在请求权限的时候传入,在回调函数中通过它判断自己的请求有没有成功。
一旦请求成功,那么你已经成功了第一步。

第二:GPS没有打开

(注意:如果你打开了的话就没有这个问题,这是android6.0很奇怪的一点) 
如果通过第一步,你获得了权限,可以是还是无法获取到附近的wifi热点,那么你不妨打开GPS试试。是的,就是这么神奇,打开后你就可以获得附近wifi热点了。那么,这到底是怎么回事呢?不妨看看getScanResults方法到底做了什么。
getScanResults是WifiManager中的一个方法,然后通过远程系统调用,调用到了WifiServiceImpl.java中的getScanResults方法,这个方法如下:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> public List<ScanResult> getScanResults(String callingPackage) {
enforceAccessPermission();
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
boolean canReadPeerMacAddresses = checkPeersMacAddress();
boolean isActiveNetworkScorer =
NetworkScorerAppManager.isCallerActiveScorer(mContext, uid);
boolean hasInteractUsersFull = checkInteractAcrossUsersFull();
long ident = Binder.clearCallingIdentity();
try {
if (!canReadPeerMacAddresses && !isActiveNetworkScorer
&& !isLocationEnabled() ) {
return new ArrayList<ScanResult>();
}
if (!canReadPeerMacAddresses && !isActiveNetworkScorer
&& !checkCallerCanAccessScanResults(callingPackage, uid)) {
return new ArrayList<ScanResult>();
}
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return new ArrayList<ScanResult>();
}
if (!isCurrentProfile(userId) && !hasInteractUsersFull) {
return new ArrayList<ScanResult>();
}
return mWifiStateMachine.syncGetScanResultsList();
} finally {
Binder.restoreCallingIdentity(ident);
}
}</span>
这个方法的try语句块中,首先第一个if中,它居然会判断:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">isLocationEnabled() </span>如果它是false,!isLocationEnabled 就为true,再加上前面两个对位true了,那么if里面的就会执行,然后就会返回一个空的List.
第二个if中则会判断权限:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_FINE_LOCATION, uid)
== PackageManager.PERMISSION_GRANTED
&& isAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) {
return true;
}

if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_COARSE_LOCATION, uid)
== PackageManager.PERMISSION_GRANTED
&& isAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid)) {
return true;
}
</span>可以看到他就是判断我们之前说的那两个权限,如果不想这么麻烦,统统把它们干掉也是可以的。这可能不是好主意,不过把对Location有没有使能的判断干掉是合理的,谁会在获取wifi热点信息的时候关注GPS有没有打开呢?google的这点设计真的很奇怪。

3.按照信号强弱排序

<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> public List<ScanResult> sortSSIDBySignalLevel(List<ScanResult> resultList){
List<ScanResult> wifiScanResults = new ArrayList<ScanResult>();
int length = resultList.size();
for (int i = 0; i < length; i++) {
for (int j = 0; j < length - i - 1; j++) {
boolean is2Swaped = false;
int lvl1 = resultList.get(j).level;
lvl1 = WifiManager
.calculateSignalLevel(lvl1, 7);
int lvl2 = resultList.get(j + 1).level;
lvl2 = WifiManager
.calculateSignalLevel(lvl2, 7);
if (lvl1 < lvl2) {
is2Swaped = true;
} else if (lvl1 == lvl2) {

String str1 = resultList.get(j).SSID;
String str2 = resultList.get(j + 1).SSID;
if (str1 != null && str2 != null
&& str1.compareToIgnoreCase(str2) > 0) {
is2Swaped = true;
} else if (str1 != null && str2 == null) {
is2Swaped = true;
}
}
if (is2Swaped) {
ScanResult temp = resultList.get(j);
resultList.set(j, resultList.get(j + 1));
resultList.set(j + 1, temp);
}
}
}
// key
wifiScanResults = resultList;
return wifiScanResults;
}</span>

4.连接wifi

wifi的连接主要使用WifiManager.addNetwork(WifiConfiguration config)方法。
因此,主要工作就是配置一个WifiConfiguration。主要配置项有:

4.1配置

1.configration.SSID

2.安全类型
2.1SECURITY_NONE,没有密码
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);</span>2.2SECURITY_WEP
配置密码:
config.wepKeys[0] = passwd;
配置安全类型之类的信息。
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);</span>2.3SECURITY_PSK
配置密码:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">config.preSharedKey = passwd;</span>配置安全类型:
<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);</span>

通过以上配置,即可调用WifiManager.addNetwork连接wifi。

4.2完整配置的示例

<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);"> private WifiConfiguration getNetConfig(){

WifiConfiguration configration = new WifiConfiguration();

String passwd = mPwdInput.getText().toString();
configration .SSID = "\"" + SSID + "\"";
switch(getSecurity(selScanResult.capabilities)){ case SECURITY_NONE: configration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); break; case SECURITY_WEP: if(passwd.equals("")){ return null; } if (passwd.length() != 0) { int length = passwd.length(); if ((length == 10 || length == 26 || length == 58) && passwd.matches("[0-9A-Fa-f]*")) { configration.wepKeys[0] = passwd; } else { configration.wepKeys[0] = "\"" + passwd + "\""; } } else{ return null; }configration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); configration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); configration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); break; case SECURITY_PSK: if(passwd.equals("")) { return null; } if (passwd.length() != 0) { if (passwd.matches("[0-9A-Fa-f]{64}")) { configration.preSharedKey = passwd; } else { configration.preSharedKey = "\"" + passwd + "\""; } }else{ return null; } configration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); break; default: break; }</span>添加示例代码如下:
int netId = wifiManager.addNetwork(wifiConfiguration);
if(netId>=0){
listViewConnectStatus("已保存");
}else {
Toast.makeText(WifiSettingsActivity.this,"保存失败",Toast.LENGTH_SHORT).show();
listViewConnectStatus("未保存");
}

if(!wifiManager.enableNetwork(netId,true)){
Log.d("test","enable network: "+netId+" failed");
}

这个,整个wifi的连接过程就做完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android wifi network 连接