Android动态代理实现修改App版本号

本文介绍如何使用动态代理技术,通过创建PackageManagerHook代理类,实现在不改变App实际版本号的情况下,动态修改显示的版本号和版本名称,适用于功能升级测试。重点解析了动态代理的实现原理和具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

应用场景

通过这个案例,我们可以了解一下动态代理技术,并且能够在不改变版本号的情况下,动态修改版本号进行升级功能的测试,主要实现原理是通过动态代理getPackageInfo()来mock数据。

一、创建PackageManagerHook代理类

public class PackageManagerHook {
  /**
   * 越早hook越好,推荐在Application.attachBaseContext中调用
   */
  public static void hook(final Context context) {
    try {
      //1、得到ActivityThread类
      Class<?> activityThreadClz = Class.forName("android.app.ActivityThread");
      Method currentActivityThread = activityThreadClz.getMethod("currentActivityThread");
      //2、得到当前的ActivityThread对象
      Object activityThread = currentActivityThread.invoke(null);
      //3、得到PackageManager对象
      Method getPackageManager = activityThreadClz.getMethod("getPackageManager");
      final Object pkgManager = getPackageManager.invoke(activityThread);

      Class<?> packageManagerClz = Class.forName("android.content.pm.IPackageManager");
      //hook sPackageManager
      Field packageManagerField = activityThreadClz.getDeclaredField("sPackageManager");
      packageManagerField.setAccessible(true);
      //动态代理
      packageManagerField.set(activityThread, Proxy.newProxyInstance(context.getClassLoader(),
          new Class[] { packageManagerClz }, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              Object result = method.invoke(pkgManager,args);
              if ("getPackageInfo".equals(method.getName())){
                PackageInfo pkgInfo = (PackageInfo) result;

                //修改App的版本信息
                pkgInfo.versionCode = 520;
                pkgInfo.versionName = "version:5.2.0";
              }
              return result;
            }
          }));
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    } catch (NoSuchFieldException e) {
      e.printStackTrace();
    }
  }
}

二、创建ProxyApplication

public class ProxyApplication extends Application {

  @Override
  protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    PackageManagerHook.hook(this);
  }
}

三、在AndroidManifest.xml设置

<application
  android:name=".ProxyApplication"
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  <activity android:name=".MainActivity">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
</application>

四、创建布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:textColor="#222222"
    android:textSize="18dp" />

</RelativeLayout>

五、在Activity中取值

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView textView = findViewById(R.id.text);
    PackageManager manager = this.getPackageManager();
    try {
      PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
      textView.setText(info.versionName + "," + info.versionCode);
    } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }
  }
}

六、运行结果

在这里插入图片描述

小结

通过上述步骤,我们可以通过动态代理技术,修改App的版本号和版本名,重点理解一下PackageManagerHook中的代码,祝大家学习愉快~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖子爱你520

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值