Я сделал обновление для плагина Android Gradle до 3.2.1 и собрал инструменты до 28.0.3.
Начал получать сбой во время выполнения при использовании функции обратной связи Android с приложением.
Ошибка: «java.lang.IncompatibleClassChangeError: метод 'void android.support.v4.widget.ExploreByTouchHelper.updateHoveredVirtualView (int)' ожидался как прямой тип, но вместо этого был обнаружен виртуальный тип"
Я проверил декс с помощью dexdump
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);
}
.....
}
Я вызываю API ExploreTouchByHelper :: dispatchHoverEvent () из кода приложения, который в свою очередь вызывает updateHoveredVirtualView () и вызывает сбой