@capgo/capacitor-patch 8.1.0 → 8.2.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 +13 -6
- package/package.json +1 -1
- package/patches/catalog.json +657 -9
- package/patches/upstream-pr-6991-android-native-bridge.patch +15 -0
- package/patches/upstream-pr-6991-ios-native-bridge.patch +15 -0
- package/patches/upstream-pr-7301-core.patch +38 -0
- package/patches/upstream-pr-7419-ios.patch +13 -0
- package/patches/upstream-pr-7420-ios.patch +13 -0
- package/patches/upstream-pr-7446-android.patch +14 -0
- package/patches/upstream-pr-7490-android.patch +13 -0
- package/patches/upstream-pr-7490-ios.patch +13 -0
- package/patches/upstream-pr-7535-android.patch +13 -0
- package/patches/upstream-pr-7599-ios.patch +86 -0
- package/patches/upstream-pr-7732-android-native-bridge.patch +12 -0
- package/patches/upstream-pr-7732-ios-native-bridge.patch +12 -0
- package/patches/upstream-pr-7781-android.patch +24 -0
- package/patches/upstream-pr-7803-android.patch +13 -0
- package/patches/upstream-pr-7831-ios.patch +13 -0
- package/patches/upstream-pr-7987-android.patch +42 -0
- package/patches/upstream-pr-8087-android.patch +64 -0
- package/patches/upstream-pr-8188-cli.patch +18 -0
- package/patches/upstream-pr-8190-android.patch +13 -0
- package/patches/upstream-pr-8249-ios.patch +32 -0
- package/patches/upstream-pr-8252-cli.patch +31 -0
- package/patches/upstream-pr-8271-core.patch +30 -0
- package/patches/upstream-pr-8275-android.patch +158 -0
- package/patches/upstream-pr-8304-ios.patch +36 -0
- package/patches/upstream-pr-8418-android.patch +82 -0
- package/patches/upstream-pr-8424-android.patch +55 -0
- package/patches/upstream-pr-8429-android.patch +19 -0
- package/patches/upstream-pr-8454-android.patch +207 -0
- package/patches/upstream-pr-8458-cli.patch +14 -0
- package/scripts/capacitor-patch/runner.mjs +38 -4
- package/patches/capacitor-cli-spm-ios-minor-platform.patch +0 -40
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
diff --git a/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
|
|
2
|
+
index 6ca1c8a8..6b9f603d 100644
|
|
3
|
+
--- a/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
|
|
4
|
+
+++ b/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
|
|
5
|
+
@@ -46,6 +46,17 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
6
|
+
void onActivityResult(ActivityResult result);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
+ // Static variables to store pending file chooser state to survive activity recreation
|
|
10
|
+
+ private static ValueCallback<Uri[]> pendingFilePathCallback;
|
|
11
|
+
+ private static Uri pendingImageFileUri;
|
|
12
|
+
+ private static FileChooserType pendingFileChooserType;
|
|
13
|
+
+
|
|
14
|
+
+ private enum FileChooserType {
|
|
15
|
+
+ IMAGE_CAPTURE,
|
|
16
|
+
+ VIDEO_CAPTURE,
|
|
17
|
+
+ FILE_PICKER
|
|
18
|
+
+ }
|
|
19
|
+
+
|
|
20
|
+
private ActivityResultLauncher permissionLauncher;
|
|
21
|
+
private ActivityResultLauncher activityLauncher;
|
|
22
|
+
private PermissionListener permissionListener;
|
|
23
|
+
@@ -70,10 +81,70 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
24
|
+
activityLauncher = bridge.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> {
|
|
25
|
+
if (activityListener != null) {
|
|
26
|
+
activityListener.onActivityResult(result);
|
|
27
|
+
+ } else if (pendingFilePathCallback != null) {
|
|
28
|
+
+ // Handle case where activity was recreated and instance callback is null
|
|
29
|
+
+ // Use the static callback instead
|
|
30
|
+
+ handlePendingFileChooserResult(result);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
+ /**
|
|
36
|
+
+ * Handle file chooser result when the activity was recreated and instance callbacks were lost.
|
|
37
|
+
+ * This uses the static pending callback to deliver the result.
|
|
38
|
+
+ */
|
|
39
|
+
+ private void handlePendingFileChooserResult(ActivityResult result) {
|
|
40
|
+
+ if (pendingFilePathCallback == null) {
|
|
41
|
+
+ return;
|
|
42
|
+
+ }
|
|
43
|
+
+
|
|
44
|
+
+ try {
|
|
45
|
+
+ Uri[] uriResult = null;
|
|
46
|
+
+ if (result.getResultCode() == Activity.RESULT_OK) {
|
|
47
|
+
+ switch (pendingFileChooserType) {
|
|
48
|
+
+ case IMAGE_CAPTURE:
|
|
49
|
+
+ if (pendingImageFileUri != null) {
|
|
50
|
+
+ uriResult = new Uri[] { pendingImageFileUri };
|
|
51
|
+
+ }
|
|
52
|
+
+ break;
|
|
53
|
+
+ case VIDEO_CAPTURE:
|
|
54
|
+
+ Intent videoData = result.getData();
|
|
55
|
+
+ if (videoData != null && videoData.getData() != null) {
|
|
56
|
+
+ uriResult = new Uri[] { videoData.getData() };
|
|
57
|
+
+ }
|
|
58
|
+
+ break;
|
|
59
|
+
+ case FILE_PICKER:
|
|
60
|
+
+ Intent fileData = result.getData();
|
|
61
|
+
+ if (fileData != null) {
|
|
62
|
+
+ if (fileData.getClipData() != null) {
|
|
63
|
+
+ final int numFiles = fileData.getClipData().getItemCount();
|
|
64
|
+
+ uriResult = new Uri[numFiles];
|
|
65
|
+
+ for (int i = 0; i < numFiles; i++) {
|
|
66
|
+
+ uriResult[i] = fileData.getClipData().getItemAt(i).getUri();
|
|
67
|
+
+ }
|
|
68
|
+
+ } else {
|
|
69
|
+
+ uriResult = WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), fileData);
|
|
70
|
+
+ }
|
|
71
|
+
+ }
|
|
72
|
+
+ break;
|
|
73
|
+
+ }
|
|
74
|
+
+ }
|
|
75
|
+
+ pendingFilePathCallback.onReceiveValue(uriResult);
|
|
76
|
+
+ } finally {
|
|
77
|
+
+ // Clear the static state after handling
|
|
78
|
+
+ clearPendingFileChooserState();
|
|
79
|
+
+ }
|
|
80
|
+
+ }
|
|
81
|
+
+
|
|
82
|
+
+ /**
|
|
83
|
+
+ * Clear the static pending file chooser state.
|
|
84
|
+
+ */
|
|
85
|
+
+ private static void clearPendingFileChooserState() {
|
|
86
|
+
+ pendingFilePathCallback = null;
|
|
87
|
+
+ pendingImageFileUri = null;
|
|
88
|
+
+ pendingFileChooserType = null;
|
|
89
|
+
+ }
|
|
90
|
+
+
|
|
91
|
+
/**
|
|
92
|
+
* Render web content in `view`.
|
|
93
|
+
*
|
|
94
|
+
@@ -340,12 +411,19 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
|
|
98
|
+
+
|
|
99
|
+
+ // Store in static variables to survive activity recreation
|
|
100
|
+
+ pendingFilePathCallback = filePathCallback;
|
|
101
|
+
+ pendingImageFileUri = imageFileUri;
|
|
102
|
+
+ pendingFileChooserType = FileChooserType.IMAGE_CAPTURE;
|
|
103
|
+
+
|
|
104
|
+
activityListener = (activityResult) -> {
|
|
105
|
+
Uri[] result = null;
|
|
106
|
+
if (activityResult.getResultCode() == Activity.RESULT_OK) {
|
|
107
|
+
result = new Uri[] { imageFileUri };
|
|
108
|
+
}
|
|
109
|
+
filePathCallback.onReceiveValue(result);
|
|
110
|
+
+ clearPendingFileChooserState();
|
|
111
|
+
};
|
|
112
|
+
activityLauncher.launch(takePictureIntent);
|
|
113
|
+
|
|
114
|
+
@@ -359,12 +437,18 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
+ // Store in static variables to survive activity recreation
|
|
119
|
+
+ pendingFilePathCallback = filePathCallback;
|
|
120
|
+
+ pendingImageFileUri = null;
|
|
121
|
+
+ pendingFileChooserType = FileChooserType.VIDEO_CAPTURE;
|
|
122
|
+
+
|
|
123
|
+
activityListener = (activityResult) -> {
|
|
124
|
+
Uri[] result = null;
|
|
125
|
+
if (activityResult.getResultCode() == Activity.RESULT_OK) {
|
|
126
|
+
result = new Uri[] { activityResult.getData().getData() };
|
|
127
|
+
}
|
|
128
|
+
filePathCallback.onReceiveValue(result);
|
|
129
|
+
+ clearPendingFileChooserState();
|
|
130
|
+
};
|
|
131
|
+
activityLauncher.launch(takeVideoIntent);
|
|
132
|
+
|
|
133
|
+
@@ -383,6 +467,12 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
134
|
+
intent.setType(validTypes[0]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
+
|
|
138
|
+
+ // Store in static variables to survive activity recreation
|
|
139
|
+
+ pendingFilePathCallback = filePathCallback;
|
|
140
|
+
+ pendingImageFileUri = null;
|
|
141
|
+
+ pendingFileChooserType = FileChooserType.FILE_PICKER;
|
|
142
|
+
+
|
|
143
|
+
try {
|
|
144
|
+
activityListener = (activityResult) -> {
|
|
145
|
+
Uri[] result;
|
|
146
|
+
@@ -397,10 +487,12 @@ public class BridgeWebChromeClient extends WebChromeClient {
|
|
147
|
+
result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent);
|
|
148
|
+
}
|
|
149
|
+
filePathCallback.onReceiveValue(result);
|
|
150
|
+
+ clearPendingFileChooserState();
|
|
151
|
+
};
|
|
152
|
+
activityLauncher.launch(intent);
|
|
153
|
+
} catch (ActivityNotFoundException e) {
|
|
154
|
+
filePathCallback.onReceiveValue(null);
|
|
155
|
+
+ clearPendingFileChooserState();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
diff --git a/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift b/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift
|
|
2
|
+
index 651c1b76..2230b32d 100644
|
|
3
|
+
--- a/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift
|
|
4
|
+
+++ b/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift
|
|
5
|
+
@@ -224,11 +224,26 @@ open class HttpRequestHandler {
|
|
6
|
+
call.reject(error.localizedDescription, (error as NSError).domain, error, nil)
|
|
7
|
+
return
|
|
8
|
+
}
|
|
9
|
+
-
|
|
10
|
+
- setCookiesFromResponse(response as! HTTPURLResponse, config)
|
|
11
|
+
-
|
|
12
|
+
- let type = ResponseType(rawValue: responseType) ?? .default
|
|
13
|
+
- call.resolve(self.buildResponse(data, response as! HTTPURLResponse, responseType: type))
|
|
14
|
+
+
|
|
15
|
+
+ if let response = response as? HTTPURLResponse {
|
|
16
|
+
+ setCookiesFromResponse(response, config)
|
|
17
|
+
+
|
|
18
|
+
+ let type = ResponseType(rawValue: responseType) ?? .default
|
|
19
|
+
+ call.resolve(self.buildResponse(data, response, responseType: type))
|
|
20
|
+
+ } else if let response = response as? NSURLResponse {
|
|
21
|
+
+ // applicable to data: URI requests
|
|
22
|
+
+ var headers = [:] as [String: Any]
|
|
23
|
+
+ headers["Content-Type"] = response.mimeType
|
|
24
|
+
+
|
|
25
|
+
+ var output = [:] as [String: Any]
|
|
26
|
+
+ output["status"] = 200
|
|
27
|
+
+ output["headers"] = headers
|
|
28
|
+
+ output["data"] = String(data: data!, encoding: .utf8)
|
|
29
|
+
+ call.resolve(output)
|
|
30
|
+
+ } else {
|
|
31
|
+
+ call.reject("Unknown response kind")
|
|
32
|
+
+ return
|
|
33
|
+
+ }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
task.resume()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
diff --git a/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
|
|
2
|
+
index a39483de..a952f2ca 100755
|
|
3
|
+
--- a/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
|
|
4
|
+
+++ b/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java
|
|
5
|
+
@@ -348,16 +348,22 @@ public class WebViewLocalServer {
|
|
6
|
+
Map<String, String> tempResponseHeaders = handler.buildDefaultResponseHeaders();
|
|
7
|
+
int statusCode = 206;
|
|
8
|
+
try {
|
|
9
|
+
- int totalRange = responseStream.available();
|
|
10
|
+
+ int totalSize = responseStream.available();
|
|
11
|
+
String[] parts = rangeString.split("=");
|
|
12
|
+
String[] streamParts = parts[1].split("-");
|
|
13
|
+
- String fromRange = streamParts[0];
|
|
14
|
+
- int range = totalRange - 1;
|
|
15
|
+
- if (streamParts.length > 1) {
|
|
16
|
+
- range = Integer.parseInt(streamParts[1]);
|
|
17
|
+
+ int fromRange = Integer.parseInt(streamParts[0]);
|
|
18
|
+
+ int endRange = totalSize - 1;
|
|
19
|
+
+ if (streamParts.length > 1 && !streamParts[1].isEmpty()) {
|
|
20
|
+
+ endRange = Integer.parseInt(streamParts[1]);
|
|
21
|
+
}
|
|
22
|
+
+
|
|
23
|
+
+ // Truncate the stream at the end of the requested range.
|
|
24
|
+
+ // Somewhere in the request pipeline, the stream gets automatically
|
|
25
|
+
+ // seeked to the correct start position, so we don't need to skip to the fromRange position here.
|
|
26
|
+
+ responseStream = new BoundedInputStream(responseStream, endRange + 1);
|
|
27
|
+
+
|
|
28
|
+
tempResponseHeaders.put("Accept-Ranges", "bytes");
|
|
29
|
+
- tempResponseHeaders.put("Content-Range", "bytes " + fromRange + "-" + range + "/" + totalRange);
|
|
30
|
+
+ tempResponseHeaders.put("Content-Range", "bytes " + fromRange + "-" + endRange + "/" + totalSize);
|
|
31
|
+
} catch (IOException e) {
|
|
32
|
+
statusCode = 404;
|
|
33
|
+
}
|
|
34
|
+
@@ -750,6 +756,48 @@ public class WebViewLocalServer {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
+ /**
|
|
39
|
+
+ * An InputStream wrapper that limits the number of bytes that can be read.
|
|
40
|
+
+ */
|
|
41
|
+
+ static class BoundedInputStream extends InputStream {
|
|
42
|
+
+
|
|
43
|
+
+ private final InputStream in;
|
|
44
|
+
+ private long remaining;
|
|
45
|
+
+
|
|
46
|
+
+ public BoundedInputStream(InputStream in, long limit) {
|
|
47
|
+
+ this.in = in;
|
|
48
|
+
+ this.remaining = limit;
|
|
49
|
+
+ }
|
|
50
|
+
+
|
|
51
|
+
+ @Override
|
|
52
|
+
+ public int available() throws IOException {
|
|
53
|
+
+ int available = in.available();
|
|
54
|
+
+ return (int) Math.min(available, remaining);
|
|
55
|
+
+ }
|
|
56
|
+
+
|
|
57
|
+
+ @Override
|
|
58
|
+
+ public int read() throws IOException {
|
|
59
|
+
+ if (remaining <= 0) return -1;
|
|
60
|
+
+ int result = in.read();
|
|
61
|
+
+ if (result != -1) remaining--;
|
|
62
|
+
+ return result;
|
|
63
|
+
+ }
|
|
64
|
+
+
|
|
65
|
+
+ @Override
|
|
66
|
+
+ public int read(byte[] b, int off, int len) throws IOException {
|
|
67
|
+
+ if (remaining <= 0) return -1;
|
|
68
|
+
+ int toRead = (int) Math.min(len, remaining);
|
|
69
|
+
+ int result = in.read(b, off, toRead);
|
|
70
|
+
+ if (result > 0) remaining -= result;
|
|
71
|
+
+ return result;
|
|
72
|
+
+ }
|
|
73
|
+
+
|
|
74
|
+
+ @Override
|
|
75
|
+
+ public void close() throws IOException {
|
|
76
|
+
+ in.close();
|
|
77
|
+
+ }
|
|
78
|
+
+ }
|
|
79
|
+
+
|
|
80
|
+
// For L and above.
|
|
81
|
+
private static class LollipopLazyInputStream extends LazyInputStream {
|
|
82
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
diff --git a/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
2
|
+
index b335b4b1..76e74207 100644
|
|
3
|
+
--- a/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
4
|
+
+++ b/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
5
|
+
@@ -164,13 +164,18 @@ public class SystemBars extends Plugin {
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
private void initSafeAreaCSSVariables() {
|
|
9
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
|
|
10
|
+
+ WindowInsetsCompat insets;
|
|
11
|
+
+
|
|
12
|
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
13
|
+
View v = (View) this.getBridge().getWebView().getParent();
|
|
14
|
+
- WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
|
|
15
|
+
- if (insets != null) {
|
|
16
|
+
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
17
|
+
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
18
|
+
- }
|
|
19
|
+
+ insets = ViewCompat.getRootWindowInsets(v);
|
|
20
|
+
+ } else {
|
|
21
|
+
+ insets = WindowInsetsCompat.CONSUMED;
|
|
22
|
+
+ }
|
|
23
|
+
+
|
|
24
|
+
+ if (insets != null) {
|
|
25
|
+
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
26
|
+
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@@ -186,10 +191,8 @@ public class SystemBars extends Plugin {
|
|
31
|
+
// We need to correct for a possible shown IME
|
|
32
|
+
v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
|
|
33
|
+
|
|
34
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
35
|
+
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
36
|
+
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
37
|
+
- }
|
|
38
|
+
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
39
|
+
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
40
|
+
|
|
41
|
+
return new WindowInsetsCompat.Builder(insets)
|
|
42
|
+
.setInsets(
|
|
43
|
+
@@ -221,10 +224,8 @@ public class SystemBars extends Plugin {
|
|
44
|
+
.setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
|
|
45
|
+
.build();
|
|
46
|
+
|
|
47
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
48
|
+
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
|
|
49
|
+
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
50
|
+
- }
|
|
51
|
+
+ Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
|
|
52
|
+
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
53
|
+
|
|
54
|
+
return newInsets;
|
|
55
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
diff --git a/capacitor/src/main/java/com/getcapacitor/Bridge.java b/capacitor/src/main/java/com/getcapacitor/Bridge.java
|
|
2
|
+
index d4995fbb..71b658f5 100644
|
|
3
|
+
--- a/capacitor/src/main/java/com/getcapacitor/Bridge.java
|
|
4
|
+
+++ b/capacitor/src/main/java/com/getcapacitor/Bridge.java
|
|
5
|
+
@@ -265,8 +265,13 @@ public class Bridge {
|
|
6
|
+
JSInjector injector = getJSInjector();
|
|
7
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
|
8
|
+
String allowedOrigin = Uri.parse(appUrl).buildUpon().path(null).fragment(null).clearQuery().build().toString();
|
|
9
|
+
+ final String finalAllowedOrigin = allowedOrigin;
|
|
10
|
+
+ Set<String> allowedOrigins = new HashSet<String>() {{
|
|
11
|
+
+ add(finalAllowedOrigin);
|
|
12
|
+
+ addAll(allowedOriginRules);
|
|
13
|
+
+ }};
|
|
14
|
+
try {
|
|
15
|
+
- WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), Collections.singleton(allowedOrigin));
|
|
16
|
+
+ WebViewCompat.addDocumentStartJavaScript(webView, injector.getScriptString(), allowedOrigins);
|
|
17
|
+
injector = null;
|
|
18
|
+
} catch (IllegalArgumentException ex) {
|
|
19
|
+
Logger.warn("Invalid url, using fallback");
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
diff --git a/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
2
|
+
index b335b4b1..c77efda7 100644
|
|
3
|
+
--- a/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
4
|
+
+++ b/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java
|
|
5
|
+
@@ -59,6 +59,8 @@ public class SystemBars extends Plugin {
|
|
6
|
+
private String currentStatusBarStyle = STYLE_DEFAULT;
|
|
7
|
+
private String currentGestureBarStyle = STYLE_DEFAULT;
|
|
8
|
+
|
|
9
|
+
+ private boolean navBarVisible = true;
|
|
10
|
+
+
|
|
11
|
+
@Override
|
|
12
|
+
public void load() {
|
|
13
|
+
getBridge().getWebView().addJavascriptInterface(this, "CapacitorSystemBarsAndroidInterface");
|
|
14
|
+
@@ -76,7 +78,15 @@ public class SystemBars extends Plugin {
|
|
15
|
+
@Override
|
|
16
|
+
public void onPageCommitVisible(WebView view, String url) {
|
|
17
|
+
super.onPageCommitVisible(view, url);
|
|
18
|
+
- getBridge().getWebView().requestApplyInsets();
|
|
19
|
+
+ View parentView = (View) getBridge().getWebView().getParent();
|
|
20
|
+
+ ViewCompat.requestApplyInsets(parentView);
|
|
21
|
+
+ if (insetHandlingEnabled) {
|
|
22
|
+
+ WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(parentView);
|
|
23
|
+
+ if (rootInsets != null) {
|
|
24
|
+
+ Insets safeArea = calcSafeAreaInsets(rootInsets);
|
|
25
|
+
+ injectSafeAreaCSS(safeArea.top, safeArea.right, safeArea.bottom, safeArea.left);
|
|
26
|
+
+ }
|
|
27
|
+
+ }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
@@ -103,8 +113,17 @@ public class SystemBars extends Plugin {
|
|
32
|
+
initSafeAreaCSSVariables();
|
|
33
|
+
|
|
34
|
+
getBridge().executeOnMainThread(() -> {
|
|
35
|
+
+ Window window = getActivity().getWindow();
|
|
36
|
+
+ WindowCompat.setDecorFitsSystemWindows(window, false);
|
|
37
|
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
38
|
+
+ window.setNavigationBarColor(android.graphics.Color.TRANSPARENT);
|
|
39
|
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
40
|
+
+ window.setNavigationBarContrastEnforced(false);
|
|
41
|
+
+ }
|
|
42
|
+
+ }
|
|
43
|
+
setStyle(style, "");
|
|
44
|
+
setHidden(hidden, "");
|
|
45
|
+
+ ViewCompat.requestApplyInsets((View) getBridge().getWebView().getParent());
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@@ -144,27 +163,64 @@ public class SystemBars extends Plugin {
|
|
50
|
+
call.resolve();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
+ @Override
|
|
54
|
+
+ protected void handleOnResume() {
|
|
55
|
+
+ super.handleOnResume();
|
|
56
|
+
+ getBridge().executeOnMainThread(() -> {
|
|
57
|
+
+ Window window = getActivity().getWindow();
|
|
58
|
+
+ WindowCompat.setDecorFitsSystemWindows(window, false);
|
|
59
|
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
60
|
+
+ window.setNavigationBarColor(android.graphics.Color.TRANSPARENT);
|
|
61
|
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
62
|
+
+ window.setNavigationBarContrastEnforced(false);
|
|
63
|
+
+ }
|
|
64
|
+
+ }
|
|
65
|
+
+ setStyle(currentGestureBarStyle, BAR_GESTURE_BAR);
|
|
66
|
+
+ setStyle(currentStatusBarStyle, BAR_STATUS_BAR);
|
|
67
|
+
+ ViewCompat.requestApplyInsets((View) getBridge().getWebView().getParent());
|
|
68
|
+
+ });
|
|
69
|
+
+ }
|
|
70
|
+
+
|
|
71
|
+
@JavascriptInterface
|
|
72
|
+
public void onDOMReady() {
|
|
73
|
+
getActivity().runOnUiThread(() -> {
|
|
74
|
+
this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
|
|
75
|
+
hasViewportCover = res.equals("true");
|
|
76
|
+
-
|
|
77
|
+
- getBridge().getWebView().requestApplyInsets();
|
|
78
|
+
+ ViewCompat.requestApplyInsets((View) getBridge().getWebView().getParent());
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
|
|
84
|
+
Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
|
|
85
|
+
- if (insets.isVisible(WindowInsetsCompat.Type.ime())) {
|
|
86
|
+
+
|
|
87
|
+
+ int bottom = safeArea.bottom;
|
|
88
|
+
+
|
|
89
|
+
+ if (bottom == 0
|
|
90
|
+
+ && Build.VERSION.SDK_INT < Build.VERSION_CODES.R
|
|
91
|
+
+ && safeArea.left == 0 && safeArea.right == 0) { // skip if nav bar is on a side (landscape)
|
|
92
|
+
+ bottom = getNavBarHeightFromResources();
|
|
93
|
+
+ }
|
|
94
|
+
+
|
|
95
|
+
+ boolean imeVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
|
96
|
+
+ ? insets.isVisible(WindowInsetsCompat.Type.ime())
|
|
97
|
+
+ : insets.getInsets(WindowInsetsCompat.Type.ime()).bottom > 0;
|
|
98
|
+
+
|
|
99
|
+
+ if (imeVisible) {
|
|
100
|
+
return Insets.of(safeArea.left, safeArea.top, safeArea.right, 0);
|
|
101
|
+
}
|
|
102
|
+
- return Insets.of(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
|
|
103
|
+
+ return Insets.of(safeArea.left, safeArea.top, safeArea.right, bottom);
|
|
104
|
+
+ }
|
|
105
|
+
+
|
|
106
|
+
+ private int getNavBarHeightFromResources() {
|
|
107
|
+
+ if (!navBarVisible) return 0;
|
|
108
|
+
+ android.content.res.Resources res = getActivity().getResources();
|
|
109
|
+
+ int heightId = res.getIdentifier("navigation_bar_height", "dimen", "android");
|
|
110
|
+
+ return heightId > 0 ? res.getDimensionPixelSize(heightId) : 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private void initSafeAreaCSSVariables() {
|
|
114
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
|
|
115
|
+
+ if (insetHandlingEnabled) {
|
|
116
|
+
View v = (View) this.getBridge().getWebView().getParent();
|
|
117
|
+
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
|
|
118
|
+
if (insets != null) {
|
|
119
|
+
@@ -176,6 +232,10 @@ public class SystemBars extends Plugin {
|
|
120
|
+
|
|
121
|
+
private void initWindowInsetsListener() {
|
|
122
|
+
ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
|
|
123
|
+
+ // getRootWindowInsets() bypasses AppCompat's intermediate view consuming the bottom inset on API < 30
|
|
124
|
+
+ WindowInsetsCompat rawInsets = ViewCompat.getRootWindowInsets(v);
|
|
125
|
+
+ WindowInsetsCompat safeAreaSource = (rawInsets != null) ? rawInsets : insets;
|
|
126
|
+
+
|
|
127
|
+
boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
|
|
128
|
+
|
|
129
|
+
Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
|
|
130
|
+
@@ -186,8 +246,8 @@ public class SystemBars extends Plugin {
|
|
131
|
+
// We need to correct for a possible shown IME
|
|
132
|
+
v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
|
|
133
|
+
|
|
134
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
135
|
+
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
|
|
136
|
+
+ if (hasViewportCover && insetHandlingEnabled) {
|
|
137
|
+
+ Insets safeAreaInsets = calcSafeAreaInsets(safeAreaSource);
|
|
138
|
+
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@@ -204,15 +264,7 @@ public class SystemBars extends Plugin {
|
|
142
|
+
.build();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
146
|
+
- // We need to correct for a possible shown IME
|
|
147
|
+
- v.setPadding(
|
|
148
|
+
- systemBarsInsets.left,
|
|
149
|
+
- systemBarsInsets.top,
|
|
150
|
+
- systemBarsInsets.right,
|
|
151
|
+
- keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom
|
|
152
|
+
- );
|
|
153
|
+
- }
|
|
154
|
+
+ v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
|
|
155
|
+
|
|
156
|
+
// Returning `WindowInsetsCompat.CONSUMED` breaks recalculation of safe area insets
|
|
157
|
+
// So we have to explicitly set insets to `0`
|
|
158
|
+
@@ -221,8 +273,8 @@ public class SystemBars extends Plugin {
|
|
159
|
+
.setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
|
|
160
|
+
.build();
|
|
161
|
+
|
|
162
|
+
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
|
|
163
|
+
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
|
|
164
|
+
+ if (insetHandlingEnabled) {
|
|
165
|
+
+ Insets safeAreaInsets = calcSafeAreaInsets(safeAreaSource);
|
|
166
|
+
injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@@ -263,6 +315,7 @@ public class SystemBars extends Plugin {
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private void setStyle(String style, String bar) {
|
|
173
|
+
+ String requestedStyle = style;
|
|
174
|
+
if (style.equals(STYLE_DEFAULT)) {
|
|
175
|
+
style = getStyleForTheme();
|
|
176
|
+
}
|
|
177
|
+
@@ -270,12 +323,12 @@ public class SystemBars extends Plugin {
|
|
178
|
+
Window window = getActivity().getWindow();
|
|
179
|
+
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView());
|
|
180
|
+
if (bar.isEmpty() || bar.equals(BAR_STATUS_BAR)) {
|
|
181
|
+
- currentStatusBarStyle = style;
|
|
182
|
+
+ currentStatusBarStyle = requestedStyle;
|
|
183
|
+
windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals(STYLE_DARK));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
|
|
187
|
+
- currentGestureBarStyle = style;
|
|
188
|
+
+ currentGestureBarStyle = requestedStyle;
|
|
189
|
+
windowInsetsControllerCompat.setAppearanceLightNavigationBars(!style.equals(STYLE_DARK));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@@ -292,6 +345,7 @@ public class SystemBars extends Plugin {
|
|
193
|
+
}
|
|
194
|
+
if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
|
|
195
|
+
windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.navigationBars());
|
|
196
|
+
+ navBarVisible = false;
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
@@ -301,6 +355,7 @@ public class SystemBars extends Plugin {
|
|
201
|
+
}
|
|
202
|
+
if (bar.isEmpty() || bar.equals(BAR_GESTURE_BAR)) {
|
|
203
|
+
windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars());
|
|
204
|
+
+ navBarVisible = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
diff --git a/dist/ios/build.js b/dist/ios/build.js
|
|
2
|
+
index 249518e..c293d47 100644
|
|
3
|
+
--- a/dist/ios/build.js
|
|
4
|
+
+++ b/dist/ios/build.js
|
|
5
|
+
@@ -44,6 +44,9 @@ async function buildiOS(config, buildOptions) {
|
|
6
|
+
if (buildOptions.xcodeSigningType == 'manual') {
|
|
7
|
+
buildArgs.push(`PROVISIONING_PROFILE_SPECIFIER=${buildOptions.xcodeProvisioningProfile}`);
|
|
8
|
+
}
|
|
9
|
+
+ else {
|
|
10
|
+
+ buildArgs.push('-allowProvisioningUpdates');
|
|
11
|
+
+ }
|
|
12
|
+
await (0, common_1.runTask)('Building xArchive', async () => (0, subprocess_1.runCommand)('xcodebuild', buildArgs, {
|
|
13
|
+
cwd: config.ios.nativeProjectDirAbs,
|
|
14
|
+
}));
|
|
@@ -28,6 +28,18 @@ export async function runCapacitorPatch(options) {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
for (const entry of selected.superseded) {
|
|
32
|
+
results.push({
|
|
33
|
+
id: entry.patch.id,
|
|
34
|
+
title: entry.patch.title,
|
|
35
|
+
phase,
|
|
36
|
+
selectedBy: entry.selectedBy,
|
|
37
|
+
status: 'skipped',
|
|
38
|
+
changedFiles: [],
|
|
39
|
+
reason: `Superseded by ${entry.supersededBy}.`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
for (const entry of selected.patches) {
|
|
32
44
|
results.push(
|
|
33
45
|
await applyCatalogPatch({
|
|
@@ -50,7 +62,7 @@ export async function runCapacitorPatch(options) {
|
|
|
50
62
|
|
|
51
63
|
return {
|
|
52
64
|
phase,
|
|
53
|
-
selectedCount: selected.patches.length + selected.unknownIds.length,
|
|
65
|
+
selectedCount: selected.patches.length + selected.unknownIds.length + selected.superseded.length,
|
|
54
66
|
results,
|
|
55
67
|
};
|
|
56
68
|
}
|
|
@@ -59,7 +71,7 @@ export function selectPatches(catalog, patchConfig, phase) {
|
|
|
59
71
|
const disabled = new Set(patchConfig.disabled);
|
|
60
72
|
const explicit = new Set(patchConfig.patches);
|
|
61
73
|
const catalogById = new Map(catalog.map((patch) => [patch.id, patch]));
|
|
62
|
-
const
|
|
74
|
+
const selectedEntries = [];
|
|
63
75
|
|
|
64
76
|
for (const patch of catalog) {
|
|
65
77
|
if (!patch?.id || patch.phase !== phase || disabled.has(patch.id)) {
|
|
@@ -67,14 +79,36 @@ export function selectPatches(catalog, patchConfig, phase) {
|
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
if (explicit.has(patch.id)) {
|
|
70
|
-
|
|
82
|
+
selectedEntries.push({ patch, selectedBy: 'explicit' });
|
|
71
83
|
} else if (patchConfig.recommended && patch.recommended === true) {
|
|
72
|
-
|
|
84
|
+
selectedEntries.push({ patch, selectedBy: 'recommended' });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const selectedIds = new Set(selectedEntries.map((entry) => entry.patch.id));
|
|
89
|
+
const supersededBy = new Map();
|
|
90
|
+
for (const entry of selectedEntries) {
|
|
91
|
+
for (const supersededId of entry.patch.supersedes ?? []) {
|
|
92
|
+
if (selectedIds.has(supersededId) && !disabled.has(supersededId)) {
|
|
93
|
+
supersededBy.set(supersededId, entry.patch.id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const patches = [];
|
|
99
|
+
const superseded = [];
|
|
100
|
+
for (const entry of selectedEntries) {
|
|
101
|
+
const replacementId = supersededBy.get(entry.patch.id);
|
|
102
|
+
if (replacementId) {
|
|
103
|
+
superseded.push({ ...entry, supersededBy: replacementId });
|
|
104
|
+
} else {
|
|
105
|
+
patches.push(entry);
|
|
73
106
|
}
|
|
74
107
|
}
|
|
75
108
|
|
|
76
109
|
return {
|
|
77
110
|
patches,
|
|
111
|
+
superseded,
|
|
78
112
|
unknownIds: patchConfig.patches.filter((id) => !disabled.has(id) && !catalogById.has(id)),
|
|
79
113
|
};
|
|
80
114
|
}
|