我将Android Gradle插件升级到3.2.1,并将构建工具升级到28.0.3。
在通过应用使用Android对讲功能时开始出现运行时崩溃。
错误为“ java.lang.IncompatibleClassChangeError:方法'void android.support.v4.widget.ExploreByTouchHelper.updateHoveredVirtualView(int)'应该是直接类型,但是却发现是虚拟类型” >
我使用dexdump检查了dex
22 : (in Landroid/support/v4/widget/ExploreByTouchHelper;)
name : 'updateHoveredVirtualView'
type : '(I)V'
**access : 0x0001 (PUBLIC) code** -
registers : 4
ins : 2
outs : 3 insns
size : 20 16-bit code units
catches : (none)
positions : 0x0000
line=612 0x0004
line=613 0x0005
line=616 0x0007
line=617 0x0009
line=621 0x000e
line=622 0x0013
line=624
locals : 0x0000 - 0x0014 reg=2 this
Landroid/support/v4/widget/y;
source_file_idx : 14328 (SourceFile)
这里方法void updateHoveredVirtualView(int)的访问类型是公共的,但是我检查了ExploreTouchByHelper.java文件中的定义,它是私有的
我正在使用以下Proguard设置:
-repackageclasses ''
-allowaccessmodification
如果我删除了上述规则,则方法的访问类型将变为私有并已解决问题。但是我不想删除allowaccessmodication,因为它会导致性能问题。
此外,我发现的另一个选择是从proguard中删除以下规则
#Preserve all View implementations, their special context constructors, and their setters.
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
# Preserve all classes that have special context constructors, and the
# constructors themselves.
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
\# Preserve all classes that have special context constructors, and the
# constructors themselves.
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
删除上述规则也可以解决崩溃问题,但是我不确定删除的副作用。有人可以解释为什么删除以上保留规则会阻止allowaccessmodification(Proguard)将方法访问类型从私有更改为公开吗?
ExploreTouchByHelper.java的快照
package android.support.v4.widget;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.SparseArrayCompat;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewParentCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import java.util.ArrayList;
import java.util.List;
public abstract class ExploreByTouchHelper
extends AccessibilityDelegateCompat
{
public static final int INVALID_ID = Integer.MIN_VALUE;
public static final int HOST_ID = -1;
private static final String DEFAULT_CLASS_NAME = "android.view.View";
private static final Rect INVALID_PARENT_BOUNDS = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
private final Rect mTempScreenRect = new Rect();
private final Rect mTempParentRect = new Rect();
private final Rect mTempVisibleRect = new Rect();
private final int[] mTempGlobalRect = new int[2];
private final AccessibilityManager mManager;
private final View mHost;
private MyNodeProvider mNodeProvider;
int mAccessibilityFocusedVirtualViewId = Integer.MIN_VALUE;
int mKeyboardFocusedVirtualViewId = Integer.MIN_VALUE;
private int mHoveredVirtualViewId = Integer.MIN_VALUE;
......
public ExploreByTouchHelper(@NonNull View host)
{
if (host == null) {
throw new IllegalArgumentException("View may not be null");
}
mHost = host;
Context context = host.getContext();
mManager = ((AccessibilityManager)context.getSystemService("accessibility"));
host.setFocusable(true);
if (ViewCompat.getImportantForAccessibility(host) == 0)
{
ViewCompat.setImportantForAccessibility(host, 1);
}
}
public final boolean dispatchHoverEvent(@NonNull MotionEvent event)
{
if ((!mManager.isEnabled()) || (!mManager.isTouchExplorationEnabled())) {
return false;
}
switch (event.getAction()) {
case 7:
case 9:
int virtualViewId = getVirtualViewAt(event.getX(), event.getY());
updateHoveredVirtualView(virtualViewId);
return virtualViewId != Integer.MIN_VALUE;
case 10:
if (mHoveredVirtualViewId != Integer.MIN_VALUE) {
updateHoveredVirtualView(Integer.MIN_VALUE);
return true;
}
return false;
}
return false;
}
private void updateHoveredVirtualView(int virtualViewId)
{
if (mHoveredVirtualViewId == virtualViewId) {
return;
}
int previousVirtualViewId = mHoveredVirtualViewId;
mHoveredVirtualViewId = virtualViewId;
sendEventForVirtualView(virtualViewId, 128);
sendEventForVirtualView(previousVirtualViewId, 256);
}
.....
}
我正在从应用程序代码中调用ExploreTouchByHelper :: dispatchHoverEvent()API,后者依次调用updateHoveredVirtualView()并导致崩溃