【问题标题】:Ble Broadcast receiver not displaying on listviewBle 广播接收器未显示在列表视图上
【发布时间】:2021-08-10 16:19:00
【问题描述】:

(免责声明:ANDROID STUDIO 的超级新手)我正在创建一个应用程序来扫描 ble 设备并将它们显示在列表中,但似乎没有发现任何设备并显示在列表视图中。任何帮助表示赞赏。我打算用找到的设备数量来更新 Textview。我还没有设置扫描过滤器,因为我仍在尝试找出我正在使用的标签的 UUID。我还将 min sdk 更改为 23,因为它在设置扫描模式、回调和匹配模式时给了我一个错误。

MainActivity.java

package com.example.tygatraxseconddraft;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "TWESBTSCANNER";
    public static final int REQUEST_ACCESS_COARSE_LOCATION = 1;
    public static final int REQUEST_ENABLE_BLUETOOTH = 11;
    private ListView listView;
    private Button scanningBtn;
    private BluetoothAdapter bluetoothAdapter;
    private final ArrayList<String> mDeviceList = new ArrayList<>();



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = findViewById(R.id.device_list);
        scanningBtn = findViewById(R.id.scanning_btn);


        hasPermissions();

        checkBluetoothState();

        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(mReceiver, filter);
        listView = findViewById(R.id.device_list);

        scanningBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
                BluetoothLeScanner scanner = adapter.getBluetoothLeScanner();


                final ScanCallback scanCallback = new ScanCallback() { //studio made it not private
                    @Override
                    public void onScanResult(int callbackType, ScanResult result) {
                        BluetoothDevice device = result.getDevice();
                        // ...do whatever you want with this found device
                    }

                    @Override
                    public void onBatchScanResults(List<ScanResult> results) {
                        // Ignore for now
                    }

                    @Override
                    public void onScanFailed(int errorCode) {
                        // Ignore for now
                    }
                };

                UUID SERVICE_DATA_UUID = UUID.fromString("00005246-0000-1000-8000-00805f9b34fb");//filter for the Nordic tags
                UUID[] serviceUUIDs = new UUID[]{SERVICE_DATA_UUID};
                List<ScanFilter> filters = null;
                if (serviceUUIDs != null) {
                    filters = new ArrayList<>();
                    for (UUID serviceUUID : serviceUUIDs) {
                        ScanFilter filter = new ScanFilter.Builder()
                                .setServiceUuid(new ParcelUuid(serviceUUID))
                                .build();
                        filters.add(filter);
                    }
                }


                ScanSettings scanSettings = new ScanSettings.Builder()
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                        .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
                        .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
                        .setReportDelay(0L)
                        .build();

                if (scanner != null) {
                    scanner.startScan(null, scanSettings, scanCallback); // must set scan settings first
                    Log.d(TAG, "scan started");
                } else {
                    Log.e(TAG, "could not get scanner object");

                }
            }
        });



    }



    @Override
    protected void onDestroy() {
        unregisterReceiver(mReceiver);
        super.onDestroy();
    }

    public final BroadcastReceiver mReceiver = new BroadcastReceiver() { //
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                mDeviceList.add(device.getName() + "\n" + device.getAddress());
                Log.i("BT", device.getName() + "\n" + device.getAddress());
                listView.setAdapter(new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, mDeviceList));

            }
        }
    };


    private boolean hasPermissions() { //checks and asks for location permission
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, REQUEST_ACCESS_COARSE_LOCATION);
                return false;
            }
        }
        return true;
    }

    //ENABLE WHEN TESTING ON PHONE
    private void checkBluetoothState() {
        //gets the bluetooth adapter
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter.isEnabled()){
            Toast.makeText(this,"Bluetooth is enabled", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Please turn on Bluetooth", Toast.LENGTH_SHORT).show();
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BLUETOOTH);
        }//requests permission if bluetooth is not enabled
    }


}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tygatraxseconddraft">

    <!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />

    <!-- Needed only if your app looks for Bluetooth devices.
             You must add an attribute to this permission, or declare the
             ACCESS_FINE_LOCATION permission, depending on the results when you
             check location usage in your app. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>


    <!-- Needed only if your app makes the device discoverable to Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

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

    <!--Makes the app show up for only ble enabled devices-->
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true"/>





    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TygaTraxsecondDraft">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/number_devices"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="@string/number_of_devices"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/scanning_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp"
        android:layout_marginBottom="50dp"
        android:text="@string/button_text"
        android:textColor="#212121"
        app:backgroundTint="@color/gray"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent" />

    <ListView
        android:id="@+id/device_list"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="24dp"
        android:layout_marginBottom="24dp"
        app:layout_constraintBottom_toTopOf="@+id/scanning_btn"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/number_devices" />

</androidx.constraintlayout.widget.ConstraintLayout>

如果需要的话 colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="gray">#7393B3</color>
</resources>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Tyga Trax (second draft)</string>
    <string name="button_text">Scan</string>
    <string name="number_of_devices">There are </string>
</resources>

【问题讨论】:

  • 我看到您已经考虑过请求权限,但是您附近真的有 BLE 设备吗?请先使用通用 BLE 扫描仪应用程序(例如 nRF Connect)进行检查。请同时添加 manifest.xml,它丢失了
  • @MichaelKotzjan 嗨,我刚刚添加了 android 清单并修复了标题。我使用了 nRF connect 并找到了我的北欧标签(称为 RF-B-AR4 BLE Beacon)here。我有 logcat here 的录音和截图。
  • 您的应用的目标 sdk 是什么?更高版本的权限要求更改
  • @MichaelKotzjan 我查看了build.gradle 文件,上面写着23:android { compileSdk 31 defaultConfig { applicationId "com.example.tygatraxseconddraft" minSdk 23 targetSdk 31 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" }

标签: java android bluetooth bluetooth-lowenergy


【解决方案1】:

新答案

我刚刚意识到你现在对找到的设备什么都不做,你的ScanCallback 是空的。你应该添加这样的东西来查看结果:

final ScanCallback scanCallback = new ScanCallback() { //studio made it not private
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        BluetoothDevice device = result.getDevice();
        Log.d(TAG, "BLE scan found Device " + device.getName() + " with MAC " + device.getAddress());
        // TODO: add device to ListView
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        // Ignore for now
    }

    @Override
    public void onScanFailed(int errorCode) {
        // Ignore for now
    }
};

您现在应该会在日志中看到找到的设备

上一个答案

您正在请求 ACCESS_COARSE_LOCATION 权限,但您的目标 SDK 是 31。Bluetooth permissions 状态指南

ACCESS_FINE_LOCATION 是必要的,因为蓝牙扫描可以收集有关用户位置的信息。此信息可能来自用户自己的设备,以及在商店和交通设施等位置使用的蓝牙信标。

还有

注意:如果您的应用面向 Android 9(API 级别 28)或更低版本,您可以声明 ACCESS_COARSE_LOCATION 权限而不是 ACCESS_FINE_LOCATION 权限。

它甚至声明将ACCESS_BACKGROUND_LOCATION 用于搭载 Android 10 或更高版本的设备。但如this 文档中所述,目标 ​​SDK 为 31(Android 12)有新权限。

<manifest>
    <!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="30" />

    <!-- Needed only if your app looks for Bluetooth devices.
         You must add an attribute to this permission, or declare the
         ACCESS_FINE_LOCATION permission, depending on the results when you
         check location usage in your app. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

    <!-- Needed only if your app makes the device discoverable to Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- Needed only if your app communicates with already-paired Bluetooth
         devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    ...
</manifest>

如您所见,还添加了诸如 BLUETOOTH 之类的旧蓝牙权限,但将选项 android:maxSdkVersion="30" 设置为仅适用于 Android 11。

【讨论】:

  • 感谢您的帮助,但不幸的是,它仍然无法正常工作。我将使用当前代码更新我的帖子。对于为什么它不起作用,您还有其他想法吗?
  • 能否将您的日志输出添加到您的问题中?
  • 我将它复制到一个 .txt 文件并上传到我的驱动器。 Here
  • @Stealthninja146 请看看我更新的答案
  • 我试过了,但还是不行。我在想我的代码中有一些非常错误的东西,我会尝试别的东西。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-03
相关资源
最近更新 更多