インストールされていないapkでリソースを読み込む

8532 ワード


package xxxxxxxxxxxxxxxxxxn.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import cn.com.lockscreen.activity.R;
import dalvik.system.DexClassLoader;

public class ReflectUtil {
    private static final String TAG = "ReflectUtil";
    public static final String DRAWABLE_STR = "drawable";
    public static final String INTEGER_STR = "integer";

    public static DexClassLoader LoadAPK(Context context, String dexpath, String dexoutputpath) {
        ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
        DexClassLoader localDexClassLoader = new DexClassLoader(dexpath, dexoutputpath, null, localClassLoader);
        Log.d(TAG, dexpath + " dex " + dexoutputpath);
        return localDexClassLoader;
    }

    //   apk     
    public static Resources getPackageResource(Context context, String apkPath) {
        try {
            //         
            //addAssetPath. Add an additional set of assets to the asset manager.  This can be
            // either a directory or ZIP file.
            Class<?> class_AssetManager = Class.forName("android.content.res.AssetManager");
            Object assetMag = class_AssetManager.newInstance();
            Method method_addAssetPath = class_AssetManager.getDeclaredMethod("addAssetPath", String.class);
            method_addAssetPath.invoke(assetMag, apkPath);
            //             
            Resources res = context.getResources();

            //            
            //Create a new Resources object on top of an existing set of assets in an
            //     * AssetManager.
            Constructor<?> constructor_Resources = Resources.class.getConstructor(class_AssetManager, res
                    .getDisplayMetrics().getClass(), res.getConfiguration().getClass());
            //    Resources
            res = (Resources) constructor_Resources.newInstance(assetMag, res.getDisplayMetrics(),
                    res.getConfiguration());
            return res;
            /*
             * String test = res.getString(id); System.out.println(test);
             */

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    void invoke(Context context, DexClassLoader dexClassLoader, Bundle paramBundle, String dexpath) {
        try {
            PackageInfo plocalObject = context.getPackageManager().getPackageArchiveInfo(dexpath, 1);
            if ((plocalObject.activities != null) && (plocalObject.activities.length > 0)) {
                String activityname = plocalObject.activities[0].name;
                Log.d(TAG, "activityname = " + activityname);
                Class localClass = dexClassLoader.loadClass(activityname);
                Constructor localConstructor = localClass.getConstructor(new Class[]{});
                Object instance = localConstructor.newInstance(new Object[]{});
                Log.d(TAG, "instance = " + instance);

                Method localMethodSetActivity = localClass.getDeclaredMethod("setActivity", new Class[]{Activity.class,
                        Bundle.class});
                localMethodSetActivity.setAccessible(true);
                localMethodSetActivity.invoke(instance, new Object[]{(Activity) context, paramBundle});

                /*
                 * Method methodonCreate =
                 * localClass.getDeclaredMethod("onCreate", new
                 * Class[]{Bundle.class}); methodonCreate.setAccessible(true);
                 * methodonCreate.invoke(instance, new Object[]{paramBundle});
                 */
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    //    XmlResourceParser
    public static ViewGroup getLayout(Context context, String dexpath,DexClassLoader dexClassLoader) {
        // If the package exists then get the resources within it.
        // Use the method in the class to get the views.
        Class<?> viewExtractor = null;
        PackageInfo plocalObject = context.getPackageManager().getPackageArchiveInfo(dexpath, 1);
        try {
            viewExtractor = dexClassLoader.loadClass(plocalObject.packageName + ".ViewExtractor");
            Log.d(TAG, viewExtractor+"  viewExtractor");
        } catch (Exception excep) {
//            continue;
            excep.printStackTrace();
        }

        View[] resultViews;
        try {
            Method m = viewExtractor.getDeclaredMethod("getAllViews", Context.class);
            resultViews = (View[]) m.invoke(null, new Object[]{context});
            Log.d(TAG, resultViews[0]+"  resultViews[0]");

            Class rClass = dexClassLoader.loadClass(plocalObject.packageName + ".R$layout");
            Field[] fields = rClass.getDeclaredFields();
            Log.d(TAG, "fields = " + Arrays.toString(fields));
            for (Field f : fields) {
                f.setAccessible(true);
                if (f.getName().equals("layout_0")) {
                    int i = f.getInt(new R.id());
                    XmlResourceParser layout = getPackageResource(context,dexpath).getLayout(i);
                    String name = layout.getName();
                    Log.d(TAG, "name = " + name);
                    layout.close();
                }
            }

            return (ViewGroup)resultViews[0];
            /*
            for (View v : resultViews) {
                 this.viewFlipper.addView(v);
                return v;
            }*/
        } catch (Exception excep) {
            excep.printStackTrace();
        }
        return null;
    }

    public static int getResId(PackageInfo plocalObject, DexClassLoader dexClassLoader, String intName, String type) {
        try {
            Class rClass = dexClassLoader.loadClass(plocalObject.packageName + ".R$" + type);
            Field[] fields = rClass.getDeclaredFields();
            Log.d(TAG, "getResIdByName fields = " + Arrays.toString(fields));
            for (Field f : fields) {
                //          
                f.setAccessible(true);
                System.out.println(f.getName());
                if (f.getName().equals(intName)) {
                    int i = f.getInt(new R.id());
                    return i;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return 0;
    }
}


使用例:

        DexClassLoader dexClassLoader = ReflectUtil.LoadAPK(context, PLUG_PATH + PLUG_NAME, file.getAbsolutePath());
        PackageInfo plocalObject = context.getPackageManager().getPackageArchiveInfo(PLUG_PATH + PLUG_NAME, 1);
        Resources plugRes = ReflectUtil.getPackageResource(context, PLUG_PATH + PLUG_NAME);
        
        int drawableId = ReflectUtil.getResId(plocalObject, dexClassLoader, "bg", ReflectUtil.DRAWABLE_STR);
        rootLayout.setBackground(plugRes.getDrawable(drawableId));

        int intId = ReflectUtil.getResId(plocalObject, dexClassLoader, "slide_y", ReflectUtil.INTEGER_STR);
        int integer = plugRes.getInteger(intId);
        sliderLayout.setY(integer);