您的位置:首页 > 移动开发 > Android开发

Android获取设备电池信息,玩些新花样

2015-11-11 18:17 323 查看
在开发过程中有时我们不可避免地需要了解当前设备电池的状态,比如当前剩余电量、电池温度、是否在充电中等等..

经过查询一些资料,我发现电池的信息大多是通过广播获取的,详细的代码不贴了,到处都是,大致的流程是注册一个广播,过滤设为 Intent.ACTION_BATTERY_CHANGED 在其中的onReceive方法中,我们通过系统给的Intent参数,调用getIntExtra可以获得大部分电池信息。

不过今天遇到一个问题,如何获取到设备电池的总容量注意!,在广播中,通过Intent我们通过“scale”键可以获得一个值,这个值通常是100,并不是我们所要的电池容量,考究了一番,网上关于电池容量的一些信息还是比较少的。下面我们的工作就是 get it

首先明确,电池的信息是厂商直接提供的,并不是通过硬件检测而来的,其实道理很简单,我们无法通过电池的金属头直接探测电池的容量,最多也就是个电压和温度信息,这些能够探测的信息在上面说的广播的方法中也可以获得。那如何获得电池容量呢?设备在写入操作系统时,厂家会在操作系统中附带一个关于电池、各部件耗电情况的表单,表单名叫 power_profile.xml,路径是com.android.internal.R.xml.power_profile,我们的任务就是从这个表单中读取信息。这时有人可能会问了,我换块电池怎么办,那么,没办法,我们能得到的只是原装电池。。。。(貌似现在的Android机能换电池的并不多)

读取这个文件的信息并不是个简单的操作,大家都知道,Android系统并不是把所有的api都暴露给开发者的,由于一些安全上面的考虑,或是由于有些api还没有最终确定形态,其中的一些值或参数后期还会改变,故将这些方法或类进行了隐藏,我们开发时所用的sdk是不包含这些类和方法的。比如我们现在需要读取power_profile的类就不能调用。

嘿嘿,但总有解决办法。

从根源想想,开发版的sdk没有,那么编译就会报错,所以就有这么几个解决方案:

1、让开发时的sdk有这些方法(这不废话么)。

2、让程序感觉开发时的sdk有这些类和方法(什么鬼!)。

3、绕过编译(终于是一句人话了)。

首先我们来说最容易理解的第3条,绕过编译,其实就是用java反射的方法,要使用反射,我们需要知道类的完整路径,参数列表,这个嘛,Android源码里有,这里我们就直接给出了。

上码!

private double getDeviceBatteryCapavity(){
Object mPowerProfile_ = null;
double batteryCapacity=0;
try {
mPowerProfile = Class.forName("com.android.internal.os.PowerProfile")
.getConstructor(Context.class).newInstance(this);
} catch (Exception e) {
e.printStackTrace();
}
try {
batteryCapacity = (Double) Class
.forName("com.android.internal.os.PowerProfile")
.getMethod("getAveragePower", java.lang.String.class)
.invoke(mPowerProfile, "battery.capacity");
Log.e(TAG, "" + batteryCapacity);
} catch (Exception e) {
e.printStackTrace();
}
return batteryCapacity;
}


mPowerProfile = Class.forName(“com.android.internal.os.PowerProfile”).getConstructor(Context.class).newInstance(this); 这句创建了解析power_profile文件的PowerProfile类实例,try语句内得到相关方法并调用,最终得到了电池的容量,是一个double值。

上面的代码很简单了,不在赘述,如果不懂反射建议学习一些,网上的资料也很多。

然后,我们来说说这个 让sdk有这个方法。这个是最复杂的一种解决方案,强烈不推荐使用,太费劲了,我只说一下简要的流程吧。首先我们要获取手机系统中/system/framework/framework.jar文件,framework.jar包含了所有隐藏的api,然后从中获取classes.dex,将其转化成classes.jar,再从classes.jar中解压获得android.jar,最后用这个android.jar编译我们的工程。好吧,心好累。。。这种方法比较锻炼人的各种技能,恩,作为一个爱探索的青年,我选择放弃。

最后来说说 让程序感觉开发时的sdk有这些类和方法。

这个,其实呢牛逼点的叫法应该是api欺骗,由于Android系统在加载类时是根据包名判断的,

那么我们就在我们的工程中建立一个一模一样的包,于是我们在项目中新建了包:com.android.internal.os,接下来再新建类PowerProfile.java,最后给类加入你需要的方法getAveragePower(),因为你需要知道方法签名,也就是返回值和参数列表,于是你不可避免的看了一眼Android源码。。。

哦,这样啊,函数体不用写,返回随意,只要按签名来就行,反正系统不会理你这个方法,这个方法唯一的作用就是让编译器感觉你的代码ok,没有调用不存在的东西,

但是! 当程序运行在设备上时~嘿嘿,系统加载了自己framework.jar中com.android.internal.os包的类文件,调用了自己类中的方法。

恩~这种方法就好像是~空手套白狼。。。。呜呜~程序员都是骗子!

有没有感觉又get了一个新技能?

由于api是隐藏的,相关方面的文档也是少得可怜,人家的东西就算拿来了也不一定会用啊(多么痛的领悟!)

最后的最后!!!!!!!!!!!!!!!!隐藏的api在不同系统版本下可能会产生不可预期的错误,正如前面所说的,其中的一些常量值在不同系统中都可能不一样!!!方法的参数列表也可能有差异!!!所以在用的时候千万要小心翼翼!!!!! 就这么多,收~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: