2024-09-01
Android/Java
00

iBeacon 最先是苹果的技术,使用android-beacon-library包可以在android上开发iBeacon 技术。

iBeacon的发明意义重大。它是一种基于蓝牙低功耗(Bluetooth Low Energy, BLE)技术的定位系统,通过向周围发送信号来标识其位置。这项技术的意义体现在以下几个方面:

  1. 室内定位与导航: iBeacon可用于在室内环境中提供定位和导航服务。传统的GPS技术在室内环境下往往效果不佳,而iBeacon通过布置在建筑物内部的信标,可以实现更精准的室内定位。

  2. 增强零售体验: 零售业是iBeacon应用的一个重要领域。商店可以利用iBeacon技术向顾客发送特定的优惠信息、促销活动或产品推荐,从而提升顾客体验并促进销售。

  3. 实时定位服务: iBeacon可以实现对移动设备的实时追踪,为企业和组织提供更有效的资产管理、人员定位和安全监控等服务。

  4. 交互式体验: 利用iBeacon技术,可以为用户提供更加个性化和交互式的体验。比如,在博物馆、展览或游乐园等场所,可以通过iBeacon向游客提供相关的解说信息或互动体验。

  5. 开发者创新: iBeacon开放的开发平台为开发者提供了广阔的创新空间,他们可以基于iBeacon技术开发各种各样的应用,从而为用户带来更丰富的体验和功能。

iBeacon的发明为室内定位和个性化服务领域带来了革命性的变革,极大地丰富了移动应用的功能和体验。

先加这句:implementation group: 'org.altbeacon', name: 'android-beacon-library', version: '2.20.6'

在这里插入图片描述

然后sync之后就能使用,xml:

cpp
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Android 12以下才需要定位权限, Android 9以下官方建议申请ACCESS_COARSE_LOCATION --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 12在不申请定位权限时,必须加上android:usesPermissionFlags="neverForLocation",否则搜不到设备 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplication" tools:targetApi="31"> <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>

主java【搜不到我想要的设备,没有android自带的搜设备兼容性好,或许我用错了,但可以搜到设备!】:

cpp
package com.example.myapplication; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.pm.PackageManager; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.util.Log; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.google.android.material.bottomnavigation.BottomNavigationView; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import org.altbeacon.beacon.Beacon; import org.altbeacon.beacon.BeaconConsumer; import org.altbeacon.beacon.BeaconManager; import org.altbeacon.beacon.BeaconParser; import org.altbeacon.beacon.MonitorNotifier; import org.altbeacon.beacon.RangeNotifier; import org.altbeacon.beacon.Region; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.UUID; public class MainActivity extends AppCompatActivity { private static final int PERMISSION_REQUEST_CODE = 100; private static final long SCAN_PERIOD = 10000; private static final String TAG = "TimeAttendantFast"; private BluetoothLeScanner mLEScanner; private BluetoothManager btManager; private BluetoothAdapter btAdapter; private Handler scanHandler; private Handler mHandler; private Button checkInBtn; private TextView tvEmpID; private boolean isShowDialog; private ScanSettings settings; private ArrayList<ScanFilter> filters; private String employeeID; private List<String> beaconDeviceList = new ArrayList<>(); private static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; private static final int REQUEST_CHECK_SETTINGS = 14; private static final String TAGx = "BluetoothSearch"; private BluetoothAdapter bluetoothAdapter; private BroadcastReceiver bluetoothReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 请求权限 requestPermissions(); settingBlueTooth(); scanLeDevice(true); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); } @Override protected void onDestroy() { super.onDestroy(); // 停止蓝牙设备搜索并注销广播接收器 if (bluetoothAdapter != null) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { return; } bluetoothAdapter.cancelDiscovery(); } unregisterReceiver(bluetoothReceiver); } private void settingBlueTooth() { // init BLE btManager = (BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE); btAdapter = btManager.getAdapter(); if (Build.VERSION.SDK_INT >= 21) { mLEScanner = btAdapter.getBluetoothLeScanner(); settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); filters = new ArrayList<>(); } } /** * bytesToHex method */ static final char[] hexArray = "0123456789ABCDEF".toCharArray(); private static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } private void foundBeacon(String uuid, int major, int minor) { //LOG Log.i(TAG, "UUID: " + uuid + "\\nmajor: " + major + "\\nminor" + minor); } private void findBeaconPattern(byte[] scanRecord) { int startByte = 2; boolean patternFound = false; while (startByte <= 5) { if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 && //Identifies an iBeacon ((int) scanRecord[startByte + 3] & 0xff) == 0x15) { //Identifies correct data length patternFound = true; break; } startByte++; } if (patternFound) { //Convert to hex String byte[] uuidBytes = new byte[16]; System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16); String hexString = bytesToHex(uuidBytes); //UUID detection String uuid = hexString.substring(0, 8) + "-" + hexString.substring(8, 12) + "-" + hexString.substring(12, 16) + "-" + hexString.substring(16, 20) + "-" + hexString.substring(20, 32); // major final int major = (scanRecord[startByte + 20] & 0xff) * 0x100 + (scanRecord[startByte + 21] & 0xff); // minor final int minor = (scanRecord[startByte + 22] & 0xff) * 0x100 + (scanRecord[startByte + 23] & 0xff); Log.i(TAG, "UUID: " + uuid + "\\nmajor: " + major + "\\nminor" + minor); foundBeacon(uuid, major, minor); } } private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { findBeaconPattern(scanRecord); } }; private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { Log.i(TAG, "callbackType " + callbackType); // 获取ScanRecord对象 ScanRecord scanRecord = result.getScanRecord(); String MAC = result.getDevice().getAddress(); // 如果字符是以A4开头的,就是我们的设备 if (MAC.startsWith("A4")) { Log.i(TAG, "MAC: " + MAC); } // 尝试直接从ScanRecord中获取设备名称 if (scanRecord != null) { String deviceName = scanRecord.getDeviceName(); if (deviceName != null && !deviceName.isEmpty()) { Log.i(TAG, "Device Name: " + deviceName); } else { // 如果getDeviceName返回null,可能需要从scanRecord的bytes中手动解析(虽然不常见) // 但大多数情况下,直接使用getDeviceName应该足够 byte[] scanRecordBytes = scanRecord.getBytes(); // 这里可以调用您自定义的方法findBeaconPattern来进一步解析数据,如果需要的话 findBeaconPattern(scanRecordBytes); Log.i(TAG, "Device Name not directly available, parsing scan record..."); } } } @Override public void onBatchScanResults(List<ScanResult> results) { for (ScanResult sr : results) { Log.i(TAG, "ScanResult - Results" + sr.toString()); } } @Override public void onScanFailed(int errorCode) { Log.e(TAG, "Scan Failed Error Code: " + errorCode); } }; private void scanLeDevice(final boolean enable) { Log.i(TAG, "BLE start scan"); if (Build.VERSION.SDK_INT < 21) { Log.i(TAG, "start SDK_INT < 21"); if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } btAdapter.startLeScan(leScanCallback); } else { Log.i(TAG, "start SDK_INT >= 21"); mLEScanner.startScan(filters, settings, mScanCallback); } } private void requestPermissions() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { // 如果没有获取到权限,请求权限 ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.BLUETOOTH, android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, }, PERMISSION_REQUEST_CODE); } } else { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { // 如果没有获取到权限,请求权限 ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, }, PERMISSION_REQUEST_CODE); } } // 如果权限已经被授予,直接进行蓝牙功能检查和定位功能检查 checkBluetoothSupport(); } private void checkBluetoothSupport() { // 检查手机蓝牙是否打开 BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, "本机不支持蓝牙功能, 无法蓝牙打卡", Toast.LENGTH_SHORT).show(); finish(); } else if (!bluetoothAdapter.isEnabled()) { Toast.makeText(this, "蓝牙未打开, 请先打开蓝牙", Toast.LENGTH_SHORT).show(); finish(); } // 检查定位是否打开 LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { Toast.makeText(this, "定位未打开, 请先打开定位", Toast.LENGTH_SHORT).show(); finish(); } // 检查是否联网network if (!locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { Toast.makeText(this, "网络未打开, 请先打开网络", Toast.LENGTH_SHORT).show(); finish(); } if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "本机不支持蓝牙功能, 无法蓝牙打卡", Toast.LENGTH_SHORT).show(); finish(); } else { BluetoothManager bm = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter bleAdapter = bm.getAdapter(); if (bleAdapter == null || !bleAdapter.isEnabled()) { Toast.makeText(this, "本机不支持低功耗蓝牙功能, 无法蓝牙打卡", Toast.LENGTH_SHORT).show(); finish(); } else { Toast.makeText(this, "手机支持蓝牙定位打卡", Toast.LENGTH_SHORT).show(); } } } }

这个代码就完全没反应搜不到了:

cpp
import org.altbeacon.beacon.Beacon; import org.altbeacon.beacon.BeaconConsumer; import org.altbeacon.beacon.BeaconManager; import org.altbeacon.beacon.RangeNotifier; import org.altbeacon.beacon.Region; public class MainActivity extends AppCompatActivity implements BeaconConsumer { private BeaconManager beaconManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化 BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this); beaconManager.bind(this); } @Override public void onBeaconServiceConnect() { // 监听 iBeacon 的信号 beaconManager.addRangeNotifier(new RangeNotifier() { @Override public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) { if (beacons.size() > 0) { for (Beacon beacon : beacons) { String uuid = beacon.getId1().toString(); // 获取 iBeacon 的 UUID Log.d("Beacon", "UUID: " + uuid); } } } }); try { // 开始监测所有的 iBeacon beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null)); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); beaconManager.unbind(this); } }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Dong

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!