【问题标题】:How to properly use reflection to access hidden methods in Telephony Manager如何正确使用反射访问 Telephony Manager 中的隐藏方法
【发布时间】:2012-02-20 22:51:19
【问题描述】:

我不确定我是否遇到了反射本身的问题,或者我尝试获取的方法。

我想做的是从类中调用函数 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();

并让它返回我输入的数字。但正如我所说的非法参数异常,我不确定如何解决这个问题。任何帮助表示赞赏。我对反思还是陌生的,所以这可能是一个简单的问题。

这是错误日志:


还有一点我忘了提的是,我使用下面的代码来检查这个方法是否真的存在于类文件中:

        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 方法。所以我相当有信心它就在那里,我可以以某种方式使用它。

【问题讨论】:

    标签: java android reflection telephony illegalargumentexception


    【解决方案1】:

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

    你把它传给setLine1Number.invoke()

    例如,如果我们正在处理 Integer 类,您会说:

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

    【讨论】:

    • 感谢您的回复!好的,我现在明白我需要传入一个我想要操作的类的实例。知道如何创建 classToInvestigate 的实例吗?
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      你需要传入一个你想要调用方法的类型的对象,而不是类对象。

      【讨论】:

      • 感谢您的快速回复!这可能是我感到困惑的部分。您要调用该方法的类型的对象是什么意思?你也许有一个例子?
      • 我找不到任何好的例子,因为我发现的所有例子都调用了用户定义的类,而不是只能通过反射访问的类。
      【解决方案4】:

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

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

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

      【讨论】:

      • 感谢文森特的回复。我正在尝试获取此实例,但没有任何运气。如果你对此有更多的指导,那就太好了。感谢您的帮助。
      【解决方案5】:

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

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

      (第 34-37 行)

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          请尝试以下代码。

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

          【讨论】:

          • 嗨,杰森,感谢您的回复。我已经在第 3 行不断收到 InstantiationException 尝试了您的代码。有什么想法吗?
          猜你喜欢
          • 2018-07-09
          • 2015-09-24
          • 1970-01-01
          • 1970-01-01
          • 2011-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多