如何正确使用reflection来访问Telephony Manager中的隐藏方法

我不确定我是否在反思本身或我想要获得的方法上遇到麻烦。

我想做的是从类中调用函数setLine1Number:

com.android.internal.telephony.gsm.GSMPhone 

这样我就可以将我的号码正确插入手机,因为它不需要在我的SIM卡中。 因此,我希望能够调用函数getLine1Number并让它返回我设置的相同数字。

reflection似乎是能够使用此function的唯一方法,因为它不在公共API中。

我写过这篇文章,但不断获得非法论证exception。 这是我的代码:

 String className = "com.android.internal.telephony.gsm.GSMPhone"; Class classToInvestigate = Class.forName(className); Object arglist[] = new Object[3]; arglist[0] = new String("Phone Number"); arglist[1] = new String ("16035552412"); // Not a real phone number arglist[2] = null; Class[] paramTypes = new Class[3]; paramTypes[0] = String.class; paramTypes[1] = String.class; paramTypes[2] = Message.class; Method setLine1Number = classToInvestigate.getMethod("setLine1Number", paramTypes); setLine1Number.setAccessible(true); Object TestReturn = setLine1Number.invoke(classToInvestigate, arglist); // Problem is here. Not sure how to properly do this. 

现在,在这一点上,我想,如果我可以打电话

 TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); String PhoneNumber2 = telephonyManager.getLine1Number(); 

并让它返回我输入的数字。 但正如我所说的非法论证exception,我不确定如何解决这个问题。 任何帮助赞赏。 我仍然很反思,所以这可能是一个简单的问题。

这是错误日志:

错误日志


我忘了提到的其他事情是我使用以下代码来检查这个方法是否真的存在于类文件中:

  Method[] checkMethod = classToInvestigate.getDeclaredMethods(); Test = new String[checkMethod.length]; int i = 0; for(Method m : checkMethod) { // Found a method m Test[i] = m.getName(); i++; } 

并且在数组中返回方法setLine1Number。 所以我相信它在那里,我可以以某种方式使用它。

您需要一个您希望操作的类的实例 – 已经创建的该类型的对象。

你把它传递给setLine1Number.invoke()

例如,如果我们处理Integer类,你会说:

 Integer i = new Integer(5); ... Object TestReturn = someIntegerMethod.invoke(i, arglist); 

您必须创建一个GSMPhone实例(classToInvestigate)。 这是一个开始:

 Class commandsInterface = Class.forName("com.android.internal.telephony.CommandsInterface"); Class phoneNotifier = Class.forName("com.android.internal.telephony.PhoneNotifier"); Constructor constructor = classToInvestigate.getConstructor(Context.class, commandsInterface, phoneNotifier); // This creation of newInstance will have to be modified depending on NullPointerExceptions. // Will probably have to pass in context, as well as instantiate CommandsInterface and PhoneNotifier in a similar fashion and then inject them as well. Object newInstance = constructor.newInstance(context, null, null); setLine1Number.invoke(newInstance, arglist); 

您需要传入要调用方法的类型的对象,而不是类对象。

invoke调用中,您需要传递GSMPhone类的实例而不是classToInvestigate

我不熟悉任何Android API,所以我不知道如何获得它的实例。

编辑:看GSMPhone它调用SIMRecords的公共方法也许你可以获得该类的实例并调用该方法?

如果您想设置不可访问的字段或调用不可访问的方法,您可以将它们设置为可访问(如果您喜欢)请参阅:

https://github.com/ko5tik/andject/blob/master/src/main/java/de/pribluda/android/andject/ViewInjector.java

(第34-37行)

1)我建议使用“com.android.internal.telephony.Phone”而不是“…. gsm.GSMPhone”

2)在开始时尝试这个(并在调用setLine1Number方法时使用mPhone):注意:如果你愿意,可以省略try / catch,但是设置你的调用方法来抛出所有东西……

 private static final String CLASS_PHONEFACTORY = "com.android.internal.telephony.PhoneFactory"; private static final String METHOD_GETDEFAULTPHONE = "getDefaultPhone"; private Class cPhoneFactory; private Class cPhone; private Method mGetDefaultPhone; private Object mPhone; 

  try { cPhoneFactory = Class.forName(CLASS_PHONEFACTORY); } catch (ClassNotFoundException e) { cPhoneFactory = null; } try { cPhone = Class.forName(CLASS_PHONE); } catch (ClassNotFoundException e) { cPhone = null; } try { mGetDefaultPhone = cPhoneFactory == null ? null : cPhoneFactory.getMethod(METHOD_GETDEFAULTPHONE,(Class[])null); } catch (NoSuchMethodException e) { mGetDefaultPhone = null; } try { mPhone = mGetDefaultPhone == null ? null : mGetDefaultPhone.invoke(null,(Object[])null); } catch (Exception e) { mPhone = null; } 

请尝试以下代码。

 String className = "com.android.internal.telephony.gsm.GSMPhone"; Class classToInvestigate = Class.forName(className); Object gsmObj = classToInvestigate.newInstance(); Object arglist[] = new Object[3]; arglist[0] = new String("Phone Number"); arglist[1] = new String ("16035552412"); // Not a real phone number arglist[2] = null; Class[] paramTypes = new Class[3]; paramTypes[0] = String.class; paramTypes[1] = String.class; paramTypes[2] = Message.class; Method setLine1Number = classToInvestigate.getMethod("setLine1Number", paramTypes); boolean accessible = setLine1Number.isAccessible(); setLine1Number.setAccessible(true); Object TestReturn = setLine1Number.invoke(gsmObj, arglist);