后续测试, Chrome已经无法使用此方法, 也找不到当初对应测试的版本
Google Chrome app is no longer the WebView provider in Android 10
后续采用Google WebView, 改法参照下文
<webviewproviders>
<webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true">
webviewprovider>
<webviewprovider description="Google WebView" packageName="com.google.android.webview" availableByDefault="false">
webviewprovider>
webviewproviders>
RK3288 + Android 7.1
选项位置: 设置 > 开发者选项 > WebView实现
1.在Pixel上, 可以显示两个选项: Android System WebView 和 Chrome
尝试把Chorme 禁用后, 选项中, 仅剩下Android System WebView.
2.尝试在RK3288主板上安装Chrome, 并增加相应配置
<webviewprovider description="Chrome WebView X" packageName="com.android.chrome" availableByDefault="true">
webviewprovider>
编译烧录后, 可以看到, 新增了Chrome WebView X, 测试选择不同的实现方法, 均可正常使用.
为确认装入Chrome后可以生效, 已删除源码自带/system/app/webview
|-- packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
mBackupManager = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
//获取 IWebViewUpdateService
mWebViewUpdateService =
IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
...
}
private void updateWebViewProviderOptions() {
try {
// 从IWebViewUpdateService中获取可用的WebView 包名, 并填充列表.
WebViewProviderInfo[] providers = mWebViewUpdateService.getValidWebViewPackages();
if (providers == null) {
Log.e(TAG, "No WebView providers available");
return;
}
ArrayList<String> options = new ArrayList<String>();
ArrayList<String> values = new ArrayList<String>();
for(int n = 0; n < providers.length; n++) {
if (Utils.isPackageEnabled(getActivity(), providers[n].packageName)) {
options.add(providers[n].description);
values.add(providers[n].packageName);
}
}
mWebViewProvider.setEntries(options.toArray(new String[options.size()]));
mWebViewProvider.setEntryValues(values.toArray(new String[values.size()]));
String value = mWebViewUpdateService.getCurrentWebViewPackageName();
if (value == null) {
value = "";
}
for (int i = 0; i < values.size(); i++) {
if (value.contentEquals(values.get(i))) {
mWebViewProvider.setValueIndex(i);
return;
}
}
} catch(RemoteException e) {
}
}
|-- frameworks/base/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
mContext = context;
mSystemInterface = systemInterface;
mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface);
}
WebViewProviderInfo[] getValidWebViewPackages() {
return mWebViewUpdater.getValidAndInstalledWebViewPackages();
}
private static class WebViewUpdater {
private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) {
WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
List<ProviderAndPackageInfo> providers = new ArrayList<>();
for(int n = 0; n < allProviders.length; n++) {
try {
PackageInfo packageInfo =
mSystemInterface.getPackageInfoForProvider(allProviders[n]);
if ((!onlyInstalled || isInstalledPackage(packageInfo))
&& isValidProvider(allProviders[n], packageInfo)) {
providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
}
} catch (NameNotFoundException e) {
// Don't add non-existent packages
}
}
return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
}
}
|-- frameworks/base/services/core/java/com/android/server/webkit/WebViewUpdateService.java
public WebViewUpdateService(Context context) {
super(context);
mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance());
}
|-- frameworks/base/services/core/java/com/android/server/webkit/SystemInterface.java
public class SystemImpl implements SystemInterface {
...
private final WebViewProviderInfo[] mWebViewProviderPackages;
// Initialization-on-demand holder idiom for getting the WebView provider packages once and
// for all in a thread-safe manner.
private static class LazyHolder {
private static final SystemImpl INSTANCE = new SystemImpl();
}
public static SystemImpl getInstance() {
return LazyHolder.INSTANCE;
}
private SystemImpl() {
int numFallbackPackages = 0;
int numAvailableByDefaultPackages = 0;
int numAvByDefaultAndNotFallback = 0;
XmlResourceParser parser = null;
List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
try {
//读取系统配置文件config_webview_packages.xml中的值:
parser = AppGlobals.getInitialApplication().getResources().getXml(
com.android.internal.R.xml.config_webview_packages);
XmlUtils.beginDocument(parser, TAG_START);
while(true) {
XmlUtils.nextElement(parser);
String element = parser.getName();
if (element == null) {
break;
}
if (element.equals(TAG_WEBVIEW_PROVIDER)) {
String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
if (packageName == null) {
throw new AndroidRuntimeException(
"WebView provider in framework resources missing package name");
}
String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
if (description == null) {
throw new AndroidRuntimeException(
"WebView provider in framework resources missing description");
}
boolean availableByDefault = "true".equals(
parser.getAttributeValue(null, TAG_AVAILABILITY));
boolean isFallback = "true".equals(
parser.getAttributeValue(null, TAG_FALLBACK));
WebViewProviderInfo currentProvider = new WebViewProviderInfo(
packageName, description, availableByDefault, isFallback,
readSignatures(parser));
if (currentProvider.isFallback) {
numFallbackPackages++;
if (!currentProvider.availableByDefault) {
throw new AndroidRuntimeException(
"Each WebView fallback package must be available by default.");
}
if (numFallbackPackages > 1) {
throw new AndroidRuntimeException(
"There can be at most one WebView fallback package.");
}
}
if (currentProvider.availableByDefault) {
numAvailableByDefaultPackages++;
if (!currentProvider.isFallback) {
numAvByDefaultAndNotFallback++;
}
}
webViewProviders.add(currentProvider);
}
else {
Log.e(TAG, "Found an element that is not a WebView provider");
}
}
} catch (XmlPullParserException | IOException e) {
throw new AndroidRuntimeException("Error when parsing WebView config " + e);
} finally {
if (parser != null) parser.close();
}
if (numAvailableByDefaultPackages == 0) {
throw new AndroidRuntimeException("There must be at least one WebView package "
+ "that is available by default");
}
if (numAvByDefaultAndNotFallback == 0) {
throw new AndroidRuntimeException("There must be at least one WebView package "
+ "that is available by default and not a fallback");
}
mWebViewProviderPackages =
webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
}
|-- frameworks/base/core/res/res/xml/config_webview_packages.xml
<webviewproviders>
<webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true">
webviewprovider>
webviewproviders>
|-- frameworks/base/core/java/android/webkit/WebView.java
private WebViewProvider mProvider;
protected WebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
super(context, attrs, defStyleAttr, defStyleRes);
if (context == null) {
throw new IllegalArgumentException("Invalid context argument");
}
sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.JELLY_BEAN_MR2;
checkThread();
ensureProviderCreated();
mProvider.init(javaScriptInterfaces, privateBrowsing);
// Post condition of creating a webview is the CookieSyncManager.getInstance() is allowed.
CookieSyncManager.setGetInstanceIsAllowed();
}
private void ensureProviderCreated() {
checkThread();
if (mProvider == null) {
// As this can get called during the base class constructor chain, pass the minimum
// number of dependencies here; the rest are deferred to init().
mProvider = getFactory().createWebView(this, new PrivateAccess());
}
}
private static synchronized WebViewFactoryProvider getFactory() {
return WebViewFactory.getProvider();
}
//加载网址
public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
checkThread();
mProvider.loadUrl(url, additionalHttpHeaders);
}
|-- frameworks/base/core/java/android/webkit/WebViewFactory.java
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
...
try {
Class<WebViewFactoryProvider> providerClass = getProviderClass();
try {
sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
.newInstance(new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
...
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
StrictMode.setThreadPolicy(oldPolicy);
}
}
}
private static Class<WebViewFactoryProvider> getProviderClass() {
Context webViewContext = null;
Application initialApplication = AppGlobals.getInitialApplication();
try {
try {
webViewContext = getWebViewContextAndSetProvider();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
initialApplication.getAssets().addAssetPathAsSharedLibrary(
webViewContext.getApplicationInfo().sourceDir);
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
loadNativeLibrary(clazzLoader);
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
try {
return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
true, clazzLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading provider", e);
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (MissingWebViewPackageException e) {
// If the package doesn't exist, then try loading the null WebView instead.
// If that succeeds, then this is a device without WebView support; if it fails then
// swallow the failure, complain that the real WebView is missing and rethrow the
// original exception.
try {
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
} catch (ClassNotFoundException e2) {
// Ignore.
}
Log.e(LOGTAG, "Chromium WebView package does not exist", e);
throw new AndroidRuntimeException(e);
}
}
private static Context getWebViewContextAndSetProvider() {
Application initialApplication = AppGlobals.getInitialApplication();
try {
WebViewProviderResponse response = null;
try {
//IWebViewUpdateService
response = getUpdateService().waitForAndGetProvider();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
...
try {
ActivityManagerNative.getDefault().addPackageDependency(
response.packageInfo.packageName);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
// Fetch package info and verify it against the chosen package
PackageInfo newPackageInfo = null;
try {
newPackageInfo = initialApplication.getPackageManager().getPackageInfo(
response.packageInfo.packageName,
PackageManager.GET_SHARED_LIBRARY_FILES
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING
// Make sure that we fetch the current provider even if its not
// installed for the current user
| PackageManager.MATCH_UNINSTALLED_PACKAGES
// Fetch signatures for verification
| PackageManager.GET_SIGNATURES
// Get meta-data for meta data flag verification
| PackageManager.GET_META_DATA);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
// Validate the newly fetched package info, throws MissingWebViewPackageException on
// failure
verifyPackageInfo(response.packageInfo, newPackageInfo);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
"initialApplication.createApplicationContext");
try {
// Construct an app context to load the Java code into the current app.
Context webViewContext = initialApplication.createApplicationContext(
newPackageInfo.applicationInfo,
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
sPackageInfo = newPackageInfo;
return webViewContext;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (RemoteException | PackageManager.NameNotFoundException e) {
throw new MissingWebViewPackageException("Failed to load WebView provider: " + e);
}
}
/** @hide */
public static IWebViewUpdateService getUpdateService() {
return IWebViewUpdateService.Stub.asInterface(
ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
}