使用非 SDK 接口。脱糖

Usage of Non-SDK interfaces. Desugaring

提问人:jlsogorb 提问时间:5/17/2023 最后编辑:jlsogorb 更新时间:5/19/2023 访问量:104

问:

在将应用发送到 Play 商店之前,我正在 Firebase 中检查我的应用,但收到以下警告:

Usage of non-SDK interfaces
Ljava/util/Collections$SynchronizedCollection;-><init>(Ljava/util/Collection;Ljava/lang/Object;)V
Ljava/util/Collections$SynchronizedCollection;->mutex:Ljava/lang/Object;
Ljava/util/Collections$SynchronizedCollection;->c:Ljava/util/Collection;
Ljava/util/Collections$SynchronizedSet;-><init>(Ljava/util/Set;Ljava/lang/Object;)V

它们在hiddenapi_flags中标记为“greylist-max-o”。 我已经隔离了问题,并注意到问题出在使用 Desugaring 库时(我包含它以使用 Api<26 中的一些时间功能,如 ZonedDateTime、ZoneOffset 等)。 我的问题是:有了这些警告,我可以将应用程序更新到 Google Play 吗?在较旧的 API 中,是否有任何替代方法可以使用与 ZonedDateTime.getAvailableZoneIds 等类似的函数? 谢谢。

Android Firebase Google-Play JDK-脱糖

评论


答:

0赞 jlsogorb 5/19/2023 #1

我把问题发给了 Issuetracker.google.com,他们正在调查这个问题。这是他们的答案:

评论 所有评论 [email protected][email protected] 2023年 #2May 17日 上午11:02

这是由 DesugarCollections.java 中的代码引起的。代码是 尝试获取基础 SynchronizedCollection 的锁 通过对内部字段和方法的反映 平台。

如果此反射不成功,则方法 removeIf, forEach、replaceAll 和 sort 将访问内部集合字段 径直。

根据 hiddenapi-flags.csv互斥锁字段不可访问 在 Android 8 之后。

这不是最佳选择,可能会导致未定义的行为。我建议 避免使用 SynchronizedCollection,而是使用 concurrent 数据结构(如果可能的话)。

[电子邮件保护][电子邮件保护] #3May 17, 2023 11:04上午

在模拟器上测试了以下代码,在 Android 上成功了 O_MR1 并在 Android P 上失败。 ALso 在 Android U 手机上进行了测试,其中 它也失败了。

public class SynchronizedCollectionReflection {
    public static String test() {
        Class<? extends Collection> SYNCHRONIZED_COLLECTION;
        SYNCHRONIZED_COLLECTION = Collections.synchronizedCollection(new ArrayList<>()).getClass();
        Class<? extends List> SYNCHRONIZED_LIST;
        SYNCHRONIZED_LIST = Collections.synchronizedList(new LinkedList<>()).getClass();
        Field MUTEX_FIELD;
        MUTEX_FIELD = getField(SYNCHRONIZED_COLLECTION, "mutex");
        if (MUTEX_FIELD != null) {
            MUTEX_FIELD.setAccessible(true);
        } else {
            return "Failed MUTEX_FIELD";
        }
        Field COLLECTION_FIELD;
        COLLECTION_FIELD = getField(SYNCHRONIZED_COLLECTION, "c");
        if (COLLECTION_FIELD != null) {
            COLLECTION_FIELD.setAccessible(true);
        } else {
            return "Failed COLLECTION_FIELD";
        }
        Class<? extends Set> synchronizedSet = Collections.synchronizedSet(new HashSet<>()).getClass();
        Constructor<? extends Set> SYNCHRONIZED_SET_CONSTRUCTOR;
        SYNCHRONIZED_SET_CONSTRUCTOR = getConstructor(synchronizedSet, Set.class, Object.class);
        if (SYNCHRONIZED_SET_CONSTRUCTOR != null) {
            SYNCHRONIZED_SET_CONSTRUCTOR.setAccessible(true);
        } else {
            return "Failed SYNCHRONIZED_SET_CONSTRUCTOR";
        }
        Constructor<? extends Collection> SYNCHRONIZED_COLLECTION_CONSTRUCTOR;
        SYNCHRONIZED_COLLECTION_CONSTRUCTOR =
                getConstructor(SYNCHRONIZED_COLLECTION, Collection.class, Object.class);
        if (SYNCHRONIZED_COLLECTION_CONSTRUCTOR != null) {
            SYNCHRONIZED_COLLECTION_CONSTRUCTOR.setAccessible(true);
        } else {
            return "Failed SYNCHRONIZED_COLLECTION_CONSTRUCTOR";
        }
        return "SUCCESS!";
    }

    private static Field getField(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException e) {
            // For Desugar: Some fields are not available on instrumented devices.
            return null;
        }
    }

    private static <E> Constructor<? extends E> getConstructor(
            Class<? extends E> clazz, Class<?>... parameterTypes) {
        try {
            return clazz.getDeclaredConstructor(parameterTypes);
        } catch (NoSuchMethodException e) {
            // For Desugar: Some constructors are not available on instrumented devices.
            return null;
        }
    }
}

[电子邮件保护][电子邮件保护] #4May 17, 2023 11:05 重新分配给 [email protected]。

我们应该再看一看这一点,并考虑失败 无法安全脱糖的操作。