热门搜索 :
考研考公
您的当前位置:首页正文

Android反射调用未安装的APK打开activity

来源:东饰资讯网

1.思路:

  • 1.1 通过getPackageArchiveInfo方法获取sd卡的未安装的APK信息和Activity
  • 1.2 获取到插件Activity的信息之后,通过反射得到插件Activity的实例
  • 1.3 获取到插件Activity的实例后通过构造函数将宿主的上下文传递到插件APP
  • 1.4 在反射调用插件activity的onCreate方法

2.宿主代码

package com.lazy.dex;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import dalvik.system.DexClassLoader;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {

  private String mClass;
  String dexPath = Environment.getExternalStorageDirectory().toString() + File.separator + "a";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.bt).setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        launchTargetActivity();
      }
    });
  }


  @SuppressLint("NewApi")
  protected void launchTargetActivity() {
    //根据sd卡的路径获取未安装的apk的信息
    PackageInfo packageInfo = getPackageManager().getPackageArchiveInfo(dexPath, 1);
    if ((packageInfo.activities != null)
        && (packageInfo.activities.length > 0)) {
      String activityName = packageInfo.activities[0].name;//获取插件中第一个activity
      mClass = activityName;
      launchTargetActivity(mClass);
    }
  }

  @SuppressLint("NewApi")
  protected void launchTargetActivity(final String className) {
    Log.e("MainActivity", "start launchTargetActivity, className=" + className);
    File dexOutputDir = this.getDir("dex", 0);
    final String dexOutputPath = dexOutputDir.getAbsolutePath();
    ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
    DexClassLoader dexClassLoader = new DexClassLoader(dexPath,
        dexOutputPath, null, localClassLoader);
    try {
      Class<?> localClass = dexClassLoader.loadClass(className);//创建插件Activity的实例
      //调用插件Activity的构造函数,将当前activity的上下文传递到插件activity中去
      Constructor<?> localConstructor = localClass.getConstructor(new Class[]{Activity.class});
      Object instance = localConstructor.newInstance(new Object[]{this});
      Log.e("MainActivity", "instance = " + instance);
      Method onCreate = localClass.getDeclaredMethod("onCreate", new Class[]{Bundle.class});
      onCreate.setAccessible(true);
      Bundle bundle = new Bundle();
      onCreate.invoke(instance, bundle);//调用插件activity的onCreate方法
    } catch (Exception e) {
      Log.e("MainActivity", e.getMessage());
    }
  }


}


3.APP插件代码

package 

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

/**
 * 项目名称:Demo1
 * 类描述:
 * 创建人:Administrator
 * 创建时间:2017/9/20 17:24
 * 修改人:Administrator
 * 修改时间:2017/9/20 17:24
 * 修改备注:
 * 
 */
public class TestActivity extends Activity implements OnClickListener {

  /**
   * 宿主的上下文引用
   */
  private Activity otherActivity;

  /**
   * 无参构造函数
   */
  public TestActivity() {
    super();
  }

  /**
   * 有参构造函数
   * @param context
   */
  public TestActivity(Activity context) {
    super();
    otherActivity = context;
    Log.e("TestActivity", otherActivity.toString() );
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    if (otherActivity != null) {
      // 使用TestHallActivity的上下文引用创建View并添加到根视图
      Button button = new Button(otherActivity);
      button.setText("我是插件TestActivity");
      button.setOnClickListener(this);

      LinearLayout root = new LinearLayout(otherActivity);

      root.addView(button);

      //使用宿主的上线文就不能使用插件的资源了
      otherActivity.setContentView(root);

    } else {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    }
  }

  /**
   * 返回当前Activity的描述信息
   * @return
   */
  private String getRoomMessage() {
    return "我是插件TestActivity";
  }

  @Override
  public void onClick(View v) {

    if (otherActivity != null) {
      // Toast.makeText(this, "This is Room A!", Toast.LENGTH_SHORT).show();是不合适的调用
      Toast.makeText(otherActivity, "我是插件TestActivity", Toast.LENGTH_SHORT).show();
    } else {
      Toast.makeText(this, "我是插件TestActivity", Toast.LENGTH_SHORT).show();
    }

  }

}


Top