android6.0 wifi连接

来源:互联网 发布:如何把淘宝微信群做大 编辑:程序博客网 时间:2024/05/02 01:06

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 = return "\"" + selScanResult.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>
添加示例代码如下:

<span style="font-family:SimSun;font-size:14px;background-color: rgb(255, 255, 255);">        int wifiAdd = mWifiManager.addNetwork(config);        if(wifiAdd < 0){    //failed        }else {            //sucess          }</span>
这个,整个wifi的连接过程就做完了。







3 0
原创粉丝点击