java.lang.IncompatibleClassChangeError:该方法应为直接类型,但被发现为虚拟螺母类型

时间:2019-05-22 09:44:11

标签: android proguard android-proguard

我将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()并导致崩溃

0 个答案:

没有答案