美文网首页Android面试经验Android开发经验谈Android开发
Android反射调用未安装的APK打开activity

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

作者: Lazy1 | 来源:发表于2017-09-21 11:38 被阅读328次

    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 com.Company.Demo;
    
    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
     * 修改备注:
     * 联系方式:906514731@qq.com
     */
    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();
        }
    
      }
    
    }
    
    
    

    相关文章

      网友评论

      • IT小后生:插件中的ActivityA跳转到插件中的ActivityB怎么做
      • _夜雨:这样插件中的Activity只是一个对象而已,onCreate也只是被调用方法,其实它并不是Activity吧?
        Lazy1:@_夜雨 是的整个生命周期需要自己控制
      • one_cup:你这个是怎么绕过系统的检查的?
        Lazy1:@one_cup 这个其实只是简单创建了Activity对象而已,并不是一个完整的Activity,你可以看下这个
        http://blog.csdn.net/jiangwei0910410003/article/details/48104455
        one_cup: @Lazy1 那如果不绕过检查的话,不会报错吗,因为没有在manifest中注册啊
        Lazy1:@one_cup 并没有绕过,只是以反射方式创建Activity对象,需要自己来控制生命周期。

      本文标题:Android反射调用未安装的APK打开activity

      本文链接:https://www.haomeiwen.com/subject/beezsxtx.html