This is an automated email from the ASF dual-hosted git repository.

GitToTheHub pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/cordova-plugin-inappbrowser.git


The following commit(s) were added to refs/heads/master by this push:
     new 1b0be4a  fix: defer navigation until async cookie or data clearing 
completes (#1150)
1b0be4a is described below

commit 1b0be4aba620d08cdfa9ddefa312d719ae36d497
Author: Manuel Beck <[email protected]>
AuthorDate: Wed May 20 10:51:29 2026 +0200

    fix: defer navigation until async cookie or data clearing completes (#1150)
    
    - Fixes #521: Cookies were persisting despite clearcache/clearsessioncache 
options because navigation started before async clearing operations finished, 
causing a race condition.
---
 src/android/InAppBrowser.java |  44 ++++++++++++---
 src/ios/CDVWKInAppBrowser.m   | 121 ++++++++++++++++++++++++++++++++----------
 2 files changed, 130 insertions(+), 35 deletions(-)

diff --git a/src/android/InAppBrowser.java b/src/android/InAppBrowser.java
index 04fe57b..258a1a7 100644
--- a/src/android/InAppBrowser.java
+++ b/src/android/InAppBrowser.java
@@ -745,6 +745,36 @@ public class InAppBrowser extends CordovaPlugin {
                 return value;
             }
 
+            /**
+             * Clears cookies according to the active options and invokes 
completion when finished.
+             *
+             * Cookie clearing APIs are asynchronous (API 22+), so loadUrl 
must run in the callback
+             * to avoid a race where navigation starts before cookie deletion 
is complete.
+             */
+            private void clearCookies(final Runnable completion) {
+                final CookieManager cookieManager = 
CookieManager.getInstance();
+
+                if (clearAllCache) {
+                    cookieManager.removeAllCookies(new 
ValueCallback<Boolean>() {
+                        @Override
+                        public void onReceiveValue(Boolean value) {
+                            cookieManager.flush();
+                            completion.run();
+                        }
+                    });
+                } else if (clearSessionCache) {
+                    cookieManager.removeSessionCookies(new 
ValueCallback<Boolean>() {
+                        @Override
+                        public void onReceiveValue(Boolean value) {
+                            cookieManager.flush();
+                            completion.run();
+                        }
+                    });
+                } else {
+                    completion.run();
+                }
+            }
+
             private View createCloseButton(int id) {
                 View _close;
                 Resources activityRes = cordova.getActivity().getResources();
@@ -1090,16 +1120,16 @@ public class InAppBrowser extends CordovaPlugin {
                 }
                 settings.setDomStorageEnabled(true);
 
-                if (clearAllCache) {
-                    CookieManager.getInstance().removeAllCookie();
-                } else if (clearSessionCache) {
-                    CookieManager.getInstance().removeSessionCookie();
-                }
-
                 // Enable Thirdparty Cookies
                 
CookieManager.getInstance().setAcceptThirdPartyCookies(inAppWebView,true);
 
-                inAppWebView.loadUrl(url);
+                // Delay navigation until cookie clearing is complete (or 
skipped).
+                clearCookies(new Runnable() {
+                    @Override
+                    public void run() {
+                        inAppWebView.loadUrl(url);
+                    }
+                });
                 inAppWebView.setId(Integer.valueOf(6));
                 inAppWebView.getSettings().setLoadWithOverviewMode(true);
                 inAppWebView.getSettings().setUseWideViewPort(useWideViewPort);
diff --git a/src/ios/CDVWKInAppBrowser.m b/src/ios/CDVWKInAppBrowser.m
index fea8bea..b826c92 100644
--- a/src/ios/CDVWKInAppBrowser.m
+++ b/src/ios/CDVWKInAppBrowser.m
@@ -120,8 +120,6 @@
 {
     CDVInAppBrowserOptions *browserOptions = [CDVInAppBrowserOptions 
parseOptions:options];
 
-    [self clearWebsiteDataByOptions:browserOptions];
-
     if (self.inAppBrowserViewController == nil) {
         self.inAppBrowserViewController = [[CDVWKInAppBrowserViewController 
alloc] initWithBrowserOptions: browserOptions 
andSettings:self.commandDelegate.settings];
         self.inAppBrowserViewController.navigationDelegate = self;
@@ -176,10 +174,19 @@
     }
     _waitForBeforeload = ![_beforeload isEqualToString:@""];
 
-    [self.inAppBrowserViewController navigateTo:url];
-    if (!browserOptions.hidden) {
-        [self show:nil withNoAnimate:browserOptions.hidden];
-    }
+    __weak CDVWKInAppBrowser *weakSelf = self;
+    // Delay the initial navigation until requested clearing operations 
complete.
+    [self clearWebsiteDataByOptions:browserOptions completionHandler:^{
+        __strong __typeof(weakSelf) strongSelf = weakSelf;
+        if (strongSelf == nil || strongSelf.inAppBrowserViewController == nil) 
{
+            return;
+        }
+
+        [strongSelf.inAppBrowserViewController navigateTo:url];
+        if (!browserOptions.hidden) {
+            [strongSelf show:nil withNoAnimate:browserOptions.hidden];
+        }
+    }];
 }
 
 /**
@@ -187,42 +194,100 @@
  * This will clear the data on the Cordova WebView also.
  *
  * @param browserOptions The options specifying which types of data to clear.
+ * @param completionHandler Called after all requested clearing operations are 
complete.
  */
-- (void)clearWebsiteDataByOptions:(CDVInAppBrowserOptions *)browserOptions
+- (void)clearWebsiteDataByOptions:(CDVInAppBrowserOptions *)browserOptions 
completionHandler:(void (^)(void))completionHandler
 {
     // NOTE: [WKWebsiteDataStore defaultDataStore] will get the default data 
store of the app,
     // which is shared between all WKWebViews, which means also the Cordova 
WebView
     WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore];
 
+    // Option precedence:
+    // 1) cleardata: clears all web data (including cookies), so cookie 
options are skipped.
+    // 2) clearcache: clears all cookies (session + persistent).
+    // 3) clearsessioncache: clears only session cookies.
+    // 4) no clear options: continue immediately.
     if (browserOptions.cleardata) {
-        [dataStore 
fetchDataRecordsOfTypes:WKWebsiteDataStore.allWebsiteDataTypes 
completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
-            [dataStore 
removeDataOfTypes:WKWebsiteDataStore.allWebsiteDataTypes forDataRecords:records 
completionHandler:^{
-                NSLog(@"Removed all WKWebView data");
-                // Create new WKProcessPool
-                if (@available(iOS 15.0, *)) {
-                    // Since iOS 15 WKProcessPool is deprecated and has no 
effect
-                } else {
+        [self clearData:dataStore completionHandler:completionHandler];
+        return;
+    }
+
+    if (browserOptions.clearcache) {
+        [self clearCookie:dataStore sessionOnly:NO 
completionHandler:completionHandler];
+        return;
+    }
+
+    if (browserOptions.clearsessioncache) {
+        [self clearCookie:dataStore sessionOnly:YES 
completionHandler:completionHandler];
+        return;
+    }
+
+    if (completionHandler != nil) {
+        completionHandler();
+    }
+}
+
+/**
+ * Clears all WKWebView website data types (cookies, local storage, IndexedDB, 
cache, etc.).
+ */
+- (void)clearData:(WKWebsiteDataStore *)dataStore completionHandler:(void 
(^)(void))completionHandler
+{
+    [dataStore fetchDataRecordsOfTypes:WKWebsiteDataStore.allWebsiteDataTypes 
completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
+        [dataStore removeDataOfTypes:WKWebsiteDataStore.allWebsiteDataTypes 
forDataRecords:records completionHandler:^{
+            NSLog(@"Removed all WKWebView data");
+            // Create new WKProcessPool
+            if (@available(iOS 15.0, *)) {
+                // Since iOS 15 WKProcessPool is deprecated and has no effect
+            } else {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-                    // Set for iOS 14 and below a new process pool
-                    
self.inAppBrowserViewController.webView.configuration.processPool = 
[[WKProcessPool alloc] init]; // create new process pool to flush all data
+                // Set for iOS 14 and below a new process pool
+                
self.inAppBrowserViewController.webView.configuration.processPool = 
[[WKProcessPool alloc] init]; // create new process pool to flush all data
 #pragma clang diagnostic pop
             }
-            }];
-        }];
-    }
 
-    // Deletes all cookies or session cookies
-    if (browserOptions.clearcache || browserOptions.clearsessioncache) {
-        WKHTTPCookieStore *cookieStore = dataStore.httpCookieStore;
-        [cookieStore getAllCookies:^(NSArray *cookies) {
-            for (NSHTTPCookie *cookie in cookies) {
-                if (browserOptions.clearcache || 
(browserOptions.clearsessioncache && cookie.sessionOnly)) {
-                    [cookieStore deleteCookie:cookie completionHandler:nil];
-                }
+            if (completionHandler != nil) {
+                completionHandler();
             }
         }];
-    }
+    }];
+}
+
+/**
+ * Clears cookies from the shared cookie store.
+ * sessionOnly=NO: clear all cookies.
+ * sessionOnly=YES: clear only session cookies.
+ */
+- (void)clearCookie:(WKWebsiteDataStore *)dataStore 
sessionOnly:(BOOL)sessionOnly completionHandler:(void 
(^)(void))completionHandler
+{
+    WKHTTPCookieStore *cookieStore = dataStore.httpCookieStore;
+    [cookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *cookies) {
+        NSMutableArray<NSHTTPCookie *> *cookiesToDelete = [NSMutableArray 
array];
+        for (NSHTTPCookie *cookie in cookies) {
+            if (!sessionOnly || cookie.sessionOnly) {
+                [cookiesToDelete addObject:cookie];
+            }
+        }
+
+        // No cookies available, return
+        if (cookiesToDelete.count == 0) {
+            if (completionHandler != nil) {
+                completionHandler();
+            }
+            return;
+        }
+
+        // [WKHTTPCookieStore deleteCookie] is async, so complete only after 
the final callback.
+        __block NSUInteger pendingCookieDeletes = cookiesToDelete.count;
+        for (NSHTTPCookie *cookie in cookiesToDelete) {
+            [cookieStore deleteCookie:cookie completionHandler:^{
+                pendingCookieDeletes--;
+                if (pendingCookieDeletes == 0 && completionHandler != nil) {
+                    completionHandler();
+                }
+            }];
+        }
+    }];
 }
 
 - (void)show:(CDVInvokedUrlCommand *)command


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to