我看到了一些SO帖子,其中讨论了如何以编程方式结束电话,例如this one。是的,人们专注于结果,但没人能真正解释为何起作用的原因吗?
我尝试了代码,效果很好。但是我想知道更多有关下面发生的事情的细节吗?为什么通过创建 ITelephony.aidl ,在我们的项目中公开了android隐藏的内部ITelephony
接口(interface)?我们自己如何创建 ITelephony.aidl 和自动生成的Java(/gen/ITelephony.java)链接到 android的ITelephony
接口(interface)?仅仅是因为名称匹配(软件包名称和辅助文件名称)吗?
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
//Why does the android internal ITelephony interface is exposed after created the ITelephony.aidl?
com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm);
telephonyService.endCall();
最佳答案
实际上,没有必要将ITelephony.aidl
添加到您的项目中,这只是一种方便。您也可以这样做:
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
在幕后,所有这些工作都使用Java反射来访问私有(private)(即,未公开记录)的方法。通过阅读开源(即公开可用)的Android源代码,您可以弄清楚那里有什么方法,以及它们做了什么。一旦知道了那里有什么,它做什么了,就可以使用反射来到达它,即使它是“隐藏的”。
TelephonyManager
类是使用远程服务实现的。如果要请求TelephonyManager
为您做某事,请在TelephonyManager
上调用一个方法(这是公开记录的部分),并在内部调用远程电话服务以实际完成工作。这是使用AIDL(这是一种“远程过程调用”)完成的。远程服务可以执行未通过TelephonyManager
类公开公开的事情。您在这里所做的是使用getITelephony()
获取“远程过程调用”接口(interface)的客户端。这将返回ITelephony
类型的对象。此类具有一个名为endCall()
的方法。一旦有了ITelephony
类型的对象,我们就可以获取其Class对象,然后从Class中获取endCall()
方法。一旦有了方法,就可以访问它,然后调用它。方法endCall()
在远程过程调用的客户端中。现在,该方法将消息发送到电话管理器服务(在远程服务器上运行),并要求其结束调用。由于
ITelephony.aidl
的源代码是公开可用的,因此您可以将源代码放入项目中,并且IDE将从ITelephony.java
生成ITelephony.aidl
(包含远程过程调用的客户端)。然后,您只需import
即可,您的IDE现在将知道ITelephony
类及其方法。这允许编译器在编译项目时生成正确的字节码。在Android设备上运行此代码时,请调用Android框架以获取ITelephony
对象,然后将其强制转换为com.android.internal.telephony.ITelephony
。从那时起,只要您拥有ITelephony.java
的Java代码与返回的ITelephony
对象的实际类定义相匹配,就可以使用生成的ITelephony
访问对象的方法和字段。如果类定义不匹配,则VM将引发适当的异常。我希望这回答了你的问题。我不确定您已经知道多少,所以也许我提到了您已经知道的东西。如果是这样,对此感到抱歉。如果不清楚,请指出您完全不了解的内容。
关于android - 为什么ITelephony.aidl可以工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18977012/