2020-09-02

package com.bigyu.myapplication;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import dalvik.system.DexClassLoader;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author bigyu
 */
public class ProxyActivity extends AppCompatActivity {
    private static final String TAG           = "ProxyActivity";
    public static final  String FROM          = "extra.from";
    public static final  int    FROM_EXTERNAL = 0;
    public static final  int    FROM_INTERNAL = 1;

    public static final String EXTRA_DEX_PATH = "extra.dex.path";
    public static final String EXTRA_CLASS    = "extra.class";

    private String              mClass;
    private String              mDexPath;
    //远程Activity
    private Activity            remoteActivity;
    //生命周期相关的方法
    private Map<String, Method> mActivityLifecircleMethods = new HashMap<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDexPath = getIntent().getStringExtra(EXTRA_DEX_PATH);
        mClass = getIntent().getStringExtra(EXTRA_CLASS);

        File mFile = new File(mDexPath);
        mLayoutInflater = LayoutInflater.from(this);
        initAssetManager(mFile);
        if (mClass != null) {
            launchTargetActivity(mClass);
        }
    }

    //activity的命名规则是:全包名+类名,例如 com.example.client.MainActivity
    protected void launchTargetActivity(final String className) {
        File         dexOutputDir     = this.getDir("dex", 0);
        final String dexOutputPath    = dexOutputDir.getAbsolutePath();
        ClassLoader  localClassLoader = ClassLoader.getSystemClassLoader();
        DexClassLoader dexClassLoader = new DexClassLoader(mDexPath, dexOutputPath, null,
                                                           localClassLoader);
        try {
            Class<?>       remoteClass       = dexClassLoader.loadClass(className);
            Constructor<?> remoteConstructor = remoteClass.getConstructor(new Class[]{});
            //创建远程Activity
            Object instance = remoteConstructor.newInstance(new Object[]{});
            remoteActivity = (Activity) instance;

            //设置远程Activity的代理,即ProxyActivity
            Method setProxy = remoteClass.getMethod("setProxy", new Class[]{Activity.class});
            setProxy.setAccessible(true);
            setProxy.invoke(instance, new Object[]{this});

            Method setResourcesM = remoteClass.getMethod("setResourcesM",
                                                         new Class[]{AssetManager.class, Resources.class, LayoutInflater.class});
            setResourcesM.setAccessible(true);
            setResourcesM
                    .invoke(instance, new Object[]{mAssetManager, mResources, mLayoutInflater});


            //手动执行远程Activity的onCreate方法
            Method onCreate = remoteClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class});
            onCreate.setAccessible(true);
            Bundle bundle = new Bundle();
            bundle.putInt(FROM, FROM_EXTERNAL);
            onCreate.invoke(instance, new Object[]{bundle});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //localClass就是从APK中解析出的Activity的Class对象
    //这个方法将这个Activity中的生命周期相关的方法都取出来放进一个Map;
    protected void bindLifecircleMethods(Class<?> localClass) {
        String[] methodNames = new String[]{"onRestart", "onStart", "onResume", "onPause", "onStop", "onDestory"};
        for (String methodName : methodNames) {
            Method method = null;
            try {
                method = localClass.getDeclaredMethod(methodName, new Class[]{});
                method.setAccessible(true);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            mActivityLifecircleMethods.put(methodName, method);
        }

        Method onCreate = null;
        try {
            onCreate = localClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class});
            onCreate.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        mActivityLifecircleMethods.put("onCreate", onCreate);

        Method onActivityResult = null;
        try {
            onActivityResult = localClass.getDeclaredMethod("onActivityResult",
                                                            new Class[]{int.class, int.class, Intent.class});
            onActivityResult.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        mActivityLifecircleMethods.put("onActivityResult", onActivityResult);
    }

    @Override
    //这里在Proxy执行生命周期相关的方法时调用远程Activity的生命周期方法就可以了
    protected void onResume() {
        super.onResume();
        Method onResume = mActivityLifecircleMethods.get("onResume");
        if (onResume != null) {
            try {
                onResume.invoke(remoteActivity, new Object[]{});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void launch(Activity activity, String url, String clazz) {
        Intent intent = new Intent(activity, ProxyActivity.class);
        intent.putExtra(EXTRA_DEX_PATH, url);
        intent.putExtra(EXTRA_CLASS, clazz);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        activity.startActivity(intent);
    }

    AssetManager   mAssetManager;
    Resources      mResources;
    LayoutInflater mLayoutInflater;

    @SuppressLint("DiscouragedPrivateApi")
    private void initAssetManager(File apkFile) {
        try {
            mAssetManager = AssetManager.class.newInstance();
            Method addAssetPathMethod = AssetManager.class
                    .getDeclaredMethod("addAssetPath", String.class);
            addAssetPathMethod.setAccessible(true);
            int result = (int) addAssetPathMethod.invoke(mAssetManager, apkFile.getAbsolutePath());
            Log.e("TAG", "initAssetManager: addAssetPath " + result);
            Method ensureStringBlocksMethod = AssetManager.class
                    .getDeclaredMethod("ensureStringBlocks");
            ensureStringBlocksMethod.setAccessible(true);
            ensureStringBlocksMethod.invoke(mAssetManager);

            mResources = new Resources(mAssetManager, getResources().getDisplayMetrics(),
                                       getResources().getConfiguration());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值