2. 动态权限请求
任务说明
本案例实现Android 12(API 31)及以上版本运行时动态请求蓝牙扫描与连接权限,并处理用户授权结果。核心目标:在应用启动后主动弹出系统权限对话框,根据用户选择更新界面状态并给出明确提示。
权限配置
在AndroidManifest.xml中声明蓝牙权限(Android 12+需声明BLUETOOTH_SCAN与BLUETOOTH_CONNECT):
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
核心实现
在MainActivity.java中实现权限请求逻辑。使用ActivityResultContracts.RequestMultiplePermissions统一请求两项权限,避免重复回调:
public class MainActivity extends AppCompatActivity {
private static final String[] REQUIRED_PERMISSIONS = {
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
};
private final ActivityResultLauncher<String[]> permissionLauncher =
registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
result -> {
boolean scanGranted = Boolean.TRUE.equals(
result.get(Manifest.permission.BLUETOOTH_SCAN));
boolean connectGranted = Boolean.TRUE.equals(
result.get(Manifest.permission.BLUETOOTH_CONNECT));
if (scanGranted && connectGranted) {
updateStatus("权限已授予,可以开始蓝牙扫描");
} else if (!scanGranted) {
updateStatus("蓝牙扫描权限被拒绝,无法发现设备");
} else {
updateStatus("蓝牙连接权限被拒绝,无法连接设备");
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_request).setOnClickListener(v -> {
if (hasAllPermissions()) {
updateStatus("权限已具备,无需重复请求");
} else {
permissionLauncher.launch(REQUIRED_PERMISSIONS);
}
});
}
private boolean hasAllPermissions() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private void updateStatus(String message) {
TextView tvStatus = findViewById(R.id.tv_status);
tvStatus.setText(message);
}
}
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp">
<Button
android:id="@+id/btn_request"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求蓝牙权限" />
<TextView
android:id="@+id/tv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="未请求权限"
android:textSize="16sp" />
</LinearLayout>
权限请求时序
验证方法
运行步骤:
- 使用Android Studio创建空项目,将上述代码分别填入
MainActivity.java、activity_main.xml和AndroidManifest.xml对应位置; - 在Android 12+模拟器或真机上运行应用;
- 点击"请求蓝牙权限"按钮。
判定标准:
- 首次点击时系统弹出权限对话框,分别显示"扫描附近的设备"和"与蓝牙设备配对"两项权限请求;
- 点击"允许"后,界面文本更新为"权限已授予,可以开始蓝牙扫描";
- 拒绝任一权限后,界面文本对应显示"蓝牙扫描权限被拒绝"或"蓝牙连接权限被拒绝";
- 再次点击按钮时,若权限已全部授予,显示"权限已具备,无需重复请求",不再弹出对话框。
预期输出示例:首次点击后系统弹出授权对话框;用户全部允许后,tv_status显示"权限已授予,可以开始蓝牙扫描"。此结果由代码逻辑直接推出,实际表现以系统对话框交互为准。