我正在使用AlarmManager发布的PendingIntent(使用setRepeating)每隔几分钟启动WiFi扫描(使用IntentService).
在大多数设备上,在大多数情况下,没有问题.
但是,在几个设备上,我收到以下错误(无法在任何测试设备上重现错误,这是用户设备的崩溃日志):
在大多数设备上,在大多数情况下,没有问题.
但是,在几个设备上,我收到以下错误(无法在任何测试设备上重现错误,这是用户设备的崩溃日志):
java.lang.RuntimeException: Unable to start service com.myapp.android.service.MyService@44a9701 with Intent { act=com.myapp.android.ACTION_PERFORM_WIFI_SCAN flg=0x4 cmp=com.myapp/com.mayapp.android.service.MyService (has extras) }: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3021) at android.app.ActivityThread.-wrap17(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1443) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5415) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:725) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:615) Caused by: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS at android.os.Parcel.readException(Parcel.java:1599) at android.os.Parcel.readException(Parcel.java:1552) at android.net.wifi.IWifiManager$Stub$Proxy.startScan(IWifiManager.java:1045) at android.net.wifi.WifiManager.startScan(WifiManager.java:1088) ...
我正在从我的应用程序创建PendingIntent,所以我看不到从WifiManager抛出的SecurityException的原因(特别是因为这很少发生).
从PendingIntent代码启动的IntentService如下:
mContext.registerReceiver(mWifiScanReceiver,new IntentFilter( WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); boolean ok = mWifiManager.startScan();
关于什么可能导致这个的任何想法?
解决方法
这是因为android m的新应用权限.
看到上面的注释wifimanager的getScanResults()的源代码api 23-
看到上面的注释wifimanager的getScanResults()的源代码api 23-
/** * Return the results of the latest access point scan. * @return the list of access points found in the most recent scan. An app must hold * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission * in order to get valid results. */ public List<ScanResult> getScanResults() { try { return mService.getScanResults(mContext.getOpPackageName()); } catch (RemoteException e) { return null; } }
因此,您必须向用户询问运行时的权限.将这些权限放在您的清单中 –
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
从api 23起,您需要访问用户位置才能使用它.我建议您只有在授予权限的情况下才会使用基于api级别的权限检查和启动意图.
像这样的东西 –
if (Build.VERSION.SDK_INT >= 23) { int hasReadLocationPermission = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION); if (hasReadLocationPermission != PackageManager.PERMISSION_GRANTED) { if (!ActivityCompat.shouldShowRequestPermissionRationale(HomeActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)) { showMessageOKCancel("You need to allow access to GPS",new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog,int which) { ActivityCompat.requestPermissions(HomeActivity.this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},GPS_ENABLE_REQUEST); } }); return; } ActivityCompat.requestPermissions(HomeActivity.this,GPS_ENABLE_REQUEST); return; } if (locationManager != null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { gotoGPSEnableScreen(); } else { //Permissions granted and gps is on launchService(true); } }
进一步检查结果 –
@Override public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) { switch (requestCode) { case GPS_ENABLE_REQUEST: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { gotoGPSEnableScreen(); } } else { launchService(false); } default: return; } }
更新:
android.permission.INTERACT_ACROSS_USERS_FULL是一个签名级别的权限.
只需在你的清单中添加这个android:protectionLevel =“signature”.
有关详细信息,您可以查看这一点
http://developer.android.com/guide/topics/manifest/permission-element.html
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>