欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android提高之蓝牙隐藏API探秘

程序员文章站 2022-05-16 12:28:25
前面文章讲解了android的蓝牙基本用法,本文讲得深入些,探讨下蓝牙方面的隐藏api。用过android系统设置(setting)的人都知道蓝牙搜索之后可以建立配对和解除...

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

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

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

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却隐藏),则自己实现调用方法:

/**
 * 与设备配对 参考源码: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源码如下:

<?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源码如下:

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的源码如下:

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程序开发有一定的借鉴帮助作用。