tyc600 发表于 2024-11-15 08:02

Android7.0 xposed hook到activity对象如何保存该对象为全局变量供外部类调用

本帖最后由 tyc600 于 2024-11-15 08:18 编辑

如下图所示我已经成功hook到activity后注册了一个动态广播来响应外部类的调用。

代码1:hook到activity对象
import android.app.Activity;
import android.os.Bundle;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

public class MyRecHook {
    public MyRecHook() {
      XposedBridge.log("MyHook start MyRecHook");
      XposedHelpers.findAndHookMethod(Activity.class, "onCreate", new Object[]{Bundle.class, new MyRecHook$1(this)});
    }
}
代码2:内部类,注册动态广播
import android.app.Activity;
import android.content.IntentFilter;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;

class MyRecHook$1 extends XC_MethodHook {
    final MyRecHook this$0;

    MyRecHook$1(MyRecHook myRecHook) {
      this.this$0 = myRecHook;
    }

    protected void beforeHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable {
      super.beforeHookedMethod(methodHookParam);
    }

    protected void afterHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable {
      super.afterHookedMethod(methodHookParam);
      try {
            XposedBridge.log("MyHook start hook");
            ((Activity) methodHookParam.thisObject).registerReceiver(new MyRecHook$1$1(this, methodHookParam), new IntentFilter("my.screen.action"));
      } catch (Exception e) {
            e.printStackTrace();
      }
    }
}
代码3:内部类,响应外部对activity的调用
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import github.xposed.MyRecHook;

class MyRecHook$1$1 extends BroadcastReceiver {
    final MyRecHook.1 this$1;
    final XC_MethodHook.MethodHookParam val$param;

    MyRecHook$1$1(MyRecHook.1 r1, XC_MethodHook.MethodHookParam methodHookParam) {
      this.this$1 = r1;
      this.val$param = methodHookParam;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
      int intExtra = intent.getIntExtra("screen", 0);
      XposedBridge.log(context.getPackageName() + "收到屏幕旋转事件" + intExtra);
      ((Activity) this.val$param.thisObject).setRequestedOrientation(intExtra);
    }
}
为了避免频繁的注册动态广播【因为实际上这个activity只在部分需要的场合才需要被调用,显然每次都hook到对象都注册动态广播对系统资源造成负担】,后来我尝试将获取到的activity对象保存为全局变量,
import android.app.Activity;
import android.content.IntentFilter;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;

class MyRecHook$1 extends XC_MethodHook {
    final MyRecHook this$0;

    MyRecHook$1(MyRecHook myRecHook) {
      this.this$0 = myRecHook;
    }

    protected void beforeHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable {
      super.beforeHookedMethod(methodHookParam);
    }

    protected void afterHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable {
      super.afterHookedMethod(methodHookParam);
      try {
            XposedBridge.log("MyHook start hook");
            new IntentFilter("my.screen.action");
【★★★修改了此行★★★】AppEnv.j().setActivity((Activity) methodHookParam.thisObject);
      } catch (Exception e) {
            e.printStackTrace();
      }
    }
}

用于存储activity对象,并响应外部调用类如下,但是运行后报错如下【,】,如何保存activity为全局变量还请路过的大虾指点一下。
import android.app.Activity;
import java.lang.ref.WeakReference;

public class AppEnv {
    private static final AppEnv o = new AppEnv$1();
    private WeakReference<Activity> myactivity;

    public static AppEnv j() {
      return o;
    }

    public final void setRequestedOrientation(int i) {
      WeakReference<Activity> weakReference = this.myactivity;
      if (weakReference != null) {
            weakReference.get().setRequestedOrientation(i);
      }
    }

    public final void setActivity(Activity activity) {
      WeakReference<Activity> weakReference = this.myactivity;
      if (weakReference != null) {
            weakReference.clear();
      }
      this.myactivity = new WeakReference<>(activity);
    }
}
内部类赋值操作如下:
import android.app.Activity;

class AppEnv$1 extends AppEnv {
    AppEnv$1() {
      setActivity((Activity) null);
    }
}

linglingsan 发表于 2024-11-16 09:45

试一下扔给国内的大模型来帮你分析一下呢,以下是我扔给大模型给的回答;
[*]使用弱引用(WeakReference)保存 Activity

[*]弱引用允许垃圾回收器在对象不再被强引用时回收它,这有助于避免因 Activity 被销毁而导致的内存泄漏问题。
[*]在 Xposed 模块中,修改代码如下:
import android.app.Activity;import android.content.Intent;import android.content.IntentFilter;import android.content.res.Configuration;import android.util.Log;import android.view.WindowManager;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook;import de.robv.android.xposed.XposedBridge;import de.robv.android.xposed.XposedHelpers;import de.robv.android.xposed.callbacks.XC_LoadPackage;import java.lang.ref.WeakReference;public class HookModule implements IXposedHookLoadPackage {    private static WeakReference<Activity> activityWeakReference;    @Override    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {      if ("目标应用包名".equals(lpparam.packageName)) {            XposedHelpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() {                @Override                protected void afterHookedMethod(MethodHookParam param) throws Throwable {                  super.afterHookedMethod(param);                  Activity activity = (Activity) param.thisObject;                  activityWeakReference = new WeakReference<>(activity);                  Log.d("HookModule", "Activity onCreate: " + activity);                  // 注册广播接收者                  registerBroadcastReceiver(activity);                }            });      }    }    private void registerBroadcastReceiver(Activity activity) {      BroadcastReceiver receiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                if (intent.getAction().equals("your_action")) {                  Log.d("HookModule", "Received broadcast in Activity: " + activityWeakReference.get());                  if (activityWeakReference.get()!= null) {                        int orientation = intent.getIntExtra("orientation", Configuration.ORIENTATION_UNDEFINED);                        activityWeakReference.get().setRequestedOrientation(orientation);                  }                }            }      };      IntentFilter filter = new IntentFilter("your_action");      activity.registerReceiver(receiver, filter);    }}




[*]在广播接收者中处理 Activity 可能为空的情况

[*]在广播接收者的 onReceive 方法中,每次使用 activityWeakReference 之前,都要检查它是否为空。
[*]如果为空,可能表示 Activity 已经被销毁,此时不执行与 Activity 相关的操作,或者根据需求进行其他处理,例如重新获取 Activity(如果可能的话)或记录错误信息。

linglingsan 发表于 2024-11-16 09:49

试一下扔给国内的大模型来帮你分析一下呢,以下是我扔给大模型给的回答;
[*]使用弱引用(WeakReference)保存 Activity

[*]弱引用允许垃圾回收器在对象不再被强引用时回收它,这有助于避免因 Activity 被销毁而导致的内存泄漏问题。
[*]在 Xposed 模块中,修改代码如下:
java
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.util.Log;
import android.view.WindowManager;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import java.lang.ref.WeakReference;

public class HookModule implements IXposedHookLoadPackage {

private static WeakReference<Activity> activityWeakReference;

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if ("目标应用包名".equals(lpparam.packageName)) {
XposedHelpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Activity activity = (Activity) param.thisObject;
activityWeakReference = new WeakReference<>(activity);
Log.d("HookModule", "Activity onCreate: " + activity);

// 注册广播接收者
registerBroadcastReceiver(activity);
}
});
}
}

private void registerBroadcastReceiver(Activity activity) {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("your_action")) {
Log.d("HookModule", "Received broadcast in Activity: " + activityWeakReference.get());
if (activityWeakReference.get()!= null) {
int orientation = intent.getIntExtra("orientation", Configuration.ORIENTATION_UNDEFINED);
activityWeakReference.get().setRequestedOrientation(orientation);
}
}
}
};
IntentFilter filter = new IntentFilter("your_action");
activity.registerReceiver(receiver, filter);
}
}



[*]在广播接收者中处理 Activity 可能为空的情况

[*]在广播接收者的 onReceive 方法中,每次使用 activityWeakReference 之前,都要检查它是否为空。
[*]如果为空,可能表示 Activity 已经被销毁,此时不执行与 Activity 相关的操作,或者根据需求进行其他处理,例如重新获取 Activity(如果可能的话)或记录错误信息。

tyc600 发表于 2024-11-16 18:33

linglingsan 发表于 2024-11-16 09:49
试一下扔给国内的大模型来帮你分析一下呢,以下是我扔给大模型给的回答;
[*]使用弱引用(WeakReference) ...

谢谢回答,但是大模型的回答好像和我一开始已经超过的方式一样:使用了动态广播来响应外部调用,我要求回避这种方式。有没有更贴合要求的方案?
页: [1]
查看完整版本: Android7.0 xposed hook到activity对象如何保存该对象为全局变量供外部类调用