我的代码如下->
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.root.securityalert">
<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/AppTheme">
<activity android:name=".DeviceScanActivity" android:label="Activity2" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="@string/app_name" android:name=".BlueTooth"/>
</application>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
deviceScanActivity
DeviceScanActivity类扩展了AppCompatActivity / ListActivity / {
public BluetoothAdapter mBluetoothAdapter;
public /*final*/ BluetoothManager mBluetoothManager;
ArrayList<ViewHolder> arrayOfUsers2 = new ArrayList<ViewHolder>();
private boolean mScanning;
private Handler mHandler;
ArrayList<String> mylist = new ArrayList<String>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 50000;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 456;
UsersAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//getActionBar().setTitle("abc");
mHandler = new Handler();
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
mBluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null ) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
if( !mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 1);
}
if( !mBluetoothAdapter.isDiscovering()) {
Intent discoverableIntent =
new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
// Construct the data source
ArrayList<ViewHolder> arrayOfUsers = new ArrayList<ViewHolder>();
// Create the adapter to convert the array to views
adapter = new UsersAdapter(this, arrayOfUsers);
ListView listView = (ListView) findViewById(R.id.mobile_list);
listView.setAdapter(adapter);
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
if(arrayOfUsers2.isEmpty())
{
ViewHolder currentX=new ViewHolder("No devices ","found");
adapter.add(currentX);
}
else {
Iterator<ViewHolder> it = arrayOfUsers2.iterator();
while (it.hasNext()) {
ViewHolder currentX = it.next();
adapter.add(currentX);
}
}
// Do something with the value
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
//invalidateOptionsMenu();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
scanLeDevice(true);
} else {
// Alert the user that this application requires the location permission to perform the scan.
}
}
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//mLeDeviceListAdapter.addDevice(device);
//mLeDeviceListAdapter.notifyDataSetChanged();
//ViewHolder newUser = new ViewHolder("Nathan", "San Diego");
String deviceName=null, deviceAddress=null;
if(device!=null)
deviceName= device.getName();
if (!(deviceName != null && deviceName.length() > 0))
deviceName = "unknown device";
if(device!=null)
deviceAddress= device.getAddress();
ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
ViewHolder newUser2 = new ViewHolder("adtv","vvg");
//if(!arrayOfUsers2.contains(newUser))
arrayOfUsers2.add(newUser);
adapter.add(newUser);
}
});
}
};
public class UsersAdapter extends ArrayAdapter<ViewHolder> {
public UsersAdapter(Context context, ArrayList<ViewHolder> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ViewHolder user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);
TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);
// Populate the data into the template view using the data object
tvName.setText(user.deviceName);
tvHome.setText(user.deviceAddress);
// Return the completed view to render on screen
return convertView;
}
}
public class ViewHolder {
String deviceName;
String deviceAddress;
public ViewHolder(String device, String __address) {
this.deviceName =device;
this.deviceAddress= __address;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ViewHolder a = (ViewHolder) o;
return Objects.equals(deviceAddress, a.deviceAddress);
}
}
}
}});
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
if(arrayOfUsers2.isEmpty())
{
ViewHolder currentX=new ViewHolder("No devices ","found");
adapter.add(currentX);
}
else {
Iterator<ViewHolder> it = arrayOfUsers2.iterator();
while (it.hasNext()) {
ViewHolder currentX = it.next();
adapter.add(currentX);
}
}
// Do something with the value
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
scanLeDevice(true);
} else {
// Alert the user that this application requires the location permission to perform the scan.
}
}
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
String deviceName=null, deviceAddress=null;
if(device!=null)
deviceName= device.getName();
if (!(deviceName != null && deviceName.length() > 0))
deviceName = "unknown device";
if(device!=null)
deviceAddress= device.getAddress();
ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
ViewHolder newUser2 = new ViewHolder("adtv","vvg");
//if(!arrayOfUsers2.contains(newUser))
arrayOfUsers2.add(newUser);
adapter.add(newUser);
}
});
}
};
public class UsersAdapter extends ArrayAdapter<ViewHolder> {
public UsersAdapter(Context context, ArrayList<ViewHolder> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ViewHolder user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);
TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);
// Populate the data into the template view using the data object
tvName.setText(user.deviceName);
tvHome.setText(user.deviceAddress);
// Return the completed view to render on screen
return convertView;
}
}
public class ViewHolder {
String deviceName;
String deviceAddress;
public ViewHolder(String device, String __address) {
this.deviceName =device;
this.deviceAddress= __address;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ViewHolder a = (ViewHolder) o;
return Objects.equals(deviceAddress, a.deviceAddress);
}
}
}
我正在尝试使用BLE API扫描附近的蓝牙设备。我已经使用此代码进行了测试,直到今天早上仍在工作。但是我有2个新设备,并且正在将此代码同时应用于它们和测试中。他们没有发现对方,也没有发现我的笔记本电脑。较早之前,我可以在附近发现其他设备。希望他们现在不在附近,他们两个都发现同一台设备但彼此之间却没有发现。 build.gradle(ModuleApp)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.example.root.securityalert"
minSdkVersion 23
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
compile 'io.reactivex.rxjava2:rxjava:2.0.0'
implementation 'com.android.support:design:27.0.2'-this line is in red(error)
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
mavenCentral()
}
Build.gradle(Project:xyz)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.2.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
compile 'io.reactivex.rxjava2:rxjava:2.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
logcat错误
build failed 213ms
Run build 90ms
Load build 3ms
Configure build 78ms
Load projects 6ms
rootProject
Configure project : 61ms
Apply plugin org.gradle.help-tasks 1ms
Apply script build.gradle 53ms--- this line is in red(error)
我也收到此错误
Could not find method compile() for arguments [io.reactivex.rxjava2:rxjava:2.0.0] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
答案 0 :(得分:0)
确保已淘汰API级别,因为大多数Android BLE构造都是> API21。其中adapter.startLeScan{}
是针对较低API设备的,这也许是新设备无法执行此操作的原因检测其他设备。我使用Kotlin用Rx创建了一个简单的BLE扫描器。这使处理线程和安排线程变得更加容易。
您可以使用Builder
对其进行配置,并为stopCallback
设置一个条件将在达到该条件时停止扫描。
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.os.Build
import android.support.annotation.RequiresApi
import io.reactivex.*
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.jetbrains.anko.bluetoothManager
class BleScannerFlowable private constructor(
private val adapter: BluetoothAdapter,
private val stopCallback: ((BluetoothDevice) -> Boolean)? = null,
private val scanFilter: Array<out ScanFilter>? = null,
private val scanSettings: ScanSettings? = null
): FlowableOnSubscribe<BluetoothDevice> {
override fun subscribe(e: FlowableEmitter<BluetoothDevice>) {
if (isAboveLollipop()) {
setupSubscriber21(e)
} else {
setupSubscriber(e)
}
}
private fun setupSubscriber(emitter: FlowableEmitter<BluetoothDevice>) {
adapter.startLeScan { device, rssi, scanRecord ->
if (stopCallback?.invoke(device) == true) {
adapter.stopLeScan { device, rssi, scanRecord ->
emitter.onComplete()
}
}
emitter.onNext(device)
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun setupSubscriber21(emitter: FlowableEmitter<BluetoothDevice>) {
val isFilterSet = scanFilter?.isNotEmpty() == true
val filters = if (isFilterSet) scanFilter!!.toMutableList() else mutableListOf()
adapter.bluetoothLeScanner?.startScan(filters, scanSettings, ScanCaller(emitter))
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private inner class ScanCaller(private val emitter: FlowableEmitter<BluetoothDevice>) : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
emitter.onError(Throwable("Scan failed with code $errorCode"))
}
override fun onScanResult(callbackType: Int, result: ScanResult?) {
if (result != null && result.device != null) {
if (stopCallback?.invoke(result.device) == true) {
adapter.bluetoothLeScanner?.stopScan(this)
emitter.onComplete()
} else {
emitter.onNext(result.device)
}
}
}
}
class Builder(private val adapter: BluetoothAdapter) {
private var scanFilter: Array<out ScanFilter>? = null
private var stopCallback: ((BluetoothDevice) -> Boolean)? = null
private var settingsBuilder: ScanSettings.Builder? = null
private var scanSettings: ScanSettings? = null
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun setFilterByName(name: String) : Builder {
setScanFilters(ScanFilter.Builder()
.setDeviceName(name)
.build())
return this
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun setScanFilters(vararg scanFilter: ScanFilter) : Builder{
this.scanFilter = scanFilter
return this
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun setScanMode(scanMode: ScanModes) : Builder{
getSettingsBuilder().setScanMode(scanMode.settingId)
return this
}
fun setStopCallback(function: (BluetoothDevice) -> Boolean) : Builder {
this.stopCallback = function
return this
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun setScanSettings(scanSettings: ScanSettings) : Builder {
this.scanSettings = scanSettings
return this
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun build(): Flowable<BluetoothDevice> =
Flowable.create(BleScannerFlowable(adapter,
stopCallback,
scanFilter,
scanSettings ?: settingsBuilder?.build()),
BackpressureStrategy.LATEST)
fun buildLower(): Flowable<BluetoothDevice> =
Flowable.create(BleScannerFlowable(adapter, stopCallback),
BackpressureStrategy.LATEST)
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun getSettingsBuilder() : ScanSettings.Builder {
if (settingsBuilder == null) {
settingsBuilder = ScanSettings.Builder()
}
return settingsBuilder!!
}
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
enum class ScanModes(val settingId: Int) {
LOW_LATENCY(ScanSettings.SCAN_MODE_LOW_LATENCY),
LOW_POWER(ScanSettings.SCAN_MODE_LOW_POWER),
BALANCED(ScanSettings.SCAN_MODE_BALANCED),
OPPORTUNISTIC(ScanSettings.SCAN_MODE_BALANCED)
}
fun startScanning() {
val adapter = applicationContext.bluetoothManager.adapter ?: return
val bleScanner = if (isAboveLollipop()) {
BleScannerFlowable.Builder(adapter)
.setScanMode(ScanModes.BALANCED)
.setStopCallback { it.name == "MyBleDevice" }
.build()
} else {
BleScannerFlowable.Builder(adapter)
.setStopCallback { it.name == "MyBleDevice" }
.buildLower()
}
bleScanner
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
// do something with the bluetooth device
}, {
// handle error
it.printStackTrace()
}, {
// do on finish scan
})
}
fun isAboveLollipop() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP