android开发笔记之reflect使用

前言

在看此文章前,请先查看下面几篇文章,理解一下reflect和Systemproperties系统属性的操作:
1.java核心技术之reflect(一):一个系统学习reflect的Demo(精)
2.github项目之读取系统属性
3.android开发笔记之system.prop使用(1)

问题

公司在搞应用apk化,也就是把android提供的应用导入androidstudio中,使用androidstudio来开发,并生成apk,内置到各个应用中。

这就有一些问题:
比如在androidstudio中,系统属性应用Systemproperties的操作api就使用不了。
再比如一些应用的功能,调用的接口的库文件不能导入到androidstudio,还有一些底层的比较特殊的接口,与硬件平台相关的接口(比如和MTK或高通相关的camera接口),当然了,还有就是一些private,protected相关的方法的调用。

此时,我们就可以使用reflect来解决这些要在androidstudio单独直接使用而不过依赖平台的接口,这样就可以直接在androidstudio中编译生成apk,直接内置到不同的平台上使用了。

说明,这是公司别的部门写的代码,我将其提出来,再重构了一下,方便自己来使用.

关键api

我们提供一个帮助类来专门处理此类问题ApiHelper.java:
此类,只是将reflect类的方便再封装了一下,没有什么特别的地方.

import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ApiHelper {

    private static final String TAG = "ApiHelper";

    public static final String FEATURE_CONFIG_BOOL_VALUE = "getBooleanValue";
    public static final String FEATURE_CONFIG_INT_VALUE = "getIntValue";
    public static final String SYSTEMPROPERTIES = "android.os.SystemProperties";


    public static Class<?> getClass(String className) {
        Class<?> class1 = null;
        try {
            class1 = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return class1;
    }


    public static boolean hasField(Class<?> klass, String fieldName) {
        try {
            klass.getDeclaredField(fieldName);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }

    public static boolean hasField(String className, String fieldName) {
        Class<?> cClass = getClass(className);
        try {
            cClass.getDeclaredField(fieldName);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }

    public static boolean hasMethod(String className, String methodName, Class<?>... parameterTypes) {
        Class<?> klass = null;
        try {
            klass = Class.forName(className);
            return hasMethod(klass,methodName,parameterTypes);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }

    }

    public static boolean hasMethod(Class<?> klass, String methodName, Class<?>... paramTypes) {
        try {
            klass.getDeclaredMethod(methodName, paramTypes);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    public static Object getField(String className, String fieldName) {
        Class<?> clazz = getClass(className);
        Object result = null;
        if (clazz != null) {
            Field field = null;
            try {
                field = clazz.getField(fieldName);
                // field = clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                Log.e(TAG, "getField:" + fieldName + " failed");
            }
            if (field != null) {
                try {
                    result = field.get(null);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    public static int getIntFieldIfExists(Class<?> klass, String fieldName, Class<?> obj, int defaultVal) {
        try {
            Field field = klass.getDeclaredField(fieldName);
            return field.getInt(obj);
        } catch (Exception e) {
            return defaultVal;
        }
    }

    public static Method getMethod(String className, String methodName, Class<?>... parameterTypes) {
        Method method = null;
        try {
            Class<?> clazz = Class.forName(className);
            method = clazz.getMethod(methodName, parameterTypes);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return method;
    }

    /* <p>If the underlying method is static, then the specified {@code obj}
     * argument is ignored. It may be null.
     */
    public static Object invokeMethod(Method method, Object obj, Object... parameters) {
        Object retObj = null;
        if (null == method /* || null == obj */)
            return null;
        try {
            method.setAccessible(true);
            retObj = method.invoke(obj, parameters);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            System.out.print(e.getTargetException());
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retObj;
    }




    public static Constructor<?> getConstructor(String className, Class<?>... parameterTypes) {

        Class<?> clazz  = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return getConstructor(clazz,parameterTypes);
    }

    public static Constructor<?> getConstructor(Class<?> class1, Class<?>... parameterTypes) {
        Constructor<?> constructor = null;
        if (class1 != null) {
            try {
                constructor = class1.getConstructor(parameterTypes);
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return constructor;
    }

    public static Object getInstance(Constructor<?> constructor, Object... parameters) {
        if (null == constructor)  return null;
        Object resultInstance = null;
        if (null != constructor) {
            if (null != parameters)
                try {
                    resultInstance = constructor.newInstance(parameters);
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            else
                try {
                    resultInstance = constructor.newInstance();
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
        return resultInstance;
    }


}

使用Demo

我在一个Activity中测试了一下主要api:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "debug_hxm";
    private AppCompatActivity context = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        testReflect();
    }

    private void testReflect() {
        context = this;

        String className = "android.os.SystemProperties";
        String fieldName = "PROP_NAME_MAX";
        String methodNameSet = "set";
        String methodNameGet = "get";
        String propFinger = "ro.build.fingerprint";
        //String propTest = "ro.pt.setMTPdefault";
        String propKey = "bluetooth.fw.rpa";


        //test field
        boolean hasField = ApiHelper.hasField(className,fieldName);
        Log.i(TAG,className+"----"+fieldName+"---"+hasField);
        Log.i(TAG,"---------------------------------------");

        //test method
        boolean hasMethod = ApiHelper.hasMethod(className,methodNameGet,String.class);
        Log.i(TAG,className+"----"+methodNameGet+"---"+hasMethod);
        hasMethod = ApiHelper.hasMethod(className,methodNameSet,String.class,String.class);
        Log.i(TAG,className+"----"+methodNameSet+"---"+hasMethod);
        hasMethod = ApiHelper.hasMethod(className,methodNameSet,String.class,int.class);
        Log.i(TAG,className+"----"+methodNameSet+"---"+hasMethod);
        Log.i(TAG,"---------------------------------------");


        //test invoke static method
        Method method = ApiHelper.getMethod(className,methodNameGet,String.class);
        String fingerprint = (String) ApiHelper.invokeMethod(method,null,propFinger);
        Log.i(TAG,"fingerprint:"+fingerprint);
        Log.i(TAG,"---------------------------------------");

        String propValue = (String) ApiHelper.invokeMethod(method,null,propKey);
        Log.i(TAG,"propValue:"+propValue);

        method = ApiHelper.getMethod(className,methodNameSet,String.class,String.class);
        ApiHelper.invokeMethod(method,null,propKey,"false");

        method = ApiHelper.getMethod(className,methodNameGet,String.class);
        propValue = (String)ApiHelper.invokeMethod(method,null,propKey);
        Log.i(TAG,"after set ,the propValue is:"+propValue);
        Log.i(TAG,"---------------------------------------");

        //test invoke method
        //context.onDestroy();
        className = "android.support.v7.app.AppCompatActivity";
        fieldName = "onDestroy";
        method = ApiHelper.getMethod(className,fieldName);
        ApiHelper.invokeMethod(method,context);
        Log.i(TAG,"--call android.support.v7.app.AppCompatActivity onDestroy()---");
        Log.i(TAG,"---------------------------------------");
    }
}

日志输出

I/debug_hxm: android.os.SystemProperties----PROP_NAME_MAX---true
I/debug_hxm: ---------------------------------------
I/debug_hxm: android.os.SystemProperties----get---true
I/debug_hxm: android.os.SystemProperties----set---true
I/debug_hxm: android.os.SystemProperties----set---false
I/debug_hxm: ---------------------------------------
I/debug_hxm: fingerprint:TINNO/k200/k200:7.0/NRD90M/1513592190:userdebug/release-keys
I/debug_hxm: ---------------------------------------
I/debug_hxm: propValue:true
I/debug_hxm: after set ,the propValue is:true
I/debug_hxm: ---------------------------------------
I/debug_hxm: --call android.support.v7.app.AppCompatActivity onDestroy()---
I/debug_hxm: ---------------------------------------

日志分析

日志:

I/debug_hxm: android.os.SystemProperties----PROP_NAME_MAX---true
I/debug_hxm: ---------------------------------------

此部分日志,我们测试类android.os.SystemProperties中是否有PROP_NAME_MAX变量,测试结果表明有.事实了也是,在类android.os.SystemProperties中:

public static final int PROP_NAME_MAX = 31;

相关的测试api为:

//test field
boolean hasField = ApiHelper.hasField(className,fieldName);
Log.i(TAG,className+"----"+fieldName+"---"+hasField);
Log.i(TAG,"---------------------------------------");

日志:

I/debug_hxm: android.os.SystemProperties----get---true
I/debug_hxm: android.os.SystemProperties----set---true
I/debug_hxm: android.os.SystemProperties----set---false

此剖分日志为我们测试类android.os.SystemProperties中的方法:
是否存在get(String),set(String,String),set(String,int)三种类型的方法.
测试结果为存在get(String),set(String,String)方法,但是不存在set(String,int)类型的方法.

相关的测试api为:

boolean hasMethod = ApiHelper.hasMethod(className,methodNameGet,String.class);
Log.i(TAG,className+"----"+methodNameGet+"---"+hasMethod);
hasMethod = ApiHelper.hasMethod(className,methodNameSet,String.class,String.class);
Log.i(TAG,className+"----"+methodNameSet+"---"+hasMethod);
hasMethod = ApiHelper.hasMethod(className,methodNameSet,String.class,int.class);
Log.i(TAG,className+"----"+methodNameSet+"---"+hasMethod);

日志:

I/debug_hxm: fingerprint:TINNO/k200/k200:7.0/NRD90M/1513592190:userdebug/release-keys

此部分日志为我们测试如何读取系统属性ro.build.fingerprint的值:

相关测试api:

Method method = ApiHelper.getMethod(className,methodNameGet,String.class);
String fingerprint = (String) ApiHelper.invokeMethod(method,null,propFinger);
Log.i(TAG,"fingerprint:"+fingerprint);

日志:

I/debug_hxm: propValue:true
I/debug_hxm: after set ,the propValue is:true

此部分日志为我们测试如何读写系统属性bluetooth.fw.rpa的值,测试的日志表明,reflect只能成功的读取系统属性的值,但是修改系统属性的值是做不到的,这是因为和系统权限相关的限制.

我查看了一下所有app源码,确实是只使用这种方式来读取系统属性性,没有修改系统属性值的地方.这是此方式的一个局限性吧.

相关测试api:

String propValue = (String) ApiHelper.invokeMethod(method,null,propKey);
Log.i(TAG,"propValue:"+propValue);

method = ApiHelper.getMethod(className,methodNameSet,String.class,String.class);
ApiHelper.invokeMethod(method,null,propKey,"false");

method = ApiHelper.getMethod(className,methodNameGet,String.class);
propValue = (String)ApiHelper.invokeMethod(method,null,propKey);
Log.i(TAG,"after set ,the propValue is:"+propValue);
Log.i(TAG,"---------------------------------------");

日志:

I/debug_hxm: --call android.support.v7.app.AppCompatActivity onDestroy()---

上面的测试,都是测试类的static方法.所以我加了一个测试对应对象的方法的api.这其实也是reflect使用的非常多的一种情况.

在类android.support.v7.app.AppCompatActivity中,onDestroy方法为protected 类型.使用对象直接调用是会报错的.

protected void onDestroy() {
    super.onDestroy();
    getDelegate().onDestroy();
}

所以我们使用context对象使用reflect的方式调用其方法,就可以正常调用.

相关测试api:

//test invoke method
//context.onDestroy();
className = "android.support.v7.app.AppCompatActivity";
fieldName = "onDestroy";
method = ApiHelper.getMethod(className,fieldName);
ApiHelper.invokeMethod(method,context);
Log.i(TAG,"--call android.support.v7.app.AppCompatActivity onDestroy()---");

猜你喜欢

转载自blog.csdn.net/hfreeman2008/article/details/78855864