@capgo/inappbrowser 6.4.4 → 6.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -70,6 +70,8 @@ Add the following to your `Info.plist` file:
70
70
 
71
71
  * [`open(...)`](#open)
72
72
  * [`clearCookies(...)`](#clearcookies)
73
+ * [`clearAllCookies()`](#clearallcookies)
74
+ * [`clearCache()`](#clearcache)
73
75
  * [`getCookies(...)`](#getcookies)
74
76
  * [`close()`](#close)
75
77
  * [`openWebView(...)`](#openwebview)
@@ -131,6 +133,36 @@ Clear cookies of url
131
133
  --------------------
132
134
 
133
135
 
136
+ ### clearAllCookies()
137
+
138
+ ```typescript
139
+ clearAllCookies() => Promise<any>
140
+ ```
141
+
142
+ Clear all cookies
143
+
144
+ **Returns:** <code>Promise&lt;any&gt;</code>
145
+
146
+ **Since:** 6.5.0
147
+
148
+ --------------------
149
+
150
+
151
+ ### clearCache()
152
+
153
+ ```typescript
154
+ clearCache() => Promise<any>
155
+ ```
156
+
157
+ Clear cache
158
+
159
+ **Returns:** <code>Promise&lt;any&gt;</code>
160
+
161
+ **Since:** 6.5.0
162
+
163
+ --------------------
164
+
165
+
134
166
  ### getCookies(...)
135
167
 
136
168
  ```typescript
@@ -402,10 +434,9 @@ Reload the current web page.
402
434
 
403
435
  #### ClearCookieOptions
404
436
 
405
- | Prop | Type |
406
- | ----------- | -------------------- |
407
- | **`url`** | <code>string</code> |
408
- | **`cache`** | <code>boolean</code> |
437
+ | Prop | Type |
438
+ | --------- | ------------------- |
439
+ | **`url`** | <code>string</code> |
409
440
 
410
441
 
411
442
  #### HttpCookie
@@ -427,31 +458,32 @@ Reload the current web page.
427
458
 
428
459
  #### OpenWebViewOptions
429
460
 
430
- | Prop | Type | Description | Default | Since |
431
- | -------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ |
432
- | **`url`** | <code>string</code> | Target URL to load. | | 0.1.0 |
433
- | **`headers`** | <code><a href="#headers">Headers</a></code> | <a href="#headers">Headers</a> to send with the request. | | 0.1.0 |
434
- | **`credentials`** | <code><a href="#credentials">Credentials</a></code> | <a href="#credentials">Credentials</a> to send with the request and all subsequent requests for the same host. | | 6.1.0 |
435
- | **`shareDisclaimer`** | <code><a href="#disclaimeroptions">DisclaimerOptions</a></code> | share options | | 0.1.0 |
436
- | **`toolbarType`** | <code><a href="#toolbartype">ToolBarType</a></code> | Toolbar type | <code>ToolBarType.DEFAULT</code> | 0.1.0 |
437
- | **`shareSubject`** | <code>string</code> | Share subject | | 0.1.0 |
438
- | **`title`** | <code>string</code> | Title of the browser | <code>'New Window'</code> | 0.1.0 |
439
- | **`backgroundColor`** | <code><a href="#backgroundcolor">BackgroundColor</a></code> | Background color of the browser, only on IOS | <code>BackgroundColor.BLACK</code> | 0.1.0 |
440
- | **`activeNativeNavigationForWebview`** | <code>boolean</code> | If true, active the native navigation within the webview, Android only | <code>false</code> | |
441
- | **`disableGoBackOnNativeApplication`** | <code>boolean</code> | Disable the possibility to go back on native application, usefull to force user to stay on the webview, Android only | <code>false</code> | |
442
- | **`isPresentAfterPageLoad`** | <code>boolean</code> | Open url in a new window fullscreen isPresentAfterPageLoad: if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | <code>false</code> | 0.1.0 |
443
- | **`isInspectable`** | <code>boolean</code> | Whether the website in the webview is inspectable or not, ios only | <code>false</code> | |
444
- | **`isAnimated`** | <code>boolean</code> | Whether the webview opening is animated or not, ios only | <code>true</code> | |
445
- | **`showReloadButton`** | <code>boolean</code> | Shows a reload button that reloads the web page | <code>false</code> | 1.0.15 |
446
- | **`closeModal`** | <code>boolean</code> | CloseModal: if true a confirm will be displayed when user clicks on close button, if false the browser will be closed immediately. | <code>false</code> | 1.1.0 |
447
- | **`closeModalTitle`** | <code>string</code> | CloseModalTitle: title of the confirm when user clicks on close button, only on IOS | <code>'Close'</code> | 1.1.0 |
448
- | **`closeModalDescription`** | <code>string</code> | CloseModalDescription: description of the confirm when user clicks on close button, only on IOS | <code>'Are you sure you want to close this window?'</code> | 1.1.0 |
449
- | **`closeModalOk`** | <code>string</code> | CloseModalOk: text of the confirm button when user clicks on close button, only on IOS | <code>'Close'</code> | 1.1.0 |
450
- | **`closeModalCancel`** | <code>string</code> | CloseModalCancel: text of the cancel button when user clicks on close button, only on IOS | <code>'Cancel'</code> | 1.1.0 |
451
- | **`visibleTitle`** | <code>boolean</code> | visibleTitle: if true the website title would be shown else shown empty | <code>true</code> | 1.2.5 |
452
- | **`toolbarColor`** | <code>string</code> | toolbarColor: color of the toolbar in hex format | <code>'#ffffff''</code> | 1.2.5 |
453
- | **`showArrow`** | <code>boolean</code> | showArrow: if true an arrow would be shown instead of cross for closing the window | <code>false</code> | 1.2.5 |
454
- | **`ignoreUntrustedSSLError`** | <code>boolean</code> | ignoreUntrustedSSLError: if true, the webview will ignore untrusted SSL errors allowing the user to view the website. | <code>false</code> | 6.1.0 |
461
+ | Prop | Type | Description | Default | Since |
462
+ | -------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ |
463
+ | **`url`** | <code>string</code> | Target URL to load. | | 0.1.0 |
464
+ | **`headers`** | <code><a href="#headers">Headers</a></code> | <a href="#headers">Headers</a> to send with the request. | | 0.1.0 |
465
+ | **`credentials`** | <code><a href="#credentials">Credentials</a></code> | <a href="#credentials">Credentials</a> to send with the request and all subsequent requests for the same host. | | 6.1.0 |
466
+ | **`shareDisclaimer`** | <code><a href="#disclaimeroptions">DisclaimerOptions</a></code> | share options | | 0.1.0 |
467
+ | **`toolbarType`** | <code><a href="#toolbartype">ToolBarType</a></code> | Toolbar type | <code>ToolBarType.DEFAULT</code> | 0.1.0 |
468
+ | **`shareSubject`** | <code>string</code> | Share subject | | 0.1.0 |
469
+ | **`title`** | <code>string</code> | Title of the browser | <code>'New Window'</code> | 0.1.0 |
470
+ | **`backgroundColor`** | <code><a href="#backgroundcolor">BackgroundColor</a></code> | Background color of the browser, only on IOS | <code>BackgroundColor.BLACK</code> | 0.1.0 |
471
+ | **`activeNativeNavigationForWebview`** | <code>boolean</code> | If true, active the native navigation within the webview, Android only | <code>false</code> | |
472
+ | **`disableGoBackOnNativeApplication`** | <code>boolean</code> | Disable the possibility to go back on native application, usefull to force user to stay on the webview, Android only | <code>false</code> | |
473
+ | **`isPresentAfterPageLoad`** | <code>boolean</code> | Open url in a new window fullscreen isPresentAfterPageLoad: if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | <code>false</code> | 0.1.0 |
474
+ | **`isInspectable`** | <code>boolean</code> | Whether the website in the webview is inspectable or not, ios only | <code>false</code> | |
475
+ | **`isAnimated`** | <code>boolean</code> | Whether the webview opening is animated or not, ios only | <code>true</code> | |
476
+ | **`showReloadButton`** | <code>boolean</code> | Shows a reload button that reloads the web page | <code>false</code> | 1.0.15 |
477
+ | **`closeModal`** | <code>boolean</code> | CloseModal: if true a confirm will be displayed when user clicks on close button, if false the browser will be closed immediately. | <code>false</code> | 1.1.0 |
478
+ | **`closeModalTitle`** | <code>string</code> | CloseModalTitle: title of the confirm when user clicks on close button, only on IOS | <code>'Close'</code> | 1.1.0 |
479
+ | **`closeModalDescription`** | <code>string</code> | CloseModalDescription: description of the confirm when user clicks on close button, only on IOS | <code>'Are you sure you want to close this window?'</code> | 1.1.0 |
480
+ | **`closeModalOk`** | <code>string</code> | CloseModalOk: text of the confirm button when user clicks on close button, only on IOS | <code>'Close'</code> | 1.1.0 |
481
+ | **`closeModalCancel`** | <code>string</code> | CloseModalCancel: text of the cancel button when user clicks on close button, only on IOS | <code>'Cancel'</code> | 1.1.0 |
482
+ | **`visibleTitle`** | <code>boolean</code> | visibleTitle: if true the website title would be shown else shown empty | <code>true</code> | 1.2.5 |
483
+ | **`toolbarColor`** | <code>string</code> | toolbarColor: color of the toolbar in hex format | <code>'#ffffff''</code> | 1.2.5 |
484
+ | **`showArrow`** | <code>boolean</code> | showArrow: if true an arrow would be shown instead of cross for closing the window | <code>false</code> | 1.2.5 |
485
+ | **`ignoreUntrustedSSLError`** | <code>boolean</code> | ignoreUntrustedSSLError: if true, the webview will ignore untrusted SSL errors allowing the user to view the website. | <code>false</code> | 6.1.0 |
486
+ | **`preShowScript`** | <code><a href="#string">String</a></code> | preShowScript: if isPresentAfterPageLoad is true and this variable is set the plugin will inject a script before showing the browser. This script will be run in an async context. The plugin will wait for the script to finish (max 10 seconds) | | 6.6.0 |
455
487
 
456
488
 
457
489
  #### DisclaimerOptions
@@ -464,6 +496,72 @@ Reload the current web page.
464
496
  | **`cancelBtn`** | <code>string</code> |
465
497
 
466
498
 
499
+ #### String
500
+
501
+ Allows manipulation and formatting of text strings and determination and location of substrings within strings.
502
+
503
+ | Prop | Type | Description |
504
+ | ------------ | ------------------- | ------------------------------------------------------------ |
505
+ | **`length`** | <code>number</code> | Returns the length of a <a href="#string">String</a> object. |
506
+
507
+ | Method | Signature | Description |
508
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
509
+ | **toString** | () =&gt; string | Returns a string representation of a string. |
510
+ | **charAt** | (pos: number) =&gt; string | Returns the character at the specified index. |
511
+ | **charCodeAt** | (index: number) =&gt; number | Returns the Unicode value of the character at the specified location. |
512
+ | **concat** | (...strings: string[]) =&gt; string | Returns a string that contains the concatenation of two or more strings. |
513
+ | **indexOf** | (searchString: string, position?: number \| undefined) =&gt; number | Returns the position of the first occurrence of a substring. |
514
+ | **lastIndexOf** | (searchString: string, position?: number \| undefined) =&gt; number | Returns the last occurrence of a substring in the string. |
515
+ | **localeCompare** | (that: string) =&gt; number | Determines whether two strings are equivalent in the current locale. |
516
+ | **match** | (regexp: string \| <a href="#regexp">RegExp</a>) =&gt; <a href="#regexpmatcharray">RegExpMatchArray</a> \| null | Matches a string with a regular expression, and returns an array containing the results of that search. |
517
+ | **replace** | (searchValue: string \| <a href="#regexp">RegExp</a>, replaceValue: string) =&gt; string | Replaces text in a string, using a regular expression or search string. |
518
+ | **replace** | (searchValue: string \| <a href="#regexp">RegExp</a>, replacer: (substring: string, ...args: any[]) =&gt; string) =&gt; string | Replaces text in a string, using a regular expression or search string. |
519
+ | **search** | (regexp: string \| <a href="#regexp">RegExp</a>) =&gt; number | Finds the first substring match in a regular expression search. |
520
+ | **slice** | (start?: number \| undefined, end?: number \| undefined) =&gt; string | Returns a section of a string. |
521
+ | **split** | (separator: string \| <a href="#regexp">RegExp</a>, limit?: number \| undefined) =&gt; string[] | Split a string into substrings using the specified separator and return them as an array. |
522
+ | **substring** | (start: number, end?: number \| undefined) =&gt; string | Returns the substring at the specified location within a <a href="#string">String</a> object. |
523
+ | **toLowerCase** | () =&gt; string | Converts all the alphabetic characters in a string to lowercase. |
524
+ | **toLocaleLowerCase** | (locales?: string \| string[] \| undefined) =&gt; string | Converts all alphabetic characters to lowercase, taking into account the host environment's current locale. |
525
+ | **toUpperCase** | () =&gt; string | Converts all the alphabetic characters in a string to uppercase. |
526
+ | **toLocaleUpperCase** | (locales?: string \| string[] \| undefined) =&gt; string | Returns a string where all alphabetic characters have been converted to uppercase, taking into account the host environment's current locale. |
527
+ | **trim** | () =&gt; string | Removes the leading and trailing white space and line terminator characters from a string. |
528
+ | **substr** | (from: number, length?: number \| undefined) =&gt; string | Gets a substring beginning at the specified location and having the specified length. |
529
+ | **valueOf** | () =&gt; string | Returns the primitive value of the specified object. |
530
+
531
+
532
+ #### RegExpMatchArray
533
+
534
+ | Prop | Type |
535
+ | ----------- | ------------------- |
536
+ | **`index`** | <code>number</code> |
537
+ | **`input`** | <code>string</code> |
538
+
539
+
540
+ #### RegExp
541
+
542
+ | Prop | Type | Description |
543
+ | ---------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
544
+ | **`source`** | <code>string</code> | Returns a copy of the text of the regular expression pattern. Read-only. The regExp argument is a Regular expression object. It can be a variable name or a literal. |
545
+ | **`global`** | <code>boolean</code> | Returns a Boolean value indicating the state of the global flag (g) used with a regular expression. Default is false. Read-only. |
546
+ | **`ignoreCase`** | <code>boolean</code> | Returns a Boolean value indicating the state of the ignoreCase flag (i) used with a regular expression. Default is false. Read-only. |
547
+ | **`multiline`** | <code>boolean</code> | Returns a Boolean value indicating the state of the multiline flag (m) used with a regular expression. Default is false. Read-only. |
548
+ | **`lastIndex`** | <code>number</code> | |
549
+
550
+ | Method | Signature | Description |
551
+ | ----------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
552
+ | **exec** | (string: string) =&gt; <a href="#regexpexecarray">RegExpExecArray</a> \| null | Executes a search on a string using a regular expression pattern, and returns an array containing the results of that search. |
553
+ | **test** | (string: string) =&gt; boolean | Returns a Boolean value that indicates whether or not a pattern exists in a searched string. |
554
+ | **compile** | () =&gt; this | |
555
+
556
+
557
+ #### RegExpExecArray
558
+
559
+ | Prop | Type |
560
+ | ----------- | ------------------- |
561
+ | **`index`** | <code>number</code> |
562
+ | **`input`** | <code>string</code> |
563
+
564
+
467
565
  #### PluginListenerHandle
468
566
 
469
567
  | Prop | Type |
@@ -9,9 +9,14 @@ import android.content.pm.ResolveInfo;
9
9
  import android.net.Uri;
10
10
  import android.os.Bundle;
11
11
  import android.text.TextUtils;
12
+ import android.util.ArrayMap;
12
13
  import android.util.Log;
14
+ import android.view.View;
15
+ import android.view.View;
13
16
  import android.webkit.CookieManager;
14
17
  import android.webkit.PermissionRequest;
18
+ import android.webkit.WebResourceRequest;
19
+ import android.webkit.WebResourceResponse;
15
20
  import androidx.browser.customtabs.CustomTabsCallback;
16
21
  import androidx.browser.customtabs.CustomTabsClient;
17
22
  import androidx.browser.customtabs.CustomTabsIntent;
@@ -25,7 +30,13 @@ import com.getcapacitor.PluginMethod;
25
30
  import com.getcapacitor.annotation.CapacitorPlugin;
26
31
  import com.getcapacitor.annotation.Permission;
27
32
  import com.getcapacitor.annotation.PermissionCallback;
33
+ import java.util.ArrayList;
28
34
  import java.util.Iterator;
35
+ import java.util.List;
36
+ import java.util.Objects;
37
+ import java.util.Optional;
38
+ import java.util.UUID;
39
+ import java.util.concurrent.Semaphore;
29
40
  import org.json.JSONException;
30
41
  import org.json.JSONObject;
31
42
 
@@ -137,7 +148,16 @@ public class InAppBrowserPlugin
137
148
 
138
149
  if (resultCode == Activity.RESULT_OK) {
139
150
  if (data != null) {
140
- results = new Uri[] { data.getData() };
151
+ String dataString = data.getDataString();
152
+ if (data.getClipData() != null) { // If multiple file selected
153
+ int count = data.getClipData().getItemCount();
154
+ results = new Uri[count];
155
+ for (int i = 0; i < count; i++) {
156
+ results[i] = data.getClipData().getItemAt(i).getUri();
157
+ }
158
+ } else if (dataString != null) { //if single file selected
159
+ results = new Uri[] { Uri.parse(dataString) };
160
+ }
141
161
  }
142
162
  }
143
163
 
@@ -284,23 +304,83 @@ public class InAppBrowserPlugin
284
304
  call.resolve();
285
305
  }
286
306
 
307
+ @PluginMethod
308
+ public void clearCache(PluginCall call) {
309
+ CookieManager cookieManager = CookieManager.getInstance();
310
+ cookieManager.removeAllCookies(null);
311
+ cookieManager.flush();
312
+ call.resolve();
313
+ }
314
+
315
+ @PluginMethod
316
+ public void clearAllCookies(PluginCall call) {
317
+ CookieManager cookieManager = CookieManager.getInstance();
318
+ cookieManager.removeAllCookies(null);
319
+ cookieManager.flush();
320
+ call.resolve();
321
+ }
322
+
287
323
  @PluginMethod
288
324
  public void clearCookies(PluginCall call) {
289
325
  String url = call.getString("url", currentUrl);
290
- Boolean clearCache = call.getBoolean("cache", false);
291
326
  if (url == null || TextUtils.isEmpty(url)) {
292
327
  call.reject("Invalid URL");
293
- } else {
294
- CookieManager cookieManager = CookieManager.getInstance();
295
- String cookie = cookieManager.getCookie(url);
296
- if (cookie != null) {
297
- cookieManager.removeAllCookies(null);
298
- if (Boolean.TRUE.equals(clearCache)) {
299
- cookieManager.removeSessionCookies(null);
328
+ return;
329
+ }
330
+
331
+ Uri uri = Uri.parse(url);
332
+ String host = uri.getHost();
333
+ if (host == null || TextUtils.isEmpty(host)) {
334
+ call.reject("Invalid URL (Host is null)");
335
+ return;
336
+ }
337
+
338
+ CookieManager cookieManager = CookieManager.getInstance();
339
+ String cookieString = cookieManager.getCookie(url);
340
+ ArrayList<String> cookiesToRemove = new ArrayList<>();
341
+
342
+ cookiesToRemove.clear();
343
+
344
+ if (cookieString != null) {
345
+ String[] cookies = cookieString.split("; ");
346
+
347
+ String domain = uri.getHost();
348
+
349
+ for (String cookie : cookies) {
350
+ String[] parts = cookie.split("=");
351
+ if (parts.length > 0) {
352
+ cookiesToRemove.add(parts[0].trim());
353
+ CookieManager.getInstance()
354
+ .setCookie(url, String.format("%s=del;", parts[0].trim()));
300
355
  }
301
356
  }
302
- call.resolve();
303
357
  }
358
+
359
+ StringBuilder scriptToRun = new StringBuilder();
360
+ for (String cookieToRemove : cookiesToRemove) {
361
+ scriptToRun.append(
362
+ String.format(
363
+ "window.cookieStore.delete('%s', {name: '%s', domain: '%s'});",
364
+ cookieToRemove,
365
+ cookieToRemove,
366
+ url
367
+ )
368
+ );
369
+ }
370
+
371
+ Log.i("DelCookies", String.format("Script to run:\n%s", scriptToRun));
372
+
373
+ this.getActivity()
374
+ .runOnUiThread(
375
+ new Runnable() {
376
+ @Override
377
+ public void run() {
378
+ webViewDialog.executeScript(scriptToRun.toString());
379
+ }
380
+ }
381
+ );
382
+
383
+ call.resolve();
304
384
  }
305
385
 
306
386
  @PluginMethod
@@ -350,6 +430,7 @@ public class InAppBrowserPlugin
350
430
  Boolean.TRUE.equals(call.getBoolean("ignoreUntrustedSSLError", false))
351
431
  );
352
432
  options.setShareDisclaimer(call.getObject("shareDisclaimer", null));
433
+ options.setPreShowScript(call.getString("preShowScript", null));
353
434
  options.setShareSubject(call.getString("shareSubject", null));
354
435
  options.setToolbarType(call.getString("toolbarType", ""));
355
436
  options.setActiveNativeNavigationForWebview(
@@ -26,6 +26,7 @@ public class Options {
26
26
  private String ToolbarColor;
27
27
  private boolean ShowArrow;
28
28
  private boolean ignoreUntrustedSSLError;
29
+ private String preShowScript;
29
30
 
30
31
  public PluginCall getPluginCall() {
31
32
  return pluginCall;
@@ -208,4 +209,12 @@ public class Options {
208
209
  public void setIgnoreUntrustedSSLError(boolean _ignoreUntrustedSSLError) {
209
210
  this.ignoreUntrustedSSLError = _ignoreUntrustedSSLError;
210
211
  }
212
+
213
+ public String getPreShowScript() {
214
+ return preShowScript;
215
+ }
216
+
217
+ public void setPreShowScript(String preLoadScript) {
218
+ this.preShowScript = preLoadScript;
219
+ }
211
220
  }
@@ -14,6 +14,7 @@ import android.net.Uri;
14
14
  import android.net.http.SslError;
15
15
  import android.text.TextUtils;
16
16
  import android.util.Log;
17
+ import android.view.KeyEvent;
17
18
  import android.view.View;
18
19
  import android.view.Window;
19
20
  import android.view.WindowManager;
@@ -25,12 +26,14 @@ import android.webkit.ValueCallback;
25
26
  import android.webkit.WebChromeClient;
26
27
  import android.webkit.WebResourceError;
27
28
  import android.webkit.WebResourceRequest;
29
+ import android.webkit.WebResourceResponse;
28
30
  import android.webkit.WebView;
29
31
  import android.webkit.WebViewClient;
30
32
  import android.widget.ImageButton;
31
33
  import android.widget.TextView;
32
34
  import android.widget.Toast;
33
35
  import android.widget.Toolbar;
36
+ import androidx.annotation.Nullable;
34
37
  import com.getcapacitor.JSObject;
35
38
  import java.net.URI;
36
39
  import java.net.URISyntaxException;
@@ -38,6 +41,10 @@ import java.util.HashMap;
38
41
  import java.util.Iterator;
39
42
  import java.util.Map;
40
43
  import java.util.Objects;
44
+ import java.util.concurrent.ExecutorService;
45
+ import java.util.concurrent.Executors;
46
+ import java.util.concurrent.Semaphore;
47
+ import java.util.concurrent.TimeUnit;
41
48
  import org.json.JSONArray;
42
49
  import org.json.JSONObject;
43
50
 
@@ -50,10 +57,14 @@ public class WebViewDialog extends Dialog {
50
57
  public Activity activity;
51
58
  private boolean isInitialized = false;
52
59
 
60
+ Semaphore preShowSemaphore = null;
61
+ String preshowError = null;
62
+
53
63
  public PermissionRequest currentPermissionRequest;
54
64
  public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
55
65
  public ValueCallback<Uri> mUploadMessage;
56
66
  public ValueCallback<Uri[]> mFilePathCallback;
67
+ ExecutorService executorService = Executors.newFixedThreadPool(1);
57
68
 
58
69
  public interface PermissionHandler {
59
70
  void handleCameraPermissionRequest(PermissionRequest request);
@@ -85,6 +96,26 @@ public class WebViewDialog extends Dialog {
85
96
  }
86
97
  }
87
98
 
99
+ public class PreShowScriptInterface {
100
+
101
+ @JavascriptInterface
102
+ public void error(String error) {
103
+ // Handle message from JavaScript
104
+ if (preShowSemaphore != null) {
105
+ preshowError = error;
106
+ preShowSemaphore.release();
107
+ }
108
+ }
109
+
110
+ @JavascriptInterface
111
+ public void success() {
112
+ // Handle message from JavaScript
113
+ if (preShowSemaphore != null) {
114
+ preShowSemaphore.release();
115
+ }
116
+ }
117
+ }
118
+
88
119
  public void presentWebView() {
89
120
  requestWindowFeature(Window.FEATURE_NO_TITLE);
90
121
  setCancelable(true);
@@ -105,6 +136,10 @@ public class WebViewDialog extends Dialog {
105
136
  new JavaScriptInterface(),
106
137
  "AndroidInterface"
107
138
  );
139
+ _webView.addJavascriptInterface(
140
+ new PreShowScriptInterface(),
141
+ "PreShowScriptInterface"
142
+ );
108
143
  _webView.getSettings().setJavaScriptEnabled(true);
109
144
  _webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
110
145
  _webView.getSettings().setDatabaseEnabled(true);
@@ -117,6 +152,7 @@ public class WebViewDialog extends Dialog {
117
152
  _webView.getSettings().setUseWideViewPort(true);
118
153
  _webView.getSettings().setAllowFileAccessFromFileURLs(true);
119
154
  _webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
155
+ _webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
120
156
 
121
157
  _webView.setWebViewClient(new WebViewClient());
122
158
 
@@ -131,7 +167,8 @@ public class WebViewDialog extends Dialog {
131
167
  ) {
132
168
  openFileChooser(
133
169
  filePathCallback,
134
- fileChooserParams.getAcceptTypes()[0]
170
+ fileChooserParams.getAcceptTypes()[0],
171
+ fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE
135
172
  );
136
173
  return true;
137
174
  }
@@ -247,14 +284,71 @@ public class WebViewDialog extends Dialog {
247
284
  _webView.evaluateJavascript(script, null);
248
285
  }
249
286
 
287
+ private void injectPreShowScript() {
288
+ // String script =
289
+ // "import('https://unpkg.com/darkreader@4.9.89/darkreader.js').then(() => {DarkReader.enable({ brightness: 100, contrast: 90, sepia: 10 });window.PreLoadScriptInterface.finished()})";
290
+
291
+ if (preShowSemaphore != null) {
292
+ return;
293
+ }
294
+
295
+ String script =
296
+ "async function preShowFunction() {\n" +
297
+ _options.getPreShowScript() +
298
+ '\n' +
299
+ "};\n" +
300
+ "preShowFunction().then(() => window.PreShowScriptInterface.success()).catch(err => { console.error('Preshow error', err); window.PreShowScriptInterface.error(JSON.stringify(err, Object.getOwnPropertyNames(err))) })";
301
+
302
+ Log.i(
303
+ "InjectPreShowScript",
304
+ String.format("PreShowScript script:\n%s", script)
305
+ );
306
+
307
+ preShowSemaphore = new Semaphore(0);
308
+ activity.runOnUiThread(
309
+ new Runnable() {
310
+ @Override
311
+ public void run() {
312
+ _webView.evaluateJavascript(script, null);
313
+ }
314
+ }
315
+ );
316
+
317
+ try {
318
+ if (!preShowSemaphore.tryAcquire(10, TimeUnit.SECONDS)) {
319
+ Log.e(
320
+ "InjectPreShowScript",
321
+ "PreShowScript running for over 10 seconds. The plugin will not wait any longer!"
322
+ );
323
+ return;
324
+ }
325
+ if (preshowError != null && !preshowError.isEmpty()) {
326
+ Log.e(
327
+ "InjectPreShowScript",
328
+ "Error within the user-provided preShowFunction: " + preshowError
329
+ );
330
+ }
331
+ } catch (InterruptedException e) {
332
+ Log.e(
333
+ "InjectPreShowScript",
334
+ "Error when calling InjectPreShowScript: " + e.getMessage()
335
+ );
336
+ } finally {
337
+ preShowSemaphore = null;
338
+ preshowError = null;
339
+ }
340
+ }
341
+
250
342
  private void openFileChooser(
251
343
  ValueCallback<Uri[]> filePathCallback,
252
- String acceptType
344
+ String acceptType,
345
+ boolean isMultiple
253
346
  ) {
254
347
  mFilePathCallback = filePathCallback;
255
348
  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
256
349
  intent.addCategory(Intent.CATEGORY_OPENABLE);
257
350
  intent.setType(acceptType); // Default to */*
351
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultiple);
258
352
  activity.startActivityForResult(
259
353
  Intent.createChooser(intent, "Select File"),
260
354
  FILE_CHOOSER_REQUEST_CODE
@@ -545,9 +639,43 @@ public class WebViewDialog extends Dialog {
545
639
  isInitialized = true;
546
640
  _webView.clearHistory();
547
641
  if (_options.isPresentAfterPageLoad()) {
548
- show();
549
- _options.getPluginCall().resolve();
642
+ boolean usePreShowScript =
643
+ _options.getPreShowScript() != null &&
644
+ !_options.getPreShowScript().isEmpty();
645
+ if (!usePreShowScript) {
646
+ show();
647
+ _options.getPluginCall().resolve();
648
+ } else {
649
+ executorService.execute(
650
+ new Runnable() {
651
+ @Override
652
+ public void run() {
653
+ if (
654
+ _options.getPreShowScript() != null &&
655
+ !_options.getPreShowScript().isEmpty()
656
+ ) {
657
+ injectPreShowScript();
658
+ }
659
+
660
+ activity.runOnUiThread(
661
+ new Runnable() {
662
+ @Override
663
+ public void run() {
664
+ show();
665
+ _options.getPluginCall().resolve();
666
+ }
667
+ }
668
+ );
669
+ }
670
+ }
671
+ );
672
+ }
550
673
  }
674
+ } else if (
675
+ _options.getPreShowScript() != null &&
676
+ !_options.getPreShowScript().isEmpty()
677
+ ) {
678
+ injectPreShowScript();
551
679
  }
552
680
 
553
681
  ImageButton backButton = _toolbar.findViewById(R.id.backButton);