用于蓝牙设备发现的BroadcastReceiver在一个设备上工作,但在另一个设备上不工作

时间:2016-06-05 05:08:10

标签: android bluetooth android-bluetooth discovery

代码:

我使用以下代码从here获取目标API级别23(以及最低API级别18)。

private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_FOUND.equals(action))
        {
            bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            deviceNameTextView.setText(bluetoothDevice.getName());
        }
    }
};

在按下按钮的事件中,我打电话:

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery(); // was initialized successsfully

我的AndroidManifest.xml包含:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

设备:

  1. 三星Galaxy S III(API级别18)
  2. Sony Xperia Z3(API级别23)
  3. 事实:

    • 两个设备都运行完全相同的代码
    • 设备1可以发现设备2(和任何其他蓝牙设备)
    • 设备2无法发现设备1(或任何其他蓝牙设备)
    • 两个设备都可以发现
    • 使用标准系统对话框测试可发现性,以便成功配对两个设备
    • 两个设备始终未配对(我不想配对)
    • 不会抛出异常。

    有什么问题?

    更新1: 由于可能必须在运行时请求API级别23权限。伊维特向我指出了这一点,谢谢!不幸的是,它没有解决我的问题。

    与她的理论有关的是:

    mBluetoothAdapter.startDiscovery()返回true,表示成功(请参阅here)。

    // Assume thisActivity is the current activity
    int permissionCheck = ContextCompat.checkSelfPermission(thisActivity , Manifest.permission.BLUETOOTH_ADMIN);
    
    if(permissionCheck == PackageManager.PERMISSION_GRANTED)
        Log.i("info", "Permission granted!");
    else
        Log.i("info", "Permission not granted!");
    

    使用BLUETOOTH_ADMINBLUETOOTH运行此代码会同时返回:

      

    获得许可!

3 个答案:

答案 0 :(得分:4)

在进行一些研究时,我在官方文档中找到了有关Android 6.0(API级别23)更改的following article

  

通过访问附近外部设备的硬件标识符   蓝牙和Wi-Fi扫描,您的应用程序现在必须具有   ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限:
   - WifiManager.getScanResults()
   - BluetoothDevice.ACTION_FOUND
   - BluetoothLeScanner.startScan()

因此,我一直缺少权限ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION。但仅仅在 AndroidManifest.xml 文件中添加它们是不够的。你必须像Yvette建议的那样在运行时请求这些权限。

您可以找到here如何做到这一点,或者只使用我编写的这段代码来获取蓝牙发现所需的权限。

final int CODE = 5; // app defined constant used for onRequestPermissionsResult

String[] permissionsToRequest =
{
    Manifest.permission.BLUETOOTH_ADMIN,
    Manifest.permission.BLUETOOTH,
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
};

boolean allPermissionsGranted = true;

for(String permission : permissionsToRequest)
{
    allPermissionsGranted = allPermissionsGranted && (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
}

if(!allPermissionsGranted)
{
    ActivityCompat.requestPermissions(this, permissionsToRequest, CODE);
}

mBluetoothAdapter.startDiscovery();

此代码假设用户授予权限(为简单起见)。如果您希望应用程序在未授予权限时表现不同,请参阅&#34;处理权限请求响应&#34;在此article

答案 1 :(得分:1)

听起来你并没有为sdk 23及更高版本管理runtime permissions。 sdk为23的手机将静默忽略任何需要运行时权限或崩溃的请求。

另请参阅文档System Permissions

  

如果您的应用在其清单中列出了正常权限(即,不会对用户的隐私或设备的操作造成太大风险的权限),系统会自动授予这些权限。如果您的应用在其清单中列出了危险权限(即可能会影响用户隐私或设备正常运行的权限),系统会要求用户明确授予这些权限。 Android发出请求的方式取决于系统版本以及应用所针对的系统版本:

     

如果设备运行的是Android 6.0(API级别23)或更高版本,并且应用程序的targetSdkVersion为23或更高,则应用程序会在运行时请求用户的权限。用户可以随时撤消权限,因此应用程序需要在每次运行时检查其是否具有权限。有关在应用程序中请求权限的详细信息,请参阅“使用系统权限”培训指南。   如果设备运行的是Android 5.1(API级别22)或更低版本,或者应用程序的targetSdkVersion为22或更低,系统会要求用户在用户安装应用程序时授予权限。如果您向应用程序的更新版本添加新权限,系统会要求用户在用户更新应用程序时授予该权限。用户安装应用程序后,他们撤销权限的唯一方法是卸载应用程序。   通常,权限失败会导致SecurityException被抛回应用程序。但是,并不能保证无处不在。例如,sendBroadcast(Intent)方法在方法调用返回后将数据传递给每个接收者时检查权限,因此如果存在权限失败,您将不会收到异常。但是,几乎在所有情况下,都会在系统日志中打印权限失败。

     

Android系统提供的权限可以在Manifest.permission中找到。任何应用程序也可以定义和强制执行自己的权限,因此这不是所有可能权限的综合列表。

     

在此期间,可能会在多个地方强制执行特定许可   你的程序的操作:

     
      
  • 在致电系统时,要阻止申请   执行某些功能。

  •   
  • 开始活动时,要防止   启动其他应用程序活动的应用程序。

  •   
  • 这两个   发送和接收广播,控制谁可以接收你的   广播或谁可以发送广播给你。

  •   
  • 访问和时   在内容提供商上运营。

  •   
  • 绑定或启动服务。

  •   

至于应用程序崩溃:

Everything every Android Developer must know about new Android's Runtime Permission

  

现在你头脑中的下一个问题。我的申请会崩溃吗?

     

通过Android团队从神发出的这种善意。当我们调用一个需要在targetSdkVersion小于23的应用程序上撤销权限用户的函数时,不会抛出任何异常。相反,它只是什么都不做。对于返回值的函数,它将返回null或0,具体取决于大小写。

     

但不要太高兴。虽然应用程序不会因调用函数而崩溃。它可能仍然可以从该应用程序下一步返回的值中崩溃。

这些答案中的更多详情Require dangerous permissions during installation When asking for runtime permission for location

答案 2 :(得分:0)

// Here, thisActivity is the current activity 
if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.BLUETOOTH) 
    != PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation? 
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
        Manifest.permission.BLUETOOTH)) { 

    // Show an expanation to the user *asynchronously* -- don't block 
    // this thread waiting for the user's response! After the user 
    // sees the explanation, try again to request the permission. 

} else { 

    // No explanation needed, we can request the permission. 

    ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.BLUETOOTH},
            MY_PERMISSIONS_REQUEST_BLUETOOTH // this variable should be a unique int identifier of your chosing); 

    // MY_PERMISSIONS_REQUEST_BLUETOOTH is an 
    // app-defined int constant. The callback method gets the 
    // result of the request. 
} 
} 

您的活动应实施onRequestPermissionsResult方法

@Override 
public void onRequestPermissionsResult(int requestCode,
    String permissions[], int[] grantResults) {
       switch (requestCode) {
       case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { 
          // If request is cancelled, the result arrays are empty. 
          if (grantResults.length > 0
               && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

             // permission was granted, yay! Do the 
             // contacts-related task you need to do. 

           } else { 

            // permission denied, boo! Disable the 
            // functionality that depends on this permission. 
           } 
           return; 
       } 

       // other 'case' lines to check for other 
       // permissions this app might request 
   } 
 } 

您可以对BLUETOOTH_ADMIN权限

执行相同的操作