手机bose音响蓝牙连接不上上蓝牙音响,提示PiN码不对是怎么回事

前言(android2.3版本,4.0版本由于是随机获取pin值,没有研究过):
1、蓝牙设备之间自动配对,需要两个设备都安装进行配对的apk(网上好多自动配对的帖子都没有说明情况)
2、在自动匹配的时候想通过反射调用BluetoothDevice的setPin、createBond、cancelPairingUserInput实现设置密钥、配对请求创建、取消密钥信息输入等。
1)createBond()创建,最终会调到源码的BluetoothService的createBond(String address)方法,通过对源码浅显的了解,createBond主要是写入匹配密钥(BluetoothService的writeDockPin())以及进入jni注册回调函数onCreatePairedDeviceResult观察匹配结果
比如: // Pins did not match, or remote device did not respond to pin
// request in time
// We rejected pairing, or the remote side rejected pairing. This
// happens if either side presses 'cancel' at the pairing dialog.
// Not sure if this happens
// Other device is not responding at all
// already bonded
等,在jni中创建了进行匹配的device(&CreatePairedDevice&),这时bluetooth会发送一个ACTION_PAIRING_REQUEST的广播,只有当前会出现密钥框的蓝牙设备收到。写完密钥之后,发送广播给另外一个蓝牙设备接收,然后打开密钥输入框进行匹配。
2)setPin()设置密钥,通过查看setting源码,发现在确认输入密钥之后会调用setPin()(如果点取消,就会调用cancelPairingUserInput,取消密钥框),setPin具体通过D-BUS做了什么没有去深究,但是在调用setPin的时候会remove掉一个map里面的键值对(address:int),也就是我们在调用setPin之后如果再去调用onCreatePairedDeviceResult,则该方法一定返回false,并且出现下面的打印提示:cancelUserInputNative(B8:FF:FE:55:EF:D6)
called but no native data available, ignoring. Maybe the PasskeyAgent Request was already cancelled by the remote or by bluez.(因为该方法也会remove掉一个键值对)
3)cancelPairingUserInput()取消用户输入密钥框,个人觉得一般情况下不要和setPin(setPasskey、setPairingConfirmation、setRemoteOutOfBandData)一起用,这几个方法都会remove掉map里面的key:value(也就是互斥的)。
3、蓝牙耳机、手柄等一些无法手动配置的设备是如何完成自动配对的。
在源码里面有一个自动配对的方法,也就是把pin值自动设为“0000”
/*package*/ synchronized boolean attemptAutoPair(String address) {
if (!mBondState.hasAutoPairingFailed(address) &&
!mBondState.isAutoPairingBlacklisted(address)) {
mBondState.attempt(address);
setPin(address, BluetoothDevice.convertPinToBytes(&0000&));
该方法是在底层回调到java层的onRequestPinCode方法时被调用,首先 Check if its a dock(正常输入的密钥,走正常配对方式,双方输入匹配值),然后再 try 0000 once if the device looks dumb(涉及到Device.AUDIO_VIDEO相关部分如:耳机,免提等进入自动匹配模式)进行自动配对。
言归正传,虽然个人觉得自动配对需要双方乃至多方蓝牙设备都需要装上实现自动配对的apk,已经失去了自动配对的意义,但有可能还是会派上用场。下面我们看看现实情况的自动配对是什么样的吧。
由于BluetoothDevice配对的方法都是hide的,所以我们需要通过反射调用被隐藏的方法,现在基本都是通用的工具类型了,网上模式基本一样。
ClsUtils.java
package cn.
import java.lang.reflect.F
import java.lang.reflect.M
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothD
import android.util.L
public class ClsUtils
public static BluetoothDevice remoteDevice=
* 与设备配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@SuppressWarnings(&unchecked&)
static public boolean createBond(@SuppressWarnings(&rawtypes&) Class btClass, BluetoothDevice btDevice)
throws Exception
Method createBondMethod = btClass.getMethod(&createBond&);
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
return returnValue.booleanValue();
* 与设备解除配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@SuppressWarnings(&unchecked&)
static public boolean removeBond(Class btClass, BluetoothDevice btDevice)
throws Exception
Method removeBondMethod = btClass.getMethod(&removeBond&);
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
return returnValue.booleanValue();
@SuppressWarnings(&unchecked&)
static public boolean setPin(Class btClass, BluetoothDevice btDevice,
String str) throws Exception
Method removeBondMethod = btClass.getDeclaredMethod(&setPin&,
new Class[]
{byte[].class});
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
new Object[]
{str.getBytes()});
Log.d(&returnValue&, &setPin is success & +btDevice.getAddress()+ returnValue.booleanValue());
catch (SecurityException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (IllegalArgumentException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
// 取消用户输入
@SuppressWarnings(&unchecked&)
static public boolean cancelPairingUserInput(Class btClass,
BluetoothDevice device)
throws Exception
Method createBondMethod = btClass.getMethod(&cancelPairingUserInput&);
// cancelBondProcess()
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
Log.d(&returnValue&, &cancelPairingUserInput is success & + returnValue.booleanValue());
return returnValue.booleanValue();
// 取消配对
@SuppressWarnings(&unchecked&)
static public boolean cancelBondProcess(Class btClass,
BluetoothDevice device)
throws Exception
Method createBondMethod = btClass.getMethod(&cancelBondProcess&);
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
return returnValue.booleanValue();
* @param clsShow
@SuppressWarnings(&unchecked&)
static public void printAllInform(Class clsShow)
// 取得所有方法
Method[] hideMethod = clsShow.getMethods();
int i = 0;
for (; i & hideMethod. i++)
//Log.e(&method name&, hideMethod.getName() + &;and the i is:&
// 取得所有常量
Field[] allFields = clsShow.getFields();
for (i = 0; i & allFields. i++)
//Log.e(&Field name&, allFields.getName());
catch (SecurityException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (IllegalArgumentException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
Bluetooth1.java 主activity,所有界面操作实现地方
package cn.
import java.io.IOE
import java.util.ArrayL
import java.util.L
import android.app.A
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothD
import android.bluetooth.BluetoothS
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.content.IntentF
import android.os.B
import android.util.L
import android.view.M
import android.view.V
import android.widget.AdapterV
import android.widget.ArrayA
import android.widget.B
import android.widget.ListV
import android.widget.T
import android.widget.ToggleB
public class Bluetooth1 extends Activity {
/** Called when the activity is first created. */
Button btnSearch, btnDis, btnE
ToggleButton tbtnS
ListView lvBTD
ArrayAdapter&String& adtD
List&String& lstDevices = new ArrayList&String&();
BluetoothAdapter btA
public static BluetoothSocket btS
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Button 设置
btnSearch = (Button) this.findViewById(R.id.btnSearch);
btnSearch.setOnClickListener(new ClickEvent());
btnExit = (Button) this.findViewById(R.id.btnExit);
btnExit.setOnClickListener(new ClickEvent());
btnDis = (Button) this.findViewById(R.id.btnDis);
btnDis.setOnClickListener(new ClickEvent());
// ToogleButton设置
tbtnSwitch = (ToggleButton) this.findViewById(R.id.tbtnSwitch);
tbtnSwitch.setOnClickListener(new ClickEvent());
// ListView及其数据源 适配器
lvBTDevices = (ListView) this.findViewById(R.id.lvDevices);
adtDevices = new ArrayAdapter&String&(this,
android.R.layout.simple_list_item_1, lstDevices);
lvBTDevices.setAdapter(adtDevices);
lvBTDevices.setOnItemClickListener(new ItemClickEvent());
btAdapt = BluetoothAdapter.getDefaultAdapter();// 初始化本机蓝牙功能
// ========================================================
// modified by wiley
* if (btAdapt.getState() == BluetoothAdapter.STATE_OFF)// 读取蓝牙状态并显示
* tbtnSwitch.setChecked(false); else if (btAdapt.getState() ==
* BluetoothAdapter.STATE_ON) tbtnSwitch.setChecked(true);
if (btAdapt.isEnabled()) {
tbtnSwitch.setChecked(false);
tbtnSwitch.setChecked(true);
// ============================================================
// 注册Receiver来获取蓝牙设备相关的结果
IntentFilter intent = new IntentFilter();
intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果
intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(searchDevices, intent);
private final BroadcastReceiver searchDevices = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Bundle b = intent.getExtras();
Object[] lstName = b.keySet().toArray();
// 显示所有收到的消息及其细节
for (int i = 0; i & lstName. i++) {
String keyName = lstName.toString();
Log.e(keyName, String.valueOf(b.get(keyName)));
BluetoothDevice device =
// 搜索设备时,取得设备的MAC地址
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
String str = &
未配对|& + device.getName() + &|&
+ device.getAddress();
if (lstDevices.indexOf(str) == -1)// 防止重复添加
lstDevices.add(str); // 获取设备名称和mac地址
adtDevices.notifyDataSetChanged();
}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()) {
case BluetoothDevice.BOND_BONDING:
Log.d(&BlueToothTestActivity&, &正在配对......&);
case BluetoothDevice.BOND_BONDED:
Log.d(&BlueToothTestActivity&, &完成配对&);
//connect(device);//连接设备
case BluetoothDevice.BOND_NONE:
Log.d(&BlueToothTestActivity&, &取消配对&);
protected void onDestroy() {
this.unregisterReceiver(searchDevices);
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
class ItemClickEvent implements AdapterView.OnItemClickListener {
public void onItemClick(AdapterView&?& arg0, View arg1, int arg2,
long arg3) {
if(btAdapt.isDiscovering())btAdapt.cancelDiscovery();
String str = lstDevices.get(arg2);
String[] values = str.split(&\\|&);
String address = values[2];
Log.e(&address&, values[2]);
BluetoothDevice btDev = btAdapt.getRemoteDevice(address);
Boolean returnValue =
if (btDev.getBondState() == BluetoothDevice.BOND_NONE) {
Toast.makeText(Bluetooth1.this, &远程设备发送蓝牙配对请求&, 5000).show();
//这里只需要createBond就行了
ClsUtils.createBond(btDev.getClass(), btDev);
}else if(btDev.getBondState() == BluetoothDevice.BOND_BONDED){
Toast.makeText(Bluetooth1.this, btDev.getBondState()+& ....正在连接..&, 1000).show();
} catch (Exception e) {
e.printStackTrace();
class ClickEvent implements View.OnClickListener {
public void onClick(View v) {
if (v == btnSearch)// 搜索蓝牙设备,在BroadcastReceiver显示结果
if (btAdapt.getState() == BluetoothAdapter.STATE_OFF) {// 如果蓝牙还没开启
Toast.makeText(Bluetooth1.this, &请先打开蓝牙&, 1000)
if (btAdapt.isDiscovering())
btAdapt.cancelDiscovery();
lstDevices.clear();
Object[] lstDevice = btAdapt.getBondedDevices().toArray();
for (int i = 0; i & lstDevice. i++) {
BluetoothDevice device = (BluetoothDevice) lstDevice[i];
String str = &
已配对|& + device.getName() + &|&
+ device.getAddress();
lstDevices.add(str); // 获取设备名称和mac地址
adtDevices.notifyDataSetChanged();
setTitle(&本机:& + btAdapt.getAddress());
btAdapt.startDiscovery();
} else if (v == tbtnSwitch) {// 本机蓝牙启动/关闭
if (tbtnSwitch.isChecked() == false)
btAdapt.enable();
else if (tbtnSwitch.isChecked() == true)
btAdapt.disable();
} else if (v == btnDis)// 本机可以被搜索
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
} else if (v == btnExit) {
if (btSocket != null)
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
Bluetooth1.this.finish();
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
PairingRequest.java (重要部分,自动配对主要是这个部分完成,activity只是创建了一个配对请求)
package cn.
import android.bluetooth.BluetoothD
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.widget.T
public class PairingRequest extends BroadcastReceiver {
String strPsw = &0000&;
final String ACTION_PAIRING_REQUEST = &android.bluetooth.device.action.PAIRING_REQUEST&;
static BluetoothDevice remoteDevice =
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PAIRING_REQUEST)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对
// ClsUtils.cancelPairingUserInput(device.getClass(),
// device); //一般调用不成功,前言里面讲解过了
Toast.makeText(context, &配对信息& + device.getName(), 5000)
} catch (Exception e) {
// TODO Auto-generated catch block
Toast.makeText(context, &请求连接错误...&, 1000).show();
// pair(device.getAddress(),strPsw);
AndroidManifest.xml 启动activity,接收广播
&manifest xmlns:android=&/apk/res/android&
package=&cn.bluetooth&
android:versionCode=&1&
android:versionName=&1.0& &
android:minSdkVersion=&8&
android:targetSdkVersion=&15& /&
&uses-permission android:name=&android.permission.BLUETOOTH_ADMIN& /&
&uses-permission android:name=&android.permission.BLUETOOTH& /&
&application
android:icon=&@drawable/ic_launcher&
android:label=&@string/app_name&
android:theme=&@style/AppTheme& &
android:name=&.Bluetooth1&
android:label=&@string/title_activity_bluetooth1& &
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&category android:name=&android.intent.category.LAUNCHER& /&
&/intent-filter&
&/activity&
&receiver android:name=&.PairingRequest&&
&intent-filter&
&action android:name=&android.bluetooth.device.action.PAIRING_REQUEST& /&
&/intent-filter&
&/receiver&
&/application&
&/manifest&
main.xml 布局
&LinearLayout xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:id=&@+id/LinearLayout1&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical& &
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:id=&@+id/btnSearch&
android:text=&btnSearch&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:id=&@+id/btnExit&
android:text=&btnExit&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:id=&@+id/btnDis&
android:text=&btnDis&
&ToggleButton
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:id=&@+id/tbtnSwitch&
android:text=&tbtnSwitch&
android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
android:id=&@+id/lvDevices&
&/LinearLayout&
我觉得想要真正意义上的完成蓝牙设备的自动配对,方法还是有的,需要研究一下setting部分的Bluetooth模块,以及根据蓝牙源码进行深入了解,期待着关于android bluetooth深入浅出的文章,大家有什么好的文章,留个言大家一起好好学习学习。
本文已收录于以下专栏:
相关文章推荐
按网上的方法,不知是版本问题,还是什么,就没有找着  Android_bluetooth_common.h
这个文件,自己来改。
定位文件:/external/bluetooth/bluedro...
转自:/blog/1179417
package cn.madfinger.  
  
import java.io.IOExc...
转自:/milton/p/5058566.html
// 设置加密模式为AES的CBC模式
最近一段时间在公司项目开发中,遇到了使用蓝牙进行数据传输,但是还必须要求其中的一个搭载android系统的蓝牙设备默认接受所有来进行蓝牙连接的设备。我们知道在如今的android系统中,使用蓝牙进行配...
蓝牙自动配对,即搜索到其它蓝牙设备之后直接进行配对,不需要弹出配对确认框或者密钥输入框。
经过最近一段时间得研究,针对网上给出的案例。总结了一个亲测好使的Demo。
他的最新文章
讲师:王哲涵
讲师:韦玮
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)红米手机 &
电视盒子 &
智能硬件 &
发烧级手机控
扫码下载App一键签到 升级加速
我的红米note识别到小米小钢炮蓝牙音箱PIN或配对密匙不正确
&来自老版论坛
扫一扫!手机看帖更爽
我的红米note识别到小米小钢炮蓝牙音箱PIN或配对密匙不正确 如题 求怎么解决
扫描二维码,手机查看本帖
·来自老版论坛
两个设备都没有
就是手机搜索到蓝牙音响 但配对不上去噢, 一点识别到的音响就自动配对,然后就配对失败 PIN或配对密匙不正确
·来自老版论坛
两个设备都没有
京ICP证110507号 京ICP备号查看: 5106|回复: 4
蓝牙提示pin或配对密钥不正确
也不出现输入密钥的地方
请输入验证码:
密钥是你设置的吧
忘记月亮 发表于
密钥是你设置的吧
根本没有设置密钥的地方...
头像被屏蔽
提示: 作者被禁止或删除 内容自动屏蔽
头像被屏蔽
提示: 作者被禁止或删除 内容自动屏蔽
站长推荐 /1
依《互联网跟帖评论服务管理规定》相关要求,10月1日起会员账户需实名认证。如您还未认证,请尽快完成,感谢您的理解及支持!
移动叔叔. 版权所有,专业的网络售后平台 (
商务合作||||

我要回帖

更多关于 jbl音响蓝牙连接不上 的文章

 

随机推荐