Search code examples
javaandroidproguardscale

NoSuchFieldException in Android ProGuard


I try to use reflection to get field mMinSapn in android.view.ScaleGestureDetector

    ScaleGestureDetector  sgd = new ScaleGestureDetector(view.getContext(), sl);
    try {
        Field field = sgd.getClass().getDeclaredField("mMinSpan");
        field.setAccessible(true);
        field.set(sgd,1);
    } catch (Exception e) {
        e.printStackTrace();
    }

but it always has NoSuchFieldException, I find that it may be caused by ProGuard. So I edit my proguard-rules.pro,add some code:

-keepclassmembers class android.view.ScaleGestureDetector {
private  <fields>;
}

or

-keepclassmembers class android.view.ScaleGestureDetector {
 private *;
}

it still has NoSuchFieldException.Something here is not right? Thank you!


Solution

  • As seen in the ScaleGestureDetector source code:

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938)
    private int mMinSpan;
    

    The UnsupportedAppUsage means that if you have a targetSdkVersion greater than 28 (the Build.VERSION_CODES.P, you cannot access mMinSpan at all, even via reflection as explained by the Restrictions on non-SDK interfaces. As that page mentions, a NoSuchFieldException is expected when trying to access these non-SDK fields.

    Of course, looking again at the source code:

    mMinSpan = viewConfiguration.getScaledMinimumScalingSpan();
    

    And getScaledMinimumScalingSpan() is part of the public API in API 29 (exactly when you cannot access the field via reflection). Therefore you can run your reflection based code on API 28 or lower and use the public API on API 29 and higher:

    ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
    in minSpan = viewConfiguration.getScaledMinimumScalingSpan();