Skip to content

Commit e93d87d

Browse files
committed
支持 Activity#finishAffinity
1 parent f6faa0d commit e93d87d

File tree

2 files changed

+151
-9
lines changed

2 files changed

+151
-9
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package org.xplugin.core.app;
2+
3+
import android.app.Activity;
4+
import android.app.Application;
5+
import android.content.pm.ActivityInfo;
6+
import android.os.Bundle;
7+
import android.text.TextUtils;
8+
9+
import org.xplugin.core.ctx.Plugin;
10+
import org.xplugin.core.util.ReflectMethod;
11+
import org.xplugin.core.util.Reflector;
12+
import org.xutils.common.util.LogUtil;
13+
14+
import java.lang.ref.WeakReference;
15+
import java.util.ArrayList;
16+
import java.util.LinkedHashMap;
17+
import java.util.ListIterator;
18+
import java.util.Map;
19+
20+
public class ActivityLifecycleMonitor implements Application.ActivityLifecycleCallbacks {
21+
22+
private static ReflectMethod getActivityToken = null;
23+
private final static LinkedHashMap<Object, WeakReference<Activity>> ACTIVITYS;
24+
25+
static {
26+
ACTIVITYS = new LinkedHashMap<Object, WeakReference<Activity>>();
27+
try {
28+
getActivityToken = Reflector.on(Activity.class).method("getActivityToken");
29+
} catch (Throwable ex) {
30+
LogUtil.e(ex.getMessage(), ex);
31+
}
32+
}
33+
34+
public ActivityLifecycleMonitor() {
35+
}
36+
37+
public static boolean finishActivityAffinity(String affinity) {
38+
if (getActivityToken != null) {
39+
synchronized (ACTIVITYS) {
40+
try {
41+
ListIterator<Map.Entry<Object, WeakReference<Activity>>> iterator
42+
= new ArrayList<Map.Entry<Object, WeakReference<Activity>>>(ACTIVITYS.entrySet()).listIterator(ACTIVITYS.size());
43+
while (iterator.hasPrevious()) {
44+
Map.Entry<Object, WeakReference<Activity>> entry = iterator.previous();
45+
WeakReference<Activity> value = entry.getValue();
46+
if (value != null) {
47+
Activity activity = value.get();
48+
if (activity != null) {
49+
while (activity.getParent() != null) {
50+
Activity parent = activity.getParent();
51+
if (parent != null) {
52+
activity = parent;
53+
}
54+
}
55+
56+
ActivityInfo info = Plugin.getPlugin(activity).getConfig().findActivityInfoByClassName(activity.getClass().getName());
57+
if (info != null && TextUtils.equals(info.taskAffinity, affinity)) {
58+
activity.finish();
59+
} else {
60+
break;
61+
}
62+
} else {
63+
iterator.remove();
64+
}
65+
} else {
66+
iterator.remove();
67+
}
68+
}
69+
} catch (Throwable ex) {
70+
LogUtil.e(ex.getMessage(), ex);
71+
}
72+
}
73+
return true;
74+
} else {
75+
return false;
76+
}
77+
}
78+
79+
@Override
80+
public void onActivityCreated(Activity activity, Bundle bundle) {
81+
if (getActivityToken != null) {
82+
synchronized (ACTIVITYS) {
83+
try {
84+
ACTIVITYS.put(getActivityToken.callByCaller(activity), new WeakReference<Activity>(activity));
85+
} catch (Throwable ex) {
86+
LogUtil.e(ex.getMessage(), ex);
87+
}
88+
}
89+
}
90+
}
91+
92+
@Override
93+
public void onActivityDestroyed(Activity activity) {
94+
if (getActivityToken != null) {
95+
synchronized (ACTIVITYS) {
96+
try {
97+
ACTIVITYS.remove(getActivityToken.callByCaller(activity));
98+
} catch (Throwable ex) {
99+
LogUtil.e(ex.getMessage(), ex);
100+
}
101+
}
102+
}
103+
}
104+
105+
@Override
106+
public void onActivityStarted(Activity activity) {
107+
}
108+
109+
@Override
110+
public void onActivityResumed(Activity activity) {
111+
}
112+
113+
@Override
114+
public void onActivityPaused(Activity activity) {
115+
}
116+
117+
@Override
118+
public void onActivityStopped(Activity activity) {
119+
}
120+
121+
@Override
122+
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
123+
}
124+
}

xplugin/src/main/java/org/xplugin/core/app/ActivityManagerHandler.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import android.app.Service;
55
import android.content.Intent;
66
import android.content.ServiceConnection;
7+
import android.content.pm.ActivityInfo;
78
import android.os.IBinder;
89
import android.util.Log;
910

1011
import org.xplugin.core.ctx.Plugin;
1112
import org.xplugin.core.util.Reflector;
13+
import org.xutils.x;
1214

1315
import java.lang.reflect.InvocationHandler;
1416
import java.lang.reflect.Method;
@@ -19,6 +21,8 @@
1921

2022
public ActivityManagerHandler(Object base) {
2123
this.mBase = base;
24+
// monitor activities
25+
x.app().registerActivityLifecycleCallbacks(new ActivityLifecycleMonitor());
2226
}
2327

2428
@Override
@@ -29,18 +33,20 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
2933
case "overridePendingTransition":
3034
// overridePendingTransition 是跨进程执行的, 必须试用宿主中的资源.
3135
/*void overridePendingTransition(in IBinder token, in String packageName, int enterAnim, int exitAnim);*/
32-
Activity activity = null;
33-
try {
34-
Reflector activityThreadReflector = Reflector.on("android.app.ActivityThread");
35-
Object activityThreadObj = activityThreadReflector.method("currentActivityThread").call();
36-
activityThreadReflector.bind(activityThreadObj);
37-
activity = activityThreadReflector.method("getActivity", IBinder.class).call(args[0]);
38-
} catch (Throwable ignored) {
39-
}
40-
36+
Activity activity = getActivityByToken(args[0]);
4137
args[2] = ActivityHelper.replaceOverridePendingTransitionAnimId(activity, (int) args[2]);
4238
args[3] = ActivityHelper.replaceOverridePendingTransitionAnimId(activity, (int) args[3]);
4339
return method.invoke(mBase, args);
40+
case "finishActivityAffinity": {
41+
/*boolean finishActivityAffinity(in IBinder token);*/
42+
Activity caller = getActivityByToken(args[0]);
43+
Plugin plugin = Plugin.getPlugin(caller);
44+
ActivityInfo info = plugin.getConfig().findActivityInfoByClassName(caller.getClass().getName());
45+
if (info != null && ActivityLifecycleMonitor.finishActivityAffinity(info.taskAffinity)) {
46+
return true;
47+
}
48+
break;
49+
}
4450
case "startService": {
4551
/*ComponentName startService(in IApplicationThread caller, in Intent service,
4652
in String resolvedType, boolean requireForeground, in String callingPackage, int userId);*/
@@ -109,4 +115,16 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
109115

110116
return method.invoke(mBase, args);
111117
}
118+
119+
private static Activity getActivityByToken(Object arg) {
120+
Activity activity = null;
121+
try {
122+
Reflector activityThreadReflector = Reflector.on("android.app.ActivityThread");
123+
Object activityThreadObj = activityThreadReflector.method("currentActivityThread").call();
124+
activityThreadReflector.bind(activityThreadObj);
125+
activity = activityThreadReflector.method("getActivity", IBinder.class).call(arg);
126+
} catch (Throwable ignored) {
127+
}
128+
return activity;
129+
}
112130
}

0 commit comments

Comments
 (0)