Android提高之蓝牙隐藏API探秘

时间:2022-09-20 16:08:34

前面文章讲解了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
/**
 * 与设备配对 参考源码: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();
}

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

本文程序运行效果如下图所示:

Android提高之蓝牙隐藏API探秘

main.xml源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:layout_height="wrap_content" android:id="@+id/btnsearch"
  android:text="search" android:layout_width="160dip"></button>
 <button android:layout_height="wrap_content"
  android:layout_width="160dip" android:text="show" android:id="@+id/btnshow"></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
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
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());
  }
 }
 }
}

希望本文实例能够对大家进行android程序开发有一定的借鉴帮助作用。