解决换肤框架与高德地图的冲突
直接通过内存地址替换整个 ArtMethod ,完成了高德地图方法的替换。
This commit is contained in:
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@@ -85,7 +85,6 @@
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@@ -1,10 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ASMIdeaPluginConfiguration">
|
||||
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
|
||||
<groovy codeStyle="LEGACY" />
|
||||
</component>
|
||||
<component name="ASMPluginConfiguration">
|
||||
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
|
||||
<groovy codeStyle="LEGACY" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
</project>
|
||||
44
modules/mogo-module-common/CMakeLists.txt
Normal file
44
modules/mogo-module-common/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
|
||||
# Sets the minimum version of CMake required to build the native library.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
|
||||
add_library( # Sets the name of the library.
|
||||
method-hook-lib
|
||||
|
||||
# Sets the library as a shared library.
|
||||
SHARED
|
||||
|
||||
# Provides a relative path to your source file(s).
|
||||
src/main/cpp/method-hook-lib.cpp )
|
||||
|
||||
# Searches for a specified prebuilt library and stores the path as a
|
||||
# variable. Because CMake includes system libraries in the search path by
|
||||
# default, you only need to specify the name of the public NDK library
|
||||
# you want to add. CMake verifies that the library exists before
|
||||
# completing its build.
|
||||
|
||||
find_library( # Sets the name of the path variable.
|
||||
log-lib
|
||||
|
||||
# Specifies the name of the NDK library that
|
||||
# you want CMake to locate.
|
||||
log )
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You
|
||||
# can link multiple libraries, such as libraries you define in this
|
||||
# build script, prebuilt third-party libraries, or system libraries.
|
||||
|
||||
target_link_libraries( # Specifies the target library.
|
||||
method-hook-lib
|
||||
|
||||
# Links the target library to the log library
|
||||
# included in the NDK.
|
||||
${log-lib} )
|
||||
@@ -11,8 +11,18 @@ android {
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles 'consumer-rules.pro'
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11 -frtti -fexceptions"
|
||||
}
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
||||
87
modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp
Normal file
87
modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// Created by donghongyu on 12/10/20 1:34 PM.
|
||||
// 源码地址 https://github.com/pqpo/methodhook
|
||||
// 方法hook jni类
|
||||
static const char *kClassMethodHookChar = "com/mogo/module/common/hook/MethodHook";
|
||||
|
||||
static struct {
|
||||
jmethodID m1;
|
||||
jmethodID m2;
|
||||
size_t methodSize;
|
||||
} methodHookClassInfo;
|
||||
|
||||
|
||||
/**
|
||||
* 替换指定类中的方法
|
||||
* @param env
|
||||
* @param type 要替换方法的目标 class
|
||||
* @param srcMethodObj 目标方法对象
|
||||
* @param destMethodObj 替换的方法对象
|
||||
* @return
|
||||
*/
|
||||
static jlong methodHook(JNIEnv *env, jclass type, jobject srcMethodObj, jobject destMethodObj) {
|
||||
void *srcMethod = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethodObj));
|
||||
void *destMethod = reinterpret_cast<void *>(env->FromReflectedMethod(destMethodObj));
|
||||
int *backupMethod = new int[methodHookClassInfo.methodSize];
|
||||
memcpy(backupMethod, srcMethod, methodHookClassInfo.methodSize);
|
||||
memcpy(srcMethod, destMethod, methodHookClassInfo.methodSize);
|
||||
return reinterpret_cast<long>(backupMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复指定类中的方法
|
||||
* @param env
|
||||
* @param type 要恢复方法的目标 class
|
||||
* @param srcMethod 目标方法对象
|
||||
* @param methodPtr
|
||||
* @return
|
||||
*/
|
||||
static jobject methodRestore(JNIEnv *env, jclass type, jobject srcMethod, jlong methodPtr) {
|
||||
int *backupMethod = reinterpret_cast<int *>(methodPtr);
|
||||
void *artMethodSrc = reinterpret_cast<void *>(env->FromReflectedMethod(srcMethod));
|
||||
memcpy(artMethodSrc, backupMethod, methodHookClassInfo.methodSize);
|
||||
delete[]backupMethod;
|
||||
return srcMethod;
|
||||
}
|
||||
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
{
|
||||
"hook_native",
|
||||
"(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)J",
|
||||
(void *) methodHook
|
||||
},
|
||||
{
|
||||
"restore_native",
|
||||
"(Ljava/lang/reflect/Method;J)Ljava/lang/reflect/Method;",
|
||||
(void *) methodRestore
|
||||
}
|
||||
};
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
/**
|
||||
* 在jni加载的时候进行方法参数获取
|
||||
* @param vm
|
||||
* @param reserved
|
||||
* @return
|
||||
*/
|
||||
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env = nullptr;
|
||||
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jclass classEvaluateUtil = env->FindClass(kClassMethodHookChar);
|
||||
if (env->RegisterNatives(classEvaluateUtil, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) <
|
||||
0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
methodHookClassInfo.m1 = env->GetStaticMethodID(classEvaluateUtil, "m1", "()V");
|
||||
methodHookClassInfo.m2 = env->GetStaticMethodID(classEvaluateUtil, "m2", "()V");
|
||||
methodHookClassInfo.methodSize = reinterpret_cast<size_t>(methodHookClassInfo.m2) -
|
||||
reinterpret_cast<size_t>(methodHookClassInfo.m1);
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mogo.module.common.hook;
|
||||
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 替换管理
|
||||
* Created by donghongyu on 12/29/20 1:34 PM
|
||||
*/
|
||||
public final class HookManager {
|
||||
|
||||
private HookManager() {
|
||||
}
|
||||
|
||||
public static HookManager get() {
|
||||
return InstanceHolder.sInstance;
|
||||
}
|
||||
|
||||
private static class InstanceHolder {
|
||||
private static HookManager sInstance = new HookManager();
|
||||
}
|
||||
|
||||
private Map<Pair<String, String>, MethodHook> methodHookMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 替换方法
|
||||
*
|
||||
* @param originMethod 原始方法
|
||||
* @param hookMethod 替换方法
|
||||
*/
|
||||
public void hookMethod(Method originMethod, Method hookMethod) {
|
||||
if (originMethod == null || hookMethod == null) {
|
||||
throw new IllegalArgumentException("argument cannot be null");
|
||||
}
|
||||
|
||||
Pair<String, String> key = Pair.create(hookMethod.getDeclaringClass().getName(), hookMethod.getName());
|
||||
if (methodHookMap.containsKey(key)) {
|
||||
MethodHook methodHook = methodHookMap.get(key);
|
||||
methodHook.restore();
|
||||
}
|
||||
MethodHook methodHook = new MethodHook(originMethod, hookMethod);
|
||||
methodHookMap.put(key, methodHook);
|
||||
methodHook.hook();
|
||||
}
|
||||
|
||||
public void callOrigin(Object receiver, Object... args) {
|
||||
StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[3];
|
||||
String className = stackTrace.getClassName();
|
||||
String methodName = stackTrace.getMethodName();
|
||||
MethodHook methodHook = methodHookMap.get(Pair.create(className, methodName));
|
||||
if (methodHook != null) {
|
||||
try {
|
||||
methodHook.callOrigin(receiver, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.mogo.module.common.hook;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 替换类与c++代码对应
|
||||
* Created by donghongyu on 12/29/20 1:34 PM
|
||||
*/
|
||||
public class MethodHook {
|
||||
|
||||
public static void m1() {
|
||||
}
|
||||
|
||||
public static void m2() {
|
||||
}
|
||||
|
||||
// 目标方法
|
||||
private Method srcMethod;
|
||||
// 要替换的方法
|
||||
private Method hookMethod;
|
||||
|
||||
// 备份目标替换方法ID
|
||||
private long backupMethodPtr;
|
||||
|
||||
public MethodHook(Method src, Method dest) {
|
||||
srcMethod = src;
|
||||
hookMethod = dest;
|
||||
srcMethod.setAccessible(true);
|
||||
hookMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
if (backupMethodPtr == 0) {
|
||||
backupMethodPtr = hook_native(srcMethod, hookMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public void restore() {
|
||||
if (backupMethodPtr != 0) {
|
||||
restore_native(srcMethod, backupMethodPtr);
|
||||
backupMethodPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void callOrigin(Object receiver, Object... args) throws InvocationTargetException, IllegalAccessException {
|
||||
if (backupMethodPtr != 0) {
|
||||
restore();
|
||||
srcMethod.invoke(receiver, args);
|
||||
hook();
|
||||
} else {
|
||||
srcMethod.invoke(receiver, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static native long hook_native(Method src, Method dest);
|
||||
|
||||
private static native Method restore_native(Method src, long methodPtr);
|
||||
|
||||
static {
|
||||
System.loadLibrary("method-hook-lib");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.module.small.map">
|
||||
|
||||
<application>
|
||||
<!--<application>
|
||||
<service
|
||||
android:name=".SmallMapService"
|
||||
android:exported="false"
|
||||
android:process=":smallMap"/>
|
||||
</application>
|
||||
/>
|
||||
</application>-->
|
||||
</manifest>
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package com.amap.api.col.n3;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.LayoutInflater.Factory;
|
||||
import android.view.View;
|
||||
import android.view.ViewStub;
|
||||
|
||||
import com.android.internal.policy.MyPhoneLayoutInflater;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
public final class le2 extends ContextThemeWrapper {
|
||||
private Resources a = lg.a();
|
||||
private Theme b;
|
||||
private LayoutInflater c;
|
||||
private ClassLoader d;
|
||||
private int e;
|
||||
private static final String[] f = new String[]{"android.widget", "android.webkit", "android.app"};
|
||||
private le2.a g = new le2.a();
|
||||
private Factory h = new Factory() {
|
||||
public final View onCreateView(String var1, Context var2, AttributeSet var3) {
|
||||
return le2.this.a(var1, var2, var3);
|
||||
}
|
||||
};
|
||||
|
||||
public le2(Context var1, int var2, ClassLoader var3) {
|
||||
super(var1, var2);
|
||||
this.d = var3;
|
||||
this.b = lg.b();
|
||||
this.e = var2;
|
||||
super.onApplyThemeResource(this.b, this.e, true);
|
||||
(new StringBuilder("classloader:")).append(this.d);
|
||||
}
|
||||
|
||||
public final Resources getResources() {
|
||||
return this.a != null ? this.a : super.getResources();
|
||||
}
|
||||
|
||||
public final void a(int var1) {
|
||||
if (var1 != this.e) {
|
||||
this.e = var1;
|
||||
super.onApplyThemeResource(this.b, this.e, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final Theme getTheme() {
|
||||
return this.b != null ? this.b : super.getTheme();
|
||||
}
|
||||
|
||||
public final Object getSystemService(String var1) {
|
||||
if ("layout_inflater".equals(var1)) {
|
||||
if (this.c == null) {
|
||||
// 这里构建一个自己对的布局填充器
|
||||
// 与已经被修改的context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
|
||||
// 隔离从而保证高德地图SDK能正常初始化
|
||||
LayoutInflater var2 = new MyPhoneLayoutInflater(getBaseContext());
|
||||
this.c = var2.cloneInContext(this);
|
||||
this.c.setFactory(this.h);
|
||||
this.c = this.c.cloneInContext(this);
|
||||
}
|
||||
|
||||
return this.c;
|
||||
} else {
|
||||
return super.getSystemService(var1);
|
||||
}
|
||||
}
|
||||
|
||||
private final View a(String var1, Context var2, AttributeSet var3) {
|
||||
if (this.g.a.contains(var1)) {
|
||||
return null;
|
||||
} else {
|
||||
Constructor var4;
|
||||
if ((var4 = (Constructor) this.g.b.get(var1)) == null) {
|
||||
Class var5 = null;
|
||||
boolean var6 = false;
|
||||
String var7 = "api.navi";
|
||||
|
||||
label71:
|
||||
{
|
||||
label70:
|
||||
{
|
||||
Throwable var10000;
|
||||
label79:
|
||||
{
|
||||
boolean var10001;
|
||||
try {
|
||||
if (var1.contains(var7)) {
|
||||
var5 = this.d.loadClass(var1);
|
||||
} else {
|
||||
String[] var17;
|
||||
int var8 = (var17 = f).length;
|
||||
int var9 = 0;
|
||||
|
||||
while (var9 < var8) {
|
||||
String var10 = var17[var9];
|
||||
|
||||
try {
|
||||
var5 = this.d.loadClass(var10 + "." + var1);
|
||||
break;
|
||||
} catch (Throwable var13) {
|
||||
++var9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (var5 == null) {
|
||||
break label71;
|
||||
}
|
||||
} catch (Throwable var15) {
|
||||
var10000 = var15;
|
||||
var10001 = false;
|
||||
break label79;
|
||||
}
|
||||
|
||||
if (var5 == ViewStub.class) {
|
||||
break label71;
|
||||
}
|
||||
|
||||
try {
|
||||
if (var5.getClassLoader() != this.d) {
|
||||
break label71;
|
||||
}
|
||||
break label70;
|
||||
} catch (Throwable var14) {
|
||||
var10000 = var14;
|
||||
var10001 = false;
|
||||
}
|
||||
}
|
||||
|
||||
Throwable var18 = var10000;
|
||||
(new StringBuilder("load view err:")).append(Log.getStackTraceString(var18));
|
||||
break label71;
|
||||
}
|
||||
|
||||
var6 = true;
|
||||
}
|
||||
|
||||
if (!var6) {
|
||||
this.g.a.add(var1);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
var4 = var5.getConstructor(Context.class, AttributeSet.class);
|
||||
this.g.b.put(var1, var4);
|
||||
} catch (Throwable var12) {
|
||||
(new StringBuilder("create view err:")).append(Log.getStackTraceString(var12));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
View var16 = null;
|
||||
if (var4 != null) {
|
||||
var16 = (View) var4.newInstance(var2, var3);
|
||||
}
|
||||
|
||||
return var16;
|
||||
} catch (Throwable var11) {
|
||||
(new StringBuilder("create view err:")).append(Log.getStackTraceString(var11));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class a {
|
||||
public HashSet<String> a = new HashSet();
|
||||
public HashMap<String, Constructor<?>> b = new HashMap();
|
||||
|
||||
public a() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.amap.api.col.n3;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* 这里是为了解决 使用换肤框架后,高德地图初始化有问题加入的
|
||||
* 问题原因是:
|
||||
* skin 框架会替换 LayoutInflater 中的 setFactory2 从而导致高德 le 中的 setFactory 失效。
|
||||
* 解决方案为:
|
||||
* 直接通过内存地址替换整个 ArtMethod,来将需要修改的高德SDK中的方法指向我们修改过后的方法。
|
||||
*/
|
||||
public class lg2 extends lg {
|
||||
static le2 b;
|
||||
|
||||
public static View a(Context var0, int var1, ViewGroup var2) {
|
||||
XmlResourceParser var9 = a().getXml(var1);
|
||||
if (!a) {
|
||||
return LayoutInflater.from(var0).inflate(var9, var2);
|
||||
} else {
|
||||
try {
|
||||
if (b == null) {
|
||||
b = new le2(var0, c == -1 ? 0 : c, lg.class.getClassLoader());
|
||||
}
|
||||
b.a(c == -1 ? 0 : c);
|
||||
View var3 = LayoutInflater.from(b).inflate(var9, var2);
|
||||
return var3;
|
||||
} catch (Throwable var7) {
|
||||
var7.printStackTrace();
|
||||
np.c(var7, "ResourcesUtil", "selfInflate(Activity activity, int resource, ViewGroup root)");
|
||||
} finally {
|
||||
var9.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.android.internal.policy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* @author donghongyu
|
||||
* @date 12/25/20 5:12 PM
|
||||
*/
|
||||
public class MyPhoneLayoutInflater extends LayoutInflater {
|
||||
private static final String[] sClassPrefixList = {
|
||||
"android.widget.",
|
||||
"android.webkit.",
|
||||
"android.app."
|
||||
};
|
||||
|
||||
/**
|
||||
* Instead of instantiating directly, you should retrieve an instance
|
||||
* through {@link Context#getSystemService}
|
||||
*
|
||||
* @param context The Context in which in which to find resources and other
|
||||
* application-specific things.
|
||||
* @see Context#getSystemService
|
||||
*/
|
||||
public MyPhoneLayoutInflater(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
protected MyPhoneLayoutInflater(LayoutInflater original, Context newContext) {
|
||||
super(original, newContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override onCreateView to instantiate names that correspond to the
|
||||
* widgets known to the Widget factory. If we don't find a match,
|
||||
* call through to our super class.
|
||||
*/
|
||||
@Override
|
||||
protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
|
||||
for (String prefix : sClassPrefixList) {
|
||||
try {
|
||||
View view = createView(name, prefix, attrs);
|
||||
if (view != null) {
|
||||
return view;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// In this case we want to let the base class take a crack
|
||||
// at it.
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateView(name, attrs);
|
||||
}
|
||||
|
||||
public LayoutInflater cloneInContext(Context newContext) {
|
||||
return new MyPhoneLayoutInflater(this, newContext);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,30 @@
|
||||
package com.mogo.module.small.map;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.amap.api.col.n3.lg;
|
||||
import com.amap.api.col.n3.lg2;
|
||||
import com.mogo.module.common.MogoApisHandler;
|
||||
import com.mogo.module.common.hook.HookManager;
|
||||
import com.mogo.module.common.wm.WindowManagerView;
|
||||
import com.mogo.service.MogoServicePaths;
|
||||
import com.mogo.service.map.IMogoSmallMapProvider;
|
||||
import com.mogo.service.module.ModuleType;
|
||||
import com.mogo.service.statusmanager.IMogoStatusChangedListener;
|
||||
import com.mogo.service.statusmanager.StatusDescriptor;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author donghongyu
|
||||
@@ -26,9 +34,11 @@ import com.mogo.service.statusmanager.StatusDescriptor;
|
||||
public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusChangedListener {
|
||||
private final String TAG = "SmallVisionProvider";
|
||||
|
||||
private Intent mSmallMapServiceIntent;
|
||||
private Context mContext;
|
||||
|
||||
private WindowManagerView mWindowManagerView;
|
||||
private SmallMapDirectionView mSmallMapDirectionView;
|
||||
|
||||
@Override
|
||||
public Fragment createFragment(Context context, Bundle data) {
|
||||
return null;
|
||||
@@ -55,6 +65,19 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh
|
||||
Log.d(TAG, "小地图模块初始化……");
|
||||
mContext = context;
|
||||
|
||||
try {
|
||||
try {
|
||||
// 替换高德地图的方法,解决因为加入换肤框架导致地图初始化失败
|
||||
Method srcMethod = lg.class.getDeclaredMethod("a", Context.class, int.class, ViewGroup.class);
|
||||
Method destMethod = lg2.class.getDeclaredMethod("a", Context.class, int.class, ViewGroup.class);
|
||||
HookManager.get().hookMethod(srcMethod, destMethod);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
MogoApisHandler.getInstance()
|
||||
.getApis()
|
||||
.getStatusManagerApi()
|
||||
@@ -76,22 +99,22 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh
|
||||
public void onDestroy() {
|
||||
Log.d(TAG, "小地图模块销毁……");
|
||||
hidePanel();
|
||||
// 释放组件内存
|
||||
mSmallMapDirectionView = null;
|
||||
mWindowManagerView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPanel() {
|
||||
Log.d(TAG, "小地图模块触发展示……");
|
||||
if (MogoApisHandler.getInstance().getApis().getStatusManagerApi().isVrMode()) {
|
||||
mSmallMapServiceIntent = new Intent(mContext, SmallMapService.class);
|
||||
mContext.startService(mSmallMapServiceIntent);
|
||||
}
|
||||
addSmallMapView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePanel() {
|
||||
Log.d(TAG, "小地图模块触发隐藏……");
|
||||
if (mSmallMapServiceIntent != null) {
|
||||
AbsMogoApplication.getApp().stopService(mSmallMapServiceIntent);
|
||||
if (mWindowManagerView != null && mWindowManagerView.isShowing()) {
|
||||
mWindowManagerView.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,4 +145,33 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加小地图View
|
||||
*/
|
||||
private void addSmallMapView() {
|
||||
Logger.d(TAG, "addSmallMapView");
|
||||
// 初始化小地图控件
|
||||
if (mSmallMapDirectionView == null) {
|
||||
mSmallMapDirectionView = new SmallMapDirectionView(mContext);
|
||||
}
|
||||
|
||||
if (mWindowManagerView == null) {
|
||||
mWindowManagerView = new WindowManagerView.Builder(mContext)
|
||||
.contentView(mSmallMapDirectionView)
|
||||
.size(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
.position(
|
||||
mContext.getResources().getDimensionPixelOffset(R.dimen.module_small_map_view_x),
|
||||
mContext.getResources().getDimensionPixelOffset(R.dimen.module_small_map_view_y)
|
||||
)
|
||||
.gravity(Gravity.TOP | Gravity.LEFT)
|
||||
.showInWindowManager();
|
||||
}
|
||||
mWindowManagerView.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user