@capgo/inappbrowser 8.1.26 → 8.3.0-alpha.0
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 +142 -32
- package/android/src/main/assets/proxy-bridge.js +197 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +95 -26
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +5 -7
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/ProxyBridge.java +60 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +2 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +262 -165
- package/dist/docs.json +258 -3
- package/dist/esm/definitions.d.ts +120 -3
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +20 -2
- package/dist/esm/index.js +79 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +1 -0
- package/dist/esm/web.js +4 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +83 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +83 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +64 -1
- package/ios/Sources/InAppBrowserPlugin/ProxySchemeHandler.swift +257 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebView+SchemeHandling.swift +53 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +18 -1
- package/package.json +4 -2
|
@@ -6,6 +6,11 @@ import android.content.ComponentName;
|
|
|
6
6
|
import android.content.Intent;
|
|
7
7
|
import android.content.pm.PackageManager;
|
|
8
8
|
import android.content.pm.ResolveInfo;
|
|
9
|
+
import android.graphics.Bitmap;
|
|
10
|
+
import android.graphics.BitmapFactory;
|
|
11
|
+
import android.graphics.Canvas;
|
|
12
|
+
import android.graphics.Color;
|
|
13
|
+
import android.graphics.drawable.Drawable;
|
|
9
14
|
import android.net.Uri;
|
|
10
15
|
import android.os.Bundle;
|
|
11
16
|
import android.text.TextUtils;
|
|
@@ -16,6 +21,8 @@ import androidx.activity.result.ActivityResult;
|
|
|
16
21
|
import androidx.activity.result.ActivityResultLauncher;
|
|
17
22
|
import androidx.activity.result.contract.ActivityResultContracts;
|
|
18
23
|
import androidx.annotation.NonNull;
|
|
24
|
+
import androidx.appcompat.content.res.AppCompatResources;
|
|
25
|
+
import androidx.browser.customtabs.CustomTabColorSchemeParams;
|
|
19
26
|
import androidx.browser.customtabs.CustomTabsCallback;
|
|
20
27
|
import androidx.browser.customtabs.CustomTabsClient;
|
|
21
28
|
import androidx.browser.customtabs.CustomTabsIntent;
|
|
@@ -39,8 +46,6 @@ import java.util.Iterator;
|
|
|
39
46
|
import java.util.List;
|
|
40
47
|
import java.util.Map;
|
|
41
48
|
import java.util.UUID;
|
|
42
|
-
import java.util.regex.Pattern;
|
|
43
|
-
import java.util.regex.PatternSyntaxException;
|
|
44
49
|
import org.json.JSONException;
|
|
45
50
|
import org.json.JSONObject;
|
|
46
51
|
|
|
@@ -55,7 +60,7 @@ import org.json.JSONObject;
|
|
|
55
60
|
)
|
|
56
61
|
public class InAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
|
|
57
62
|
|
|
58
|
-
private final String pluginVersion = "8.
|
|
63
|
+
private final String pluginVersion = "8.3.0-alpha.0";
|
|
59
64
|
|
|
60
65
|
public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
|
|
61
66
|
private CustomTabsClient customTabsClient;
|
|
@@ -337,7 +342,66 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
|
|
|
337
342
|
}
|
|
338
343
|
currentUrl = url;
|
|
339
344
|
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getCustomTabsSession());
|
|
345
|
+
|
|
346
|
+
// --- Chrome Custom Tab UI customization ---
|
|
347
|
+
|
|
348
|
+
// Toolbar color (applied to both light and dark color schemes)
|
|
349
|
+
String toolbarColor = call.getString("toolbarColor");
|
|
350
|
+
if (toolbarColor != null) {
|
|
351
|
+
try {
|
|
352
|
+
int colorInt = Color.parseColor(toolbarColor);
|
|
353
|
+
CustomTabColorSchemeParams colorParams = new CustomTabColorSchemeParams.Builder()
|
|
354
|
+
.setToolbarColor(colorInt)
|
|
355
|
+
.setNavigationBarColor(colorInt)
|
|
356
|
+
.build();
|
|
357
|
+
builder.setDefaultColorSchemeParams(colorParams);
|
|
358
|
+
builder.setColorSchemeParams(CustomTabsIntent.COLOR_SCHEME_DARK, colorParams);
|
|
359
|
+
} catch (IllegalArgumentException e) {
|
|
360
|
+
Log.w(getLogTag(), "Invalid toolbarColor value: " + toolbarColor, e);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Auto-hide URL bar on scroll
|
|
365
|
+
if (call.getBoolean("urlBarHidingEnabled", false)) {
|
|
366
|
+
builder.setUrlBarHidingEnabled(true);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Show page <title> instead of URL
|
|
370
|
+
if (call.getBoolean("showTitle", false)) {
|
|
371
|
+
builder.setShowTitle(true);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Replace X close icon with a back arrow
|
|
375
|
+
if (call.getBoolean("showArrow", false)) {
|
|
376
|
+
Drawable arrowDrawable = AppCompatResources.getDrawable(getContext(), R.drawable.arrow_back_enabled);
|
|
377
|
+
if (arrowDrawable != null) {
|
|
378
|
+
Bitmap backArrow = Bitmap.createBitmap(
|
|
379
|
+
arrowDrawable.getIntrinsicWidth(),
|
|
380
|
+
arrowDrawable.getIntrinsicHeight(),
|
|
381
|
+
Bitmap.Config.ARGB_8888
|
|
382
|
+
);
|
|
383
|
+
Canvas canvas = new Canvas(backArrow);
|
|
384
|
+
arrowDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
|
385
|
+
arrowDrawable.draw(canvas);
|
|
386
|
+
builder.setCloseButtonIcon(backArrow);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Remove share action from overflow menu
|
|
391
|
+
if (call.getBoolean("disableShare", false)) {
|
|
392
|
+
builder.setShareState(CustomTabsIntent.SHARE_STATE_OFF);
|
|
393
|
+
}
|
|
394
|
+
|
|
340
395
|
CustomTabsIntent tabsIntent = builder.build();
|
|
396
|
+
|
|
397
|
+
// Undocumented Chromium flags — these may stop working on future Chrome updates
|
|
398
|
+
if (call.getBoolean("disableBookmark", false)) {
|
|
399
|
+
tabsIntent.intent.putExtra("org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_STAR_BUTTON", true);
|
|
400
|
+
}
|
|
401
|
+
if (call.getBoolean("disableDownload", false)) {
|
|
402
|
+
tabsIntent.intent.putExtra("org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_DOWNLOAD_BUTTON", true);
|
|
403
|
+
}
|
|
404
|
+
|
|
341
405
|
tabsIntent.intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(Intent.URI_ANDROID_APP_SCHEME + "//" + getContext().getPackageName()));
|
|
342
406
|
tabsIntent.intent.putExtra(android.provider.Browser.EXTRA_HEADERS, this.getHeaders(call));
|
|
343
407
|
|
|
@@ -511,14 +575,7 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
|
|
|
511
575
|
options.setTextZoom(textZoom);
|
|
512
576
|
}
|
|
513
577
|
|
|
514
|
-
|
|
515
|
-
if (proxyRequestsStr != null) {
|
|
516
|
-
try {
|
|
517
|
-
options.setProxyRequestsPattern(Pattern.compile(proxyRequestsStr));
|
|
518
|
-
} catch (PatternSyntaxException e) {
|
|
519
|
-
Log.e("WebViewDialog", String.format("Pattern '%s' is not a valid pattern", proxyRequestsStr));
|
|
520
|
-
}
|
|
521
|
-
}
|
|
578
|
+
options.setProxyRequests(Boolean.TRUE.equals(call.getBoolean("proxyRequests", false)));
|
|
522
579
|
|
|
523
580
|
try {
|
|
524
581
|
// Try to set buttonNearDone if present, with better error handling
|
|
@@ -667,6 +724,22 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
|
|
|
667
724
|
notifyListeners("confirmBtnClicked", new JSObject().put("id", webViewId).put("url", url));
|
|
668
725
|
}
|
|
669
726
|
|
|
727
|
+
@Override
|
|
728
|
+
public void proxyRequestEvent(String requestId, String url, String method, String headersJson, String body, String wvId) {
|
|
729
|
+
JSObject data = new JSObject();
|
|
730
|
+
data.put("requestId", requestId);
|
|
731
|
+
data.put("url", url);
|
|
732
|
+
data.put("method", method);
|
|
733
|
+
try {
|
|
734
|
+
data.put("headers", new JSObject(headersJson));
|
|
735
|
+
} catch (Exception e) {
|
|
736
|
+
data.put("headers", new JSObject());
|
|
737
|
+
}
|
|
738
|
+
data.put("body", body);
|
|
739
|
+
data.put("webviewId", wvId);
|
|
740
|
+
notifyListeners("proxyRequest", data);
|
|
741
|
+
}
|
|
742
|
+
|
|
670
743
|
@Override
|
|
671
744
|
public void javascriptCallback(String message) {
|
|
672
745
|
// Handle the message received from JavaScript
|
|
@@ -1004,24 +1077,20 @@ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.Permissi
|
|
|
1004
1077
|
}
|
|
1005
1078
|
|
|
1006
1079
|
@PluginMethod
|
|
1007
|
-
public void
|
|
1080
|
+
public void handleProxyRequest(PluginCall call) {
|
|
1081
|
+
String requestId = call.getString("requestId");
|
|
1082
|
+
if (requestId == null) {
|
|
1083
|
+
call.reject("requestId is required");
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1008
1086
|
String webviewId = call.getString("webviewId");
|
|
1009
1087
|
WebViewDialog webViewDialog = webviewId != null ? webViewDialogs.get(webviewId) : resolveDialog(null);
|
|
1010
|
-
if (webViewDialog
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
if (id == null) {
|
|
1014
|
-
Log.e("InAppBrowserProxy", "CRITICAL ERROR, proxy id = null");
|
|
1015
|
-
return;
|
|
1016
|
-
}
|
|
1017
|
-
if (Boolean.FALSE.equals(ok)) {
|
|
1018
|
-
String result = call.getString("result", "");
|
|
1019
|
-
webViewDialog.handleProxyResultError(result, id);
|
|
1020
|
-
} else {
|
|
1021
|
-
JSONObject object = call.getObject("result");
|
|
1022
|
-
webViewDialog.handleProxyResultOk(object, id);
|
|
1023
|
-
}
|
|
1088
|
+
if (webViewDialog == null) {
|
|
1089
|
+
call.reject("Target WebView not found for proxy request");
|
|
1090
|
+
return;
|
|
1024
1091
|
}
|
|
1092
|
+
JSObject response = call.getObject("response");
|
|
1093
|
+
webViewDialog.handleProxyResponse(requestId, response);
|
|
1025
1094
|
call.resolve();
|
|
1026
1095
|
}
|
|
1027
1096
|
|
|
@@ -9,8 +9,6 @@ import java.io.InputStream;
|
|
|
9
9
|
import java.util.ArrayList;
|
|
10
10
|
import java.util.List;
|
|
11
11
|
import java.util.Objects;
|
|
12
|
-
import java.util.Objects;
|
|
13
|
-
import java.util.regex.Pattern;
|
|
14
12
|
|
|
15
13
|
public class Options {
|
|
16
14
|
|
|
@@ -170,7 +168,7 @@ public class Options {
|
|
|
170
168
|
private boolean ignoreUntrustedSSLError;
|
|
171
169
|
private String preShowScript;
|
|
172
170
|
private String toolbarTextColor;
|
|
173
|
-
private
|
|
171
|
+
private boolean proxyRequests = false;
|
|
174
172
|
private boolean materialPicker = false;
|
|
175
173
|
private int textZoom = 100; // Default text zoom is 100%
|
|
176
174
|
private boolean preventDeeplink = false;
|
|
@@ -262,12 +260,12 @@ public class Options {
|
|
|
262
260
|
this.useTopInset = useTopInset;
|
|
263
261
|
}
|
|
264
262
|
|
|
265
|
-
public
|
|
266
|
-
return
|
|
263
|
+
public boolean getProxyRequests() {
|
|
264
|
+
return proxyRequests;
|
|
267
265
|
}
|
|
268
266
|
|
|
269
|
-
public void
|
|
270
|
-
this.
|
|
267
|
+
public void setProxyRequests(boolean proxyRequests) {
|
|
268
|
+
this.proxyRequests = proxyRequests;
|
|
271
269
|
}
|
|
272
270
|
|
|
273
271
|
public PluginCall getPluginCall() {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package ee.forgr.capacitor_inappbrowser;
|
|
2
|
+
|
|
3
|
+
import android.webkit.JavascriptInterface;
|
|
4
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
5
|
+
|
|
6
|
+
public class ProxyBridge {
|
|
7
|
+
|
|
8
|
+
private static final int MAX_STORED_REQUESTS = 256;
|
|
9
|
+
|
|
10
|
+
public static class StoredRequest {
|
|
11
|
+
|
|
12
|
+
public final String method;
|
|
13
|
+
public final String headersJson;
|
|
14
|
+
public final String base64Body;
|
|
15
|
+
|
|
16
|
+
public StoredRequest(String method, String headersJson, String base64Body) {
|
|
17
|
+
this.method = method != null ? method : "";
|
|
18
|
+
this.headersJson = headersJson != null ? headersJson : "{}";
|
|
19
|
+
this.base64Body = base64Body != null ? base64Body : "";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private final ConcurrentHashMap<String, StoredRequest> storedRequests = new ConcurrentHashMap<>();
|
|
24
|
+
private final String accessToken;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param accessToken Random token generated per webview instance.
|
|
28
|
+
* The injected proxy-bridge script receives this token and must
|
|
29
|
+
* pass it on every storeRequest call. Page JS that doesn't know
|
|
30
|
+
* the token cannot abuse the interface.
|
|
31
|
+
*/
|
|
32
|
+
public ProxyBridge(String accessToken) {
|
|
33
|
+
this.accessToken = accessToken;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@JavascriptInterface
|
|
37
|
+
public void storeRequest(String token, String requestId, String method, String headersJson, String base64Body) {
|
|
38
|
+
if (token == null || !token.equals(accessToken)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (requestId == null || requestId.isEmpty()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (storedRequests.size() >= MAX_STORED_REQUESTS) {
|
|
45
|
+
// Remove an arbitrary entry to prevent unbounded growth
|
|
46
|
+
var it = storedRequests.keys().asIterator();
|
|
47
|
+
if (it.hasNext()) {
|
|
48
|
+
storedRequests.remove(it.next());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
storedRequests.put(requestId, new StoredRequest(method, headersJson, base64Body));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public StoredRequest getAndRemove(String requestId) {
|
|
55
|
+
if (requestId == null) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return storedRequests.remove(requestId);
|
|
59
|
+
}
|
|
60
|
+
}
|