如何在Android中以编程方式启用/禁用蓝牙

115

我想通过程序启用/禁用蓝牙。我有以下代码。

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    
if (!mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

但是这段代码在SDK 1.5中无法工作。我该如何使它工作?


为什么它没法工作?你遇到错误了吗?如果有的话,是什么错误? - Adam Driscoll
1
BluetoothAdapter在SDK 1.5中出现错误。 - user458295
11个回答

172
这段代码对我来说有效..
//Disable bluetooth
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    
if (mBluetoothAdapter.isEnabled()) {
    mBluetoothAdapter.disable(); 
} 
    

为了使这个工作正常运行,您必须具备以下权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

API 33+ 的更新

在 Android API 33+ (13+) 中,此方法已被弃用,并且不再可能在没有用户同意的情况下启用/禁用蓝牙。根据文档,您应该改用ACTION_REQUEST_ENABLE


它对我也非常有效。在安卓设备上断开蓝牙的简单方法。非常感谢你,伙计。 - Amit Thaper
7
如果您添加了 BLUETOOTH_ADMIN 权限,它会起作用,但如果没有,则需要使用 startActivityForResult(enableBtIntent, 0); 来启用蓝牙。 - Majid Golshadi
1
谢谢您的有用答案 +1。我只想补充一点,对于不知道如何启用它的人:mBluetoothAdapter.enable()。 - Chris Sim
1
那些清单权限在2022年对我不起作用。正确的是android.permission.BLUETOOTH_CONNECT。否则它会授予权限但不会禁用。 - Luis A. Florit

105

以下是一种更为健壮的方法,还能处理enable()\disable()方法的返回值:

public static boolean setBluetooth(boolean enable) {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    boolean isEnabled = bluetoothAdapter.isEnabled();
    if (enable && !isEnabled) {
        return bluetoothAdapter.enable(); 
    }
    else if(!enable && isEnabled) {
        return bluetoothAdapter.disable();
    }
    // No need to change bluetooth state
    return true;
}

请将以下权限添加到您的清单文件中:

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

但请记住以下重要点:

这是一个异步调用:它会立即返回,客户端应该监听 ACTION_STATE_CHANGED 以便在适配器状态发生变化时得到通知。如果此调用返回 true,则适配器状态将立即从 STATE_OFF 转换为 STATE_TURNING_ON,稍后转换为 STATE_OFF 或 STATE_ON。如果此调用返回 false,则会出现立即阻止适配器开启的问题,例如飞行模式或适配器已经打开。

更新:

好的,那么如何实现蓝牙监听器?:

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

        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                                                 BluetoothAdapter.ERROR);
            switch (state) {
            case BluetoothAdapter.STATE_OFF:
                // Bluetooth has been turned off;
                break;
            case BluetoothAdapter.STATE_TURNING_OFF:
                // Bluetooth is turning off;
                break;
            case BluetoothAdapter.STATE_ON:
                // Bluetooth is on
                break;
            case BluetoothAdapter.STATE_TURNING_ON:
                // Bluetooth is turning on
                break;
            }
        }
    }
};

如何在您的Activity类中注册/取消注册接收器?

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ...

    // Register for broadcasts on BluetoothAdapter state change
    IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    registerReceiver(mReceiver, filter);
}

@Override
public void onStop() {
    super.onStop();

     // ...

    // Unregister broadcast listeners
    unregisterReceiver(mReceiver);
}

1
如果您添加了BLUETOOTH_ADMIN权限,它就可以工作,但如果没有,则需要使用startActivityForResult(enableBtIntent, 0);来启用蓝牙。 - Majid Golshadi
1
“高亮显示的信息摘自BluetoothAdapter文档,特别是enable()方法。” - Kevin Lee
1
嘿,文档中说“蓝牙不应在没有直接用户同意的情况下启用。如果您想打开蓝牙以创建无线连接,则应使用ACTION_REQUEST_ENABLE Intent,它将引发一个对话框,请求用户允许打开蓝牙。enable()方法仅适用于包括用户界面以更改系统设置的应用程序,例如“电源管理器”应用程序。”这是什么意思?例如,我从您的代码中制作了一个小应用程序,并且它可以工作。但是,如果我想上传到Play Store,它会失效吗? - Hilal
@Hilal 这会起作用。但用户需要在安装之前同意。他们将看到类似于此的对话框:https://www.pewinternet.org/2015/11/10/apps-permissions-in-the-google-play-store/pi_2015-11-10_apps-permissions_0-01/ - Caner

31

28

要启用蓝牙,您可以使用以下任一函数:

 public void enableBT(){
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (!mBluetoothAdapter.isEnabled()){
        Intent intentBtEnabled = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
        // The REQUEST_ENABLE_BT constant passed to startActivityForResult() is a locally defined integer (which must be greater than 0), that the system passes back to you in your onActivityResult() 
        // implementation as the requestCode parameter. 
        int REQUEST_ENABLE_BT = 1;
        startActivityForResult(intentBtEnabled, REQUEST_ENABLE_BT);
        }
  }

第二个函数是:

public void enableBT(){
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (!mBluetoothAdapter.isEnabled()){
        mBluetoothAdapter.enable();
    }
}

两个函数的区别在于,第一个函数会让应用程序向用户请求权限来打开或拒绝蓝牙。而第二个函数会直接打开蓝牙。

要禁用蓝牙,请使用以下函数:

public void disableBT(){
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter.isEnabled()){
        mBluetoothAdapter.disable();
    }
}

注意/第一个函数仅需要在AndroidManifest.xml文件中定义以下权限:

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

第二和第三个函数需要以下权限:

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

我认为参数(View view)是不必要的。 - CitrusO2
导入 android.bluetooth.BluetoothAdapter; - CS QGB

6

Prijin的解决方案对我非常有效。公平地说,还需要两个额外的权限:

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

当这些被添加后,默认蓝牙适配器的启用和禁用功能可以完美地工作。

3
我已经用协程在 Kotlin 中编写了一个类来处理几乎所有这些问题。

class ActivityResultHandler(
    private val registry: ActivityResultRegistry
) {

    private val handlers = mutableListOf<ActivityResultLauncher<*>>()

    fun unregisterHandlers() {
        handlers.forEach {
            it.unregister()
        }
    }

    suspend fun requestLocationPermission(): Boolean {
        return suspendCoroutine<Boolean> { continuation ->
            val launcher = registry.register(
                LOCATION_PERMISSION_REQUEST,
//                lifecycleOwner,
                ActivityResultContracts.RequestPermission()
            ) {
                continuation.resumeWith(Result.success(it))
            }
            handlers.add(launcher)
            launcher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
        }
    }

    suspend fun requestBluetoothActivation(): Boolean {
        return suspendCoroutine<Boolean> { continuation ->
            val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)

            val launcher = registry.register(
                BLUETOOTH_ON_REQUEST,
//                lifecycleOwner,
                ActivityResultContracts.StartActivityForResult()
            ) { result ->
                continuation.resume(
                    result.resultCode == Activity.RESULT_OK
                )
            }
            handlers.add(launcher)
            launcher.launch(enableBtIntent)
        }
    }

    fun checkLocationPermission(context: Context): Boolean {
        return ContextCompat.checkSelfPermission(
            context,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED
    }

    private suspend fun requestLocationActivation(
        intentSenderRequest: IntentSenderRequest,
    ): Boolean {
        return suspendCoroutine { continuation ->
            val launcher = registry.register(
                LOCATION_ACTIVATION_REQUEST,
//                lifecycleOwner,
                ActivityResultContracts.StartIntentSenderForResult()
            ) {
                continuation.resume(it.resultCode == Activity.RESULT_OK)
            }
            handlers.add(launcher)
            launcher.launch(intentSenderRequest)
        }
    }


    suspend fun enableLocation(context: Context): Boolean =
        suspendCoroutine { continuation ->

            val locationSettingsRequest = LocationSettingsRequest.Builder()
//        .setNeedBle(true)
                .addLocationRequest(
                    LocationRequest.create().apply {
                        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
                    }
                )
                .build()

            val client: SettingsClient = LocationServices.getSettingsClient(context)
            val task: Task<LocationSettingsResponse> =
                client.checkLocationSettings(locationSettingsRequest)

            task.addOnSuccessListener {
                continuation.resume(true)
            }
            task.addOnFailureListener { exception ->
                if (exception is ResolvableApiException &&
                    exception.statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED
                ) {
                    val intentSenderRequest =
                        IntentSenderRequest.Builder(exception.resolution).build()

                    CoroutineScope(continuation.context).launch {
                        val result = requestLocationActivation(intentSenderRequest)
                        continuation.resume(result)
                    }
                } else {
                    continuation.resume(false)
                }
            }
        }


    companion object {
        private const val LOCATION_PERMISSION_REQUEST = "LOCATION_REQUEST"
        private const val BLUETOOTH_ON_REQUEST = "LOCATION_REQUEST"
        private const val LOCATION_ACTIVATION_REQUEST = "LOCATION_REQUEST"
    }
}

使用方式如下:

// make sure you extend AppCompatActivity
class MainActivity : AppCompatActivity() {

    private val permissionRequests = ActivityResultHandler(activityResultRegistry)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // use viewmodels and fragments instead of GlobalScope
        GlobalScope.launch {
            // turn on bluetooth
            permissionRequests.requestBluetoothActivation()
            // to be able to scan for devices you also need location permission
            // also show pop up to let users know why you need location
            // https://support.google.com/googleplay/android-developer/answer/9799150?hl=en
            permissionRequests.requestLocationPermission()
            // also you need navigation to be enabled
            permissionRequests.enableLocation(this@MainActivity)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        permissionRequests.unregisterHandlers()
    }
}

Gradle中的协程依赖

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'

同时在清单文件中添加以下权限

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

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

在主活动中如何获取activityResultRegistry的值? - Lavanya Velusamy
@LavanyaVelusamy 它应该可以从AppCompatActivity类中获取。尝试从 https://developer.android.com/jetpack/androidx/releases/activity 添加此依赖项。 - George Shalvashvili
我添加了activity-ktx库,但是我无法使用它。 - Lavanya Velusamy
你在扩展 AppCompatActivity 吗?activityResultRegistry 存在于 ComponentActivity 中,而这个类又被 FragmentActivity 继承,最终被 AppCompatActivity 继承...也许你可以在 Github 上搜索一下?至少会有一个项目会使用它。 - George Shalvashvili

3

针对Android 12进行更新:

AndroidManifest.xml -

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

当您请求存储或其他“提示”项目的权限时,必须像请求权限 BLUETOOTH_CONNECT 一样执行标准权限请求。

用法(Kotlin)-

val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
if (bluetoothAdapter.isEnabled)
    bluetoothAdapter.disable()

针对Android 12及以上的版本,在获取当前状态或切换蓝牙的情况下不再需要BLUETOOTHBLUETOOTH_ADMIN权限,除非要针对更低的API版本。


这似乎不起作用,你确定它在Android 12+上受支持吗?我在运行Android 13的Pixel 5上进行了测试。 - behelit
2
@behelit Android 13移除了启用和禁用适配器的功能。没有替代方案,只是从开发者手中剥夺了这个功能。 - Abandoned Cart
BluetoothAdapter在Android OS13中已被弃用。在OS13上,是否有其他方法可以通过编程方式启用蓝牙? - tklanilkumar
谷歌专门移除了该选项。现在似乎只能使用意图。谷歌通过设计不佳且过多的弹窗来创造安全假象。它越像恶意软件,你就越不太可能被打扰或者类似于这样的情况。 - Abandoned Cart

3

我在我的应用启动时使用以下代码来禁用蓝牙,它可以正常工作。不确定这是否是正确实现的方法,因为谷歌建议不要在没有显式用户操作关闭蓝牙的情况下使用"bluetooth.disable();"。

    BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
    bluetooth.disable();

我只使用了以下权限。
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

如果应用程序依赖于蓝牙关闭,那么使用此方法可能会出现问题,因为存在竞争条件,由于bluetooth.disable()是异步的。 - David

1
请将以下权限添加到您的清单文件中:

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

启用蓝牙使用此功能

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    
if (!mBluetoothAdapter.isEnabled()) {
    mBluetoothAdapter.enable(); 
}else{Toast.makeText(getApplicationContext(), "Bluetooth Al-Ready Enable", Toast.LENGTH_LONG).show();}

禁用蓝牙使用此功能

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    
if (mBluetoothAdapter.isEnabled()) {
    mBluetoothAdapter.disable(); 
}

这将会创建一个竞争条件,因为Bluetooth.enable()是异步的... - David

0

试试这个:

//this method to check bluetooth is enable or not: true if enable, false is not enable
public static boolean isBluetoothEnabled()
    {
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!mBluetoothAdapter.isEnabled()) {
            // Bluetooth is not enable :)
            return false;
        }
        else{
            return true;
        }

    }

//method to enable bluetooth
    public static void enableBluetooth(){
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
        }
    }

//method to disable bluetooth
    public static void disableBluetooth(){
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.disable();
        }
    }

在清单文件中添加这些权限。
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

这将创建一个竞态条件,因为Bluetooth.enable()是异步的... - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接