13.探秘蓝牙隐藏API

上次讲解Android的蓝牙基本用法,这次讲得深入些,探讨下蓝牙方面的隐藏API。用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对和解除配对,但是这两项功能的函数没有在SDK中给出,那么如何去使用这两项功能呢?本文利用JAVA的反射机制去调用这两项功能对应的函数:createBond和removeBond,具体的发掘和实现步骤如下:

1、使用Git工具下载platform/packages/apps/Settings.git,在Setting源码中查找关于建立配对和解除配对的API,知道这两个API的宿主(BluetoothDevice);

2、使用反射机制对BluetoothDevice枚举其所有方法和常量,看看是否存在:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static  public  void  printAllInform(Class clsShow) {
     try  {
         // 取得所有方法
         Method[] hideMethod = clsShow.getMethods();
         int  i =  0 ;
         for  (; i < hideMethod.length; i++) {
             Log.e( "method name" , hideMethod[i].getName());
         }
         // 取得所有常量
         Field[] allFields = clsShow.getFields();
         for  (i =  0 ; i < allFields.length; i++) {
             Log.e( "Field name" , allFields[i].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();
     }
}

结果如下:

11-29 09:19:12.012: method name(452): cancelBondProcess
11-29 09:19:12.020: method name(452): cancelPairingUserInput
11-29 09:19:12.020: method name(452): createBond
11-29 09:19:12.020: method name(452): createInsecureRfcommSocket
11-29 09:19:12.027: method name(452): createRfcommSocket
11-29 09:19:12.027: method name(452): createRfcommSocketToServiceRecord
11-29 09:19:12.027: method name(452): createScoSocket
11-29 09:19:12.027: method name(452): describeContents
11-29 09:19:12.035: method name(452): equals
11-29 09:19:12.035: method name(452): fetchUuidsWithSdp
11-29 09:19:12.035: method name(452): getAddress
11-29 09:19:12.035: method name(452): getBluetoothClass
11-29 09:19:12.043: method name(452): getBondState
11-29 09:19:12.043: method name(452): getName
11-29 09:19:12.043: method name(452): getServiceChannel
11-29 09:19:12.043: method name(452): getTrustState
11-29 09:19:12.043: method name(452): getUuids
11-29 09:19:12.043: method name(452): hashCode
11-29 09:19:12.043: method name(452): isBluetoothDock
11-29 09:19:12.043: method name(452): removeBond
11-29 09:19:12.043: method name(452): setPairingConfirmation
11-29 09:19:12.043: method name(452): setPasskey
11-29 09:19:12.043: method name(452): setPin
11-29 09:19:12.043: method name(452): setTrust
11-29 09:19:12.043: method name(452): toString
11-29 09:19:12.043: method name(452): writeToParcel
11-29 09:19:12.043: method name(452): convertPinToBytes
11-29 09:19:12.043: method name(452): getClass
11-29 09:19:12.043: method name(452): notify
11-29 09:19:12.043: method name(452): notifyAll
11-29 09:19:12.043: method name(452): wait
11-29 09:19:12.051: method name(452): wait
11-29 09:19:12.051: method name(452): wait

3、如果枚举发现API存在(SDK却隐藏),则自己实现调用方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  * 与设备配对 参考源码:platform/packages/apps/Settings.git
  * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
  */
static  public  boolean  createBond(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
  */
static  public  boolean  removeBond(Class btClass,BluetoothDevice btDevice) throws  Exception {
     Method removeBondMethod = btClass.getMethod( "removeBond" );
     Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
     return  returnValue.booleanValue();
}

PS : SDK之所以不给出隐藏的API肯定有其原因,也许是出于安全性或者是后续版本兼容性的考虑,因此不能保证隐藏API能在所有Android平台上很好地运行。。。

本文程序运行效果如下:

程序运行效果图

main.xml源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<? xml  version = "1.0"  encoding = "utf-8" ?>
< LinearLayout  xmlns:android = "http://schemas.android.com/apk/res/android"
     android:orientation = "vertical"
     android:layout_width = "fill_parent"
     android:layout_height = "fill_parent" >
     < LinearLayout
         android:id = "@+id/LinearLayout01"
         android:layout_height = "wrap_content"
         android:layout_width = "fill_parent" >
         < Button
             android:id = "@+id/btnSearch"
             android:layout_width = "160dip"
             android:layout_height = "wrap_content"
             android:text = "Search" >
         </ Button >
         < Button
             android:id = "@+id/btnShow"
             android:layout_height = "wrap_content"
             android:layout_width = "160dip"
             android:text = "Show"
         </Button>
     </ LinearLayout >
     < LinearLayout
         android:id = "@+id/LinearLayout02"
         android:layout_width = "wrap_content"
         android:layout_height = "wrap_content" >
     </ LinearLayout >
     < ListView
         android:id = "@+id/ListView01"
         android:layout_width = "fill_parent"
         android:layout_height = "fill_parent" >
     </ ListView >
</ LinearLayout >

工具类ClsUtils.java源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package  com.testReflect;
 
import  java.lang.reflect.Field;
import  java.lang.reflect.Method;
import  android.bluetooth.BluetoothDevice;
import  android.util.Log;
 
public  class  ClsUtils {
 
     /**
      * 与设备配对 参考源码:platform/packages/apps/Settings.git
      * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
      */
     static  public  boolean  createBond(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
      */
     static  public  boolean  removeBond(Class btClass, BluetoothDevice btDevice)
             throws  Exception {
         Method removeBondMethod = btClass.getMethod( "removeBond" );
         Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
         return  returnValue.booleanValue();
     }
 
     /**
      *
      * @param clsShow
      */
     static  public  void  printAllInform(Class clsShow) {
         try  {
             // 取得所有方法
             Method[] hideMethod = clsShow.getMethods();
             int  i =  0 ;
             for  (; i < hideMethod.length; i++) {
                 Log.e( "method name" , hideMethod[i].getName());
             }
             // 取得所有常量
             Field[] allFields = clsShow.getFields();
             for  (i =  0 ; i < allFields.length; i++) {
                 Log.e( "Field name" , allFields[i].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();
         }
     }
}

主程序testReflect.java的源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package  com.testReflect;
 
import  java.util.ArrayList;
import  java.util.List;
import  android.app.Activity;
import  android.bluetooth.BluetoothAdapter;
import  android.bluetooth.BluetoothDevice;
import  android.content.BroadcastReceiver;
import  android.content.Context;
import  android.content.Intent;
import  android.content.IntentFilter;
import  android.os.Bundle;
import  android.util.Log;
import  android.view.View;
import  android.widget.AdapterView;
import  android.widget.ArrayAdapter;
import  android.widget.Button;
import  android.widget.ListView;
import  android.widget.Toast;
 
public  class  testReflect  extends  Activity {
     Button btnSearch, btnShow;
     ListView lvBTDevices;
     ArrayAdapter<String> adtDevices;
     List<String> lstDevices =  new  ArrayList<String>();
     BluetoothDevice btDevice;
     BluetoothAdapter btAdapt;
 
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
 
         btnSearch = (Button)  this .findViewById(R.id.btnSearch);
         btnSearch.setOnClickListener( new  ClickEvent());
         btnShow = (Button)  this .findViewById(R.id.btnShow);
         btnShow.setOnClickListener( new  ClickEvent());
 
         lvBTDevices = (ListView)  this .findViewById(R.id.ListView01);
         adtDevices =  new  ArrayAdapter<String>(testReflect. this ,
                 android.R.layout.simple_list_item_1, lstDevices);
         lvBTDevices.setAdapter(adtDevices);
         lvBTDevices.setOnItemClickListener( new  ItemClickEvent());
 
         btAdapt = BluetoothAdapter.getDefaultAdapter(); // 初始化本机蓝牙功能
         if  (btAdapt.getState() == BluetoothAdapter.STATE_OFF) // 开蓝牙
             btAdapt.enable();
 
         // 注册Receiver来获取蓝牙设备相关的结果
         IntentFilter intent =  new  IntentFilter();
         intent.addAction(BluetoothDevice.ACTION_FOUND);
         intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         registerReceiver(searchDevices, intent);
 
     }
 
     private  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.length; i++) {
                 String keyName = lstName[i].toString();
                 Log.e(keyName, String.valueOf(b.get(keyName)));
             }
             // 搜索设备时,取得设备的MAC地址
             if  (BluetoothDevice.ACTION_FOUND.equals(action)) {
                 BluetoothDevice device = intent
                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
 
                 if  (device.getBondState() == BluetoothDevice.BOND_NONE) {
                     String str =  "未配对|"  + device.getName() +  "|"
                             + device.getAddress();
                     lstDevices.add(str);  // 获取设备名称和mac地址
                     adtDevices.notifyDataSetChanged();
                 }
             }
         }
     };
 
     class  ItemClickEvent  implements  AdapterView.OnItemClickListener {
 
         @Override
         public  void  onItemClick(AdapterView<?> arg0, View arg1,  int  arg2,
                 long  arg3) {
             btAdapt.cancelDiscovery();
             String str = lstDevices.get(arg2);
             String[] values = str.split( "//|" );
             String address = values[ 2 ];
 
             btDevice = btAdapt.getRemoteDevice(address);
             try  {
                 if  (values[ 0 ].equals( "未配对" )) {
                     Toast.makeText(testReflect. this "由未配对转为已配对" , 500 ).show();
                     ClsUtils.createBond(btDevice.getClass(), btDevice);
                 else  if  (values[ 0 ].equals( "已配对" )) {
                     Toast.makeText(testReflect. this "由已配对转为未配对" , 500 ).show();
                     ClsUtils.removeBond(btDevice.getClass(), btDevice);
                 }
             catch  (Exception e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
 
     }
 
     /**
      * 按键处理
      *
      * @author GV
      *
      */
     class  ClickEvent  implements  View.OnClickListener {
 
         @Override
         public  void  onClick(View v) {
             if  (v == btnSearch) { // 搜索附近的蓝牙设备
                 lstDevices.clear();
 
                 Object[] lstDevice = btAdapt.getBondedDevices().toArray();
                 for  ( int  i =  0 ; i < lstDevice.length; 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 == btnShow) { // 显示BluetoothDevice的所有方法和常量,包括隐藏api
                 ClsUtils.printAllInform(btDevice.getClass());
             }
 
         }
 
     }
 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值