确定 WebView 实现(系统 WebView 或 Chrome)
Posted
技术标签:
【中文标题】确定 WebView 实现(系统 WebView 或 Chrome)【英文标题】:Determine WebView Implementation (System WebView or Chrome) 【发布时间】:2017-05-05 05:14:26 【问题描述】:android 7.0 允许用户(通过开发人员选项)选择其 WebView 的实现。用户可以选择独立的 WebView 或使用 Chrome APK 来呈现 WebView。 Reference
由于这可能意味着使用 WebViews 的用户现在需要担心两个不同的代码库,因此了解当前选择了哪个实现会很有用。
有没有办法确定在 Android 7 中选择了哪种 WebView 实现?
【问题讨论】:
【参考方案1】:现在在 Android O 预览版中看起来像这样:
链接:https://developer.android.com/preview/features/managing-webview.html
从 Android 7.0(API 级别 24)开始,用户可以在多个 用于在 WebView 对象中显示 Web 内容的不同包。 Android O 包含一个 API,用于获取与 在您的应用中显示 Web 内容的包。这个 API 是 在分析仅当您的应用程序出现的错误时特别有用 尝试使用特定包的显示 Web 内容 WebView 的实现。
要使用这个API,添加如下代码sn-p所示的逻辑:
PackageInfo webViewPackageInfo = WebView.getCurrentWebViewPackage(); Log.d(TAG, "WebView version: " + webViewPackageInfo.versionName);
WebView.getCurrentWebViewPackage 文档:https://developer.android.com/reference/android/webkit/WebView.html#getCurrentWebViewPackage()
【讨论】:
还有WebViewCompat.getCurrentWebViewPackage()
可以在 L+ 上工作【参考方案2】:
为了获取当前的 Android WebView
实现和版本,我创建了这个方法,它应该对每个 API 级别都有效。
@SuppressLint("PrivateApi")
@SuppressWarnings("unchecked", "JavaReflectionInvocation")
public @Nullable PackageInfo getCurrentWebViewPackageInfo()
PackageInfo pInfo = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
//starting with Android O (API 26) they added a new method specific for this
pInfo = WebView.getCurrentWebViewPackage();
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
//with Android Lollipop (API 21) they started to update the WebView
//as a separate APK with the PlayStore and they added the
//getLoadedPackageInfo() method to the WebViewFactory class and this
//should handle the Android 7.0 behaviour changes too
try
Class webViewFactory = Class.forName("android.webkit.WebViewFactory");
Method method = webViewFactory.getMethod("getLoadedPackageInfo");
pInfo = (PackageInfo) method.invoke(null);
catch (Exception e)
e.printStackTrace();
else
//before Lollipop the WebView was bundled with the
//OS, the fixed versions can be found online, for example:
//Android 4.4 has WebView version 30.0.0.0
//Android 4.4.3 has WebView version 33.0.0.0
//etc...
return pInfo;
然后你可以评估结果
if (pInfo != null)
Log.d("WEBVIEW VERSION", pInfo.packageName + ", " + pInfo.versionName);
记住:WebView 的应用更新后,会立即崩溃 可能如下所示: https://***.com/a/29809338/2910520,此时,上面代码的这一行
webViewFactory.getMethod("getLoadedPackageInfo")
将返回null。 其实有 您无法采取任何措施来防止这种情况发生(如果 WebView 实现取自 Chrome 应用但未得到确认,则不应发生这种情况)。
【讨论】:
对于第二种方法(Lollipop 直到 Oreo),您必须确保“WebView 已加载到当前进程中”。如果没有初始化 WebViewgetLoadedPackageInfo
将返回 null。
目前无法知道 WebView 何时加载。这就是代码在 try-catch 中的原因。也许我们可以添加一个延迟来执行检查,以便有更多的机会加载 WebView。我可以向你保证,即使我只调用公共 API,我也会遇到同样的问题,例如在 Application 中调用 WebView.enableSlowWholeDocumentDraw() 作为第一件事,我已经报告了与此相关的背景异常的 CrashLytics :(
@MatPag 在将 WebView 实现连接到当前进程之前,我们可以安全地假设这只是时间问题吗?当通过通知中的 PendingIntent 启动时,我在膨胀 WebView 的活动中偶尔遇到 RuntimeException 崩溃。您认为添加延迟可能会有所帮助吗?谢谢【参考方案3】:
作为the answer of DataDino 的补充信息,对于低于 26 的 API,这里有一段代码可以提供所需的输出:
Class webViewFactory = Class.forName("android.webkit.WebViewFactory");
Method method = webViewFactory.getMethod("getLoadedPackageInfo");
PackageInfo packageInfo = (PackageInfo) method.invoke(null, null);
if ("com.android.webview".equals(packageInfo.packageName))
// "Android System WebView" is selected
else
// something else selected
// in case of chrome it would be "com.android.chrome"
【讨论】:
【参考方案4】:有一个appCompat版本:
WebViewCompat.getCurrentWebViewPackage(context)
【讨论】:
【参考方案5】:dependencies
// ...
implementation 'androidx.webkit:webkit:1.4.0' // Add to your gradle
public static String WebViewPackageName(Context context)
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(context);
return webViewPackageInfo.packageName;
【讨论】:
以上是关于确定 WebView 实现(系统 WebView 或 Chrome)的主要内容,如果未能解决你的问题,请参考以下文章