public abstract class

StartupApiFeature

extends java.lang.Object

 java.lang.Object

↳androidx.webkit.internal.StartupApiFeature

Subclasses:

StartupApiFeature.P, StartupApiFeature.NoFramework

Gradle dependencies

compile group: 'androidx.webkit', name: 'webkit', version: '1.12.0-rc01'

  • groupId: androidx.webkit
  • artifactId: webkit
  • version: 1.12.0-rc01

Artifact androidx.webkit:webkit:1.12.0-rc01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.webkit:webkit com.android.support:webkit

Overview

Enum-like class to represent startup features that are supported by the AndroidX webview API. Features that have framework support should be represented by the appropriate subclass matching the SDK version where the feature became available, which allows static analysis to verify that calling the feature is safe through the StartupApiFeature.isSupportedByFramework() method. To gain this benefit, variables containing StartupApiFeature should always be declared as the specific subtype. To add support for a new API version, add a new subclass representing the desired API level. This class should only be instantiated as constants in WebViewFeatureInternal and is meant to act as enum values for that class. Startup API feature checks if a feature is supported in WebView by looking for metadata entries in the WebView manifest. Calling this method does not lead to WebView being loaded into the calling process.

Summary

Fields
public static final java.lang.StringMETADATA_HOLDER_SERVICE_NAME

Methods
public java.lang.StringgetPublicFeatureName()

public booleanisSupported(Context context)

Return whether this feature is supported.

public abstract booleanisSupportedByFramework()

Return whether this StartupApiFeature is supported by the framework of the current device.

public booleanisSupportedByWebView(Context context)

Return whether this StartupApiFeature is supported by the current WebView APK.

public static java.util.Set<StartupApiFeature>values()

Get all instantiated values of this class as if it was an enum.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final java.lang.String METADATA_HOLDER_SERVICE_NAME

Methods

public java.lang.String getPublicFeatureName()

public boolean isSupported(Context context)

Return whether this feature is supported.

public abstract boolean isSupportedByFramework()

Return whether this StartupApiFeature is supported by the framework of the current device.

Make sure the static type of the object you are calling this method on corresponds to one of the subtypes of StartupApiFeature to ensure static analysis of the correct framework level.

public boolean isSupportedByWebView(Context context)

Return whether this StartupApiFeature is supported by the current WebView APK.

WebView updates were only supported starting in Android L and the preinstalled WebView in earlier OS versions is not compatible with this library. If this returns true, then that implies we're on Android L or above.

It checks if a feature is supported in WebView by looking for metadata entries in the WebView manifest. Calling this method does not lead to WebView being loaded into the calling process.

public static java.util.Set<StartupApiFeature> values()

Get all instantiated values of this class as if it was an enum.

Source

/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.webkit.internal;

import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.webkit.WebViewCompat;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * Enum-like class to represent startup features that are supported by the AndroidX webview API.
 *
 * Features that have framework support should be represented by the appropriate subclass
 * matching the SDK version where the feature became available, which allows static analysis to
 * verify that calling the feature is safe through the {@link #isSupportedByFramework()} method.
 *
 * To gain this benefit, variables containing {@link StartupApiFeature} should always be declared as
 * the specific subtype.
 *
 * To add support for a new API version, add a new subclass representing the desired API level.
 *
 * This class should only be instantiated as constants in {@link WebViewFeatureInternal} and is
 * meant to act as enum values for that class.
 *
 * Startup API feature checks if a feature is supported in WebView by looking for metadata entries
 * in the WebView manifest. Calling this method does not lead to WebView being loaded into the
 * calling process.
 */
public abstract class StartupApiFeature {
    // Collection of declared values, populated by the constructor, to allow enum-like
    // iteration over all declared values.

    private static final Set<StartupApiFeature> sValues = new HashSet<>();
    // Do not change value, it is used by external AndroidManifest.xml files
    @VisibleForTesting
    public static final String METADATA_HOLDER_SERVICE_NAME = "org.chromium.android_webview"
            + ".services.StartupFeatureMetadataHolder";

    private final String mPublicFeatureValue;
    private final String mInternalFeatureValue;

    StartupApiFeature(@NonNull String publicFeatureValue, @NonNull String internalFeatureValue) {
        mPublicFeatureValue = publicFeatureValue;
        mInternalFeatureValue = internalFeatureValue;
        sValues.add(this);
    }

    @NonNull
    public String getPublicFeatureName() {
        return mPublicFeatureValue;
    }

    /**
     * Return whether this feature is supported.
     */
    public boolean isSupported(@NonNull Context context) {
        return isSupportedByFramework() || isSupportedByWebView(context);
    }


    /**
     * Return whether this {@link StartupApiFeature} is supported by the framework of the
     * current device.
     *
     * <p>Make sure the static type of the object you are calling this method on corresponds to one
     * of the subtypes of {@link StartupApiFeature} to ensure static analysis of the correct
     * framework level.
     */
    public abstract boolean isSupportedByFramework();

    /**
     * Return whether this {@link StartupApiFeature} is supported by the current WebView APK.
     *
     * <p>WebView updates were only supported starting in Android L and the preinstalled WebView in
     * earlier OS versions is not compatible with this library. If this returns true, then that
     * implies we're on Android L or above.
     *
     * <p>It checks if a feature is supported in WebView by looking for metadata entries
     * in the WebView manifest. Calling this method does not lead to WebView being loaded into the
     * calling process.
     */
    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.LOLLIPOP)
    public boolean isSupportedByWebView(@NonNull Context context) {
        Bundle bundle = getMetaDataFromWebViewManifestOrNull(context);
        if (bundle == null) {
            return false;
        }
        return bundle.containsKey(mInternalFeatureValue);
    }

    /**
     * Get all instantiated values of this class as if it was an enum.
     */
    @NonNull
    public static Set<StartupApiFeature> values() {
        return Collections.unmodifiableSet(sValues);
    }

    private static @Nullable Bundle getMetaDataFromWebViewManifestOrNull(@NonNull Context context) {
        PackageInfo systemWebViewPackage = WebViewCompat.getCurrentWebViewPackage(context);
        if (systemWebViewPackage == null) {
            return null;
        }
        ComponentName compName =
                new ComponentName(systemWebViewPackage.packageName, METADATA_HOLDER_SERVICE_NAME);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            PackageManager.ComponentInfoFlags flags =
                    ApiHelperForTiramisu.of(PackageManager.MATCH_DISABLED_COMPONENTS
                            | PackageManager.GET_META_DATA);
            try {
                return ApiHelperForTiramisu.getServiceInfo(context.getPackageManager(), compName,
                        flags)
                        .metaData;
            } catch (PackageManager.NameNotFoundException e) {
                return null;
            }
        } else {
            int flags = PackageManager.GET_META_DATA;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                flags |= PackageManager.MATCH_DISABLED_COMPONENTS;
            }
            try {

                return getServiceInfo(context, compName, flags)
                        .metaData;
            } catch (PackageManager.NameNotFoundException e) {
                return null;
            }
        }
    }

    // To suppress deprecation warnings even when it is never called in API versions where it is
    // not deprecated.
    @SuppressWarnings("deprecation")
    private static ServiceInfo getServiceInfo(@NonNull Context context, ComponentName compName,
            int flags) throws PackageManager.NameNotFoundException {
        assert Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU;
        return context.getPackageManager()
                .getServiceInfo(compName, flags);
    }

    // --- Implement API version specific subclasses below this line ---

    /**
     * Represents a feature that was added in P.
     */
    public static class P extends StartupApiFeature {
        P(@NonNull String publicFeatureValue, @NonNull String internalFeatureValue) {
            super(publicFeatureValue, internalFeatureValue);
        }

        @Override
        public final boolean isSupportedByFramework() {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
        }
    }

    /**
     * Represents a feature that is not supported by framework.
     */
    public static class NoFramework extends StartupApiFeature {
        NoFramework(@NonNull String publicFeatureValue, @NonNull String internalFeatureValue) {
            super(publicFeatureValue, internalFeatureValue);
        }

        @Override
        public final boolean isSupportedByFramework() {
            return false;
        }
    }
}