28

从 Android Pie (API 28) 开始,Google 不允许在 2 个不同的进程中使用单个 WebView 实例。

文档:https://developer.android.com/reference/android/webkit/WebView.html#setDataDirectorySuffix(java.lang.String)

根据需要,我打电话WebView.setDataDirectorySuffix("dir_name_no_separator")但不幸的是,我得到了一个例外。我尝试在第二个进程 Service onCreate() 中调用此方法。

java.lang.RuntimeException: Unable to create service com.myapp.service.MyService: java.lang.IllegalStateException: Can't set data directory suffix: WebView already initialized
        at android.app.ActivityThread.handleCreateService(ActivityThread.java:3544)
        at android.app.ActivityThread.access$1300(ActivityThread.java:199)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1666)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.IllegalStateException: Can't set data directory suffix: WebView already initialized
        at android.webkit.WebViewFactory.setDataDirectorySuffix(WebViewFactory.java:136)
        at android.webkit.WebView.setDataDirectorySuffix(WebView.java:2165)
        at com.myapp.service.MyService.onCreate(MyService.java:134)

我找不到该异常的任何原因。我没有两次调用这个方法,也没有在我的主进程中调用它。有任何想法吗?

4

3 回答 3

26

解决了。

我的项目托管 AdMob 广告,我在课堂上调用该MobileAds.initialize()方法。在调用该方法之前,广告初始化程序会加载现在禁止在新进程中执行的操作。ApplicationonCreate()WebViewWebView.setDataDirectorySuffix("dir_name_no_separator")

当创建第二个进程时,它也会经历相同的应用程序创建流程,这意味着它在类 onCreate()内部调用相同的流程,该流程调用试图创建新实例并导致崩溃的 。ApplicationMobileAds.initialize()WebView

IllegalStateException: Can't set data directory suffix: WebView already initialized

我是如何解决这个问题的?

我使用以下方法获取进程名称并检查它是否是我的主进程 - 调用 MobileAds.initialize() 方法,如果它是我的第二个进程,则调用该 WebView.setDataDirectorySuffix("dir_name_no_separator")方法。

获取进程名称:

public static String getProcessName(Context context) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
        if (processInfo.pid == android.os.Process.myPid()) {
            return processInfo.processName;
        }
    }

    return null;
}

应用程序类 onCreate():

if (!Utils.getProcessName(this).equals("YOUR_SECOND_PROCESS_NAME")) {
    MobileAds.initialize(this);
} else {
    WebView.setDataDirectorySuffix("dir_name_no_separator")
}
于 2018-08-16T14:55:55.410 回答
0

总结所有改进的修复,这是 Kotlin 中的代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    if (packageName != Application.getProcessName()) {
        WebView.setDataDirectorySuffix(Application.getProcessName())
    }
}

将其添加到您的Application类中以onCreate()方法。

请注意,这只会解决最多 2 个进程的问题。如果您的应用程序使用更多,您必须为每个应用程序提供不同的 WebView 后缀。

于 2020-05-12T09:34:23.933 回答
0

当由于广告而出错时,则在应用程序类中

try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val process = getProcessName()
            if (packageName != process) WebView.setDataDirectorySuffix(process)
        }

        MobileAds.initialize(this)
        AudienceNetworkAds.initialize(this)

    } catch (e: Error) {
        Timber.e(e)
    } catch (e: Exception) {
        Timber.e(e)
    }
于 2020-09-23T05:26:46.030 回答