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

时间:2012-02-20 22:51:19

标签: java android reflection telephony illegalargumentexception

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

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

com.android.internal.telephony.gsm.GSMPhone

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

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

我写过这个,但不断获得非法参数异常。这是我的代码:

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();

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

以下是错误日志:

Error Log


我忘记提及的其他事情是我使用以下代码检查此方法是否确实存在于类文件中:

        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在数组中返回。所以我相信它在那里,我可以以某种方式使用它。

7 个答案:

答案 0 :(得分:1)

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

您将其传递给setLine1Number.invoke()

例如,如果我们正在处理您要说的Integer课程:

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

答案 1 :(得分:1)

您必须创建一个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);

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

我不熟悉任何Android API,所以我不确定如何获取它的实例。

编辑:查看GSMPhone它调用SIMRecords的公共方法,也许您可​​以获取该类的实例并调用该方法?

答案 4 :(得分:0)

如果您想设置不可访问的字段或调用不可访问的方法,可以根据需要将它们设置为可访问 参见:

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

(第34-37行)

答案 5 :(得分:0)

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;
    }

答案 6 :(得分:-1)

请尝试以下代码。

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);