@capgo/inappbrowser 7.2.21 → 7.3.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/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +23 -6
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +12 -6
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +159 -145
- package/ios/Plugin/InAppBrowserPlugin.swift +44 -36
- package/ios/Plugin/WKWebViewController.swift +19 -6
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ import com.getcapacitor.annotation.Permission;
|
|
|
28
28
|
import com.getcapacitor.annotation.PermissionCallback;
|
|
29
29
|
import java.util.ArrayList;
|
|
30
30
|
import java.util.Iterator;
|
|
31
|
+
import java.util.Objects;
|
|
31
32
|
import java.util.regex.Pattern;
|
|
32
33
|
import java.util.regex.PatternSyntaxException;
|
|
33
34
|
import org.json.JSONException;
|
|
@@ -91,7 +92,9 @@ public class InAppBrowserPlugin
|
|
|
91
92
|
currentPermissionRequest.deny();
|
|
92
93
|
currentPermissionRequest = null;
|
|
93
94
|
}
|
|
94
|
-
call
|
|
95
|
+
if (call != null) {
|
|
96
|
+
call.reject("Microphone permission is required");
|
|
97
|
+
}
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
|
|
@@ -155,7 +158,7 @@ public class InAppBrowserPlugin
|
|
|
155
158
|
webViewDialog.mFilePathCallback.onReceiveValue(results);
|
|
156
159
|
webViewDialog.mFilePathCallback = null;
|
|
157
160
|
} catch (Exception e) {
|
|
158
|
-
Log.e("ACTIVITYRESULT", e.getMessage());
|
|
161
|
+
Log.e("ACTIVITYRESULT", Objects.requireNonNull(e.getMessage()));
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
}
|
|
@@ -723,10 +726,8 @@ public class InAppBrowserPlugin
|
|
|
723
726
|
new CustomTabsCallback() {
|
|
724
727
|
@Override
|
|
725
728
|
public void onNavigationEvent(int navigationEvent, Bundle extras) {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
notifyListeners("browserPageLoaded", new JSObject());
|
|
729
|
-
break;
|
|
729
|
+
if (navigationEvent == NAVIGATION_FINISHED) {
|
|
730
|
+
notifyListeners("browserPageLoaded", new JSObject());
|
|
730
731
|
}
|
|
731
732
|
}
|
|
732
733
|
}
|
|
@@ -734,4 +735,20 @@ public class InAppBrowserPlugin
|
|
|
734
735
|
}
|
|
735
736
|
return currentSession;
|
|
736
737
|
}
|
|
738
|
+
|
|
739
|
+
@Override
|
|
740
|
+
protected void handleOnDestroy() {
|
|
741
|
+
if (webViewDialog != null) {
|
|
742
|
+
try {
|
|
743
|
+
webViewDialog.dismiss();
|
|
744
|
+
} catch (Exception e) {
|
|
745
|
+
// Ignore, dialog may already be dismissed
|
|
746
|
+
}
|
|
747
|
+
webViewDialog = null;
|
|
748
|
+
}
|
|
749
|
+
currentPermissionRequest = null;
|
|
750
|
+
customTabsClient = null;
|
|
751
|
+
currentSession = null;
|
|
752
|
+
super.handleOnDestroy();
|
|
753
|
+
}
|
|
737
754
|
}
|
|
@@ -17,10 +17,10 @@ public class Options {
|
|
|
17
17
|
ASSET,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
private AllIconTypes iconType;
|
|
21
|
-
private String icon;
|
|
22
|
-
private int height;
|
|
23
|
-
private int width;
|
|
20
|
+
private final AllIconTypes iconType;
|
|
21
|
+
private final String icon;
|
|
22
|
+
private final int height;
|
|
23
|
+
private final int width;
|
|
24
24
|
|
|
25
25
|
private ButtonNearDone(
|
|
26
26
|
AllIconTypes iconType,
|
|
@@ -80,14 +80,20 @@ public class Options {
|
|
|
80
80
|
try {
|
|
81
81
|
fileInputString.close();
|
|
82
82
|
} catch (IOException e) {
|
|
83
|
-
|
|
83
|
+
e.printStackTrace();
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
Integer width = android.getInteger("width", 48);
|
|
88
88
|
|
|
89
89
|
Integer height = android.getInteger("height", 48);
|
|
90
|
-
|
|
90
|
+
final ButtonNearDone buttonNearDone1 = new ButtonNearDone(
|
|
91
|
+
AllIconTypes.ASSET,
|
|
92
|
+
icon,
|
|
93
|
+
height,
|
|
94
|
+
width
|
|
95
|
+
);
|
|
96
|
+
return buttonNearDone1;
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
public AllIconTypes getIconType() {
|
|
@@ -15,7 +15,6 @@ import android.graphics.Picture;
|
|
|
15
15
|
import android.graphics.drawable.PictureDrawable;
|
|
16
16
|
import android.net.Uri;
|
|
17
17
|
import android.net.http.SslError;
|
|
18
|
-
import android.os.Build;
|
|
19
18
|
import android.text.TextUtils;
|
|
20
19
|
import android.util.Base64;
|
|
21
20
|
import android.util.Log;
|
|
@@ -37,7 +36,6 @@ import android.widget.ImageButton;
|
|
|
37
36
|
import android.widget.TextView;
|
|
38
37
|
import android.widget.Toast;
|
|
39
38
|
import android.widget.Toolbar;
|
|
40
|
-
import androidx.annotation.RequiresApi;
|
|
41
39
|
import androidx.core.view.WindowInsetsControllerCompat;
|
|
42
40
|
import com.caverock.androidsvg.SVG;
|
|
43
41
|
import com.caverock.androidsvg.SVGParseException;
|
|
@@ -45,15 +43,12 @@ import com.getcapacitor.JSObject;
|
|
|
45
43
|
import java.io.ByteArrayInputStream;
|
|
46
44
|
import java.io.IOException;
|
|
47
45
|
import java.io.InputStream;
|
|
48
|
-
import java.net.CookiePolicy;
|
|
49
46
|
import java.net.URI;
|
|
50
47
|
import java.net.URISyntaxException;
|
|
51
|
-
import java.net.URL;
|
|
52
48
|
import java.nio.charset.StandardCharsets;
|
|
53
49
|
import java.util.Arrays;
|
|
54
50
|
import java.util.HashMap;
|
|
55
51
|
import java.util.Iterator;
|
|
56
|
-
import java.util.List;
|
|
57
52
|
import java.util.Map;
|
|
58
53
|
import java.util.Objects;
|
|
59
54
|
import java.util.UUID;
|
|
@@ -61,7 +56,6 @@ import java.util.concurrent.ExecutorService;
|
|
|
61
56
|
import java.util.concurrent.Executors;
|
|
62
57
|
import java.util.concurrent.Semaphore;
|
|
63
58
|
import java.util.concurrent.TimeUnit;
|
|
64
|
-
import java.util.function.Consumer;
|
|
65
59
|
import java.util.regex.Matcher;
|
|
66
60
|
import java.util.regex.Pattern;
|
|
67
61
|
import org.json.JSONException;
|
|
@@ -69,10 +63,10 @@ import org.json.JSONObject;
|
|
|
69
63
|
|
|
70
64
|
public class WebViewDialog extends Dialog {
|
|
71
65
|
|
|
72
|
-
private class ProxiedRequest {
|
|
66
|
+
private static class ProxiedRequest {
|
|
73
67
|
|
|
74
68
|
private WebResourceResponse response;
|
|
75
|
-
private Semaphore semaphore;
|
|
69
|
+
private final Semaphore semaphore;
|
|
76
70
|
|
|
77
71
|
public WebResourceResponse getResponse() {
|
|
78
72
|
return response;
|
|
@@ -86,21 +80,23 @@ public class WebViewDialog extends Dialog {
|
|
|
86
80
|
|
|
87
81
|
private WebView _webView;
|
|
88
82
|
private Toolbar _toolbar;
|
|
89
|
-
private Options _options;
|
|
90
|
-
private Context _context;
|
|
83
|
+
private Options _options = null;
|
|
84
|
+
private final Context _context;
|
|
91
85
|
public Activity activity;
|
|
92
86
|
private boolean isInitialized = false;
|
|
93
|
-
private WebView capacitorWebView;
|
|
94
|
-
private
|
|
87
|
+
private final WebView capacitorWebView;
|
|
88
|
+
private final Map<String, ProxiedRequest> proxiedRequestsHashmap =
|
|
89
|
+
new HashMap<>();
|
|
90
|
+
private final ExecutorService executorService =
|
|
91
|
+
Executors.newCachedThreadPool();
|
|
95
92
|
|
|
96
93
|
Semaphore preShowSemaphore = null;
|
|
97
|
-
String
|
|
94
|
+
String preShowError = null;
|
|
98
95
|
|
|
99
96
|
public PermissionRequest currentPermissionRequest;
|
|
100
97
|
public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
|
|
101
98
|
public ValueCallback<Uri> mUploadMessage;
|
|
102
99
|
public ValueCallback<Uri[]> mFilePathCallback;
|
|
103
|
-
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
|
104
100
|
|
|
105
101
|
public interface PermissionHandler {
|
|
106
102
|
void handleCameraPermissionRequest(PermissionRequest request);
|
|
@@ -108,7 +104,7 @@ public class WebViewDialog extends Dialog {
|
|
|
108
104
|
void handleMicrophonePermissionRequest(PermissionRequest request);
|
|
109
105
|
}
|
|
110
106
|
|
|
111
|
-
private PermissionHandler permissionHandler;
|
|
107
|
+
private final PermissionHandler permissionHandler;
|
|
112
108
|
|
|
113
109
|
public WebViewDialog(
|
|
114
110
|
Context context,
|
|
@@ -123,30 +119,48 @@ public class WebViewDialog extends Dialog {
|
|
|
123
119
|
this.permissionHandler = permissionHandler;
|
|
124
120
|
this.isInitialized = false;
|
|
125
121
|
this.capacitorWebView = capacitorWebView;
|
|
126
|
-
this.proxiedRequestsHashmap = new HashMap<>();
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
|
|
124
|
+
// Add this class to provide safer JavaScript interface
|
|
125
|
+
private class JavaScriptInterface {
|
|
130
126
|
|
|
131
127
|
@JavascriptInterface
|
|
132
128
|
public void postMessage(String message) {
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
try {
|
|
130
|
+
// Handle message from JavaScript safely
|
|
131
|
+
if (message == null || message.isEmpty()) {
|
|
132
|
+
Log.e("InAppBrowser", "Received empty message from WebView");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
_options.getCallbacks().javascriptCallback(message);
|
|
136
|
+
} catch (Exception e) {
|
|
137
|
+
Log.e("InAppBrowser", "Error in postMessage: " + e.getMessage());
|
|
138
|
+
}
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
@JavascriptInterface
|
|
138
142
|
public void close() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
try {
|
|
144
|
+
// close webview safely
|
|
145
|
+
if (activity != null) {
|
|
146
|
+
activity.runOnUiThread(() -> {
|
|
147
|
+
try {
|
|
148
|
+
dismiss();
|
|
149
|
+
if (_webView != null) {
|
|
150
|
+
String currentUrl = _webView.getUrl();
|
|
151
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
152
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
153
|
+
}
|
|
154
|
+
_webView.destroy();
|
|
155
|
+
}
|
|
156
|
+
} catch (Exception e) {
|
|
157
|
+
Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
|
|
158
|
+
}
|
|
159
|
+
});
|
|
148
160
|
}
|
|
149
|
-
)
|
|
161
|
+
} catch (Exception e) {
|
|
162
|
+
Log.e("InAppBrowser", "Error in close: " + e.getMessage());
|
|
163
|
+
}
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
166
|
|
|
@@ -154,23 +168,31 @@ public class WebViewDialog extends Dialog {
|
|
|
154
168
|
|
|
155
169
|
@JavascriptInterface
|
|
156
170
|
public void error(String error) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
try {
|
|
172
|
+
// Handle message from JavaScript
|
|
173
|
+
if (preShowSemaphore != null) {
|
|
174
|
+
preShowError = error;
|
|
175
|
+
preShowSemaphore.release();
|
|
176
|
+
}
|
|
177
|
+
} catch (Exception e) {
|
|
178
|
+
Log.e("InAppBrowser", "Error in error callback: " + e.getMessage());
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
181
|
|
|
164
182
|
@JavascriptInterface
|
|
165
183
|
public void success() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
preShowSemaphore
|
|
184
|
+
try {
|
|
185
|
+
// Handle message from JavaScript
|
|
186
|
+
if (preShowSemaphore != null) {
|
|
187
|
+
preShowSemaphore.release();
|
|
188
|
+
}
|
|
189
|
+
} catch (Exception e) {
|
|
190
|
+
Log.e("InAppBrowser", "Error in success callback: " + e.getMessage());
|
|
169
191
|
}
|
|
170
192
|
}
|
|
171
193
|
}
|
|
172
194
|
|
|
173
|
-
@SuppressLint("SetJavaScriptEnabled")
|
|
195
|
+
@SuppressLint({ "SetJavaScriptEnabled", "AddJavascriptInterface" })
|
|
174
196
|
public void presentWebView() {
|
|
175
197
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
176
198
|
setCancelable(true);
|
|
@@ -210,9 +232,6 @@ public class WebViewDialog extends Dialog {
|
|
|
210
232
|
_webView.getSettings().setDatabaseEnabled(true);
|
|
211
233
|
_webView.getSettings().setDomStorageEnabled(true);
|
|
212
234
|
_webView.getSettings().setAllowFileAccess(true);
|
|
213
|
-
_webView
|
|
214
|
-
.getSettings()
|
|
215
|
-
.setPluginState(android.webkit.WebSettings.PluginState.ON);
|
|
216
235
|
_webView.getSettings().setLoadWithOverviewMode(true);
|
|
217
236
|
_webView.getSettings().setUseWideViewPort(true);
|
|
218
237
|
_webView.getSettings().setAllowFileAccessFromFileURLs(true);
|
|
@@ -228,7 +247,7 @@ public class WebViewDialog extends Dialog {
|
|
|
228
247
|
public boolean onShowFileChooser(
|
|
229
248
|
WebView webView,
|
|
230
249
|
ValueCallback<Uri[]> filePathCallback,
|
|
231
|
-
|
|
250
|
+
FileChooserParams fileChooserParams
|
|
232
251
|
) {
|
|
233
252
|
openFileChooser(
|
|
234
253
|
filePathCallback,
|
|
@@ -392,10 +411,10 @@ public class WebViewDialog extends Dialog {
|
|
|
392
411
|
);
|
|
393
412
|
return;
|
|
394
413
|
}
|
|
395
|
-
if (
|
|
414
|
+
if (preShowError != null && !preShowError.isEmpty()) {
|
|
396
415
|
Log.e(
|
|
397
416
|
"InjectPreShowScript",
|
|
398
|
-
"Error within the user-provided preShowFunction: " +
|
|
417
|
+
"Error within the user-provided preShowFunction: " + preShowError
|
|
399
418
|
);
|
|
400
419
|
}
|
|
401
420
|
} catch (InterruptedException e) {
|
|
@@ -405,7 +424,7 @@ public class WebViewDialog extends Dialog {
|
|
|
405
424
|
);
|
|
406
425
|
} finally {
|
|
407
426
|
preShowSemaphore = null;
|
|
408
|
-
|
|
427
|
+
preShowError = null;
|
|
409
428
|
}
|
|
410
429
|
}
|
|
411
430
|
|
|
@@ -529,7 +548,7 @@ public class WebViewDialog extends Dialog {
|
|
|
529
548
|
.setMessage(_options.getCloseModalDescription())
|
|
530
549
|
.setPositiveButton(
|
|
531
550
|
_options.getCloseModalOk(),
|
|
532
|
-
new
|
|
551
|
+
new OnClickListener() {
|
|
533
552
|
public void onClick(DialogInterface dialog, int which) {
|
|
534
553
|
// Close button clicked, do something
|
|
535
554
|
dismiss();
|
|
@@ -618,7 +637,7 @@ public class WebViewDialog extends Dialog {
|
|
|
618
637
|
try {
|
|
619
638
|
inputStream.close();
|
|
620
639
|
} catch (IOException e) {
|
|
621
|
-
|
|
640
|
+
e.printStackTrace();
|
|
622
641
|
}
|
|
623
642
|
}
|
|
624
643
|
}
|
|
@@ -742,9 +761,7 @@ public class WebViewDialog extends Dialog {
|
|
|
742
761
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
743
762
|
context.startActivity(intent);
|
|
744
763
|
return true;
|
|
745
|
-
} catch (ActivityNotFoundException e) {
|
|
746
|
-
// Do nothing
|
|
747
|
-
} catch (URISyntaxException e) {
|
|
764
|
+
} catch (ActivityNotFoundException | URISyntaxException e) {
|
|
748
765
|
// Do nothing
|
|
749
766
|
}
|
|
750
767
|
}
|
|
@@ -769,7 +786,6 @@ public class WebViewDialog extends Dialog {
|
|
|
769
786
|
// _webView.evaluateJavascript("");
|
|
770
787
|
// }
|
|
771
788
|
//
|
|
772
|
-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
|
773
789
|
@Override
|
|
774
790
|
public WebResourceResponse shouldInterceptRequest(
|
|
775
791
|
WebView view,
|
|
@@ -798,7 +814,7 @@ public class WebViewDialog extends Dialog {
|
|
|
798
814
|
// We need to call a JS function
|
|
799
815
|
String requestId = randomRequestId();
|
|
800
816
|
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
801
|
-
|
|
817
|
+
addProxiedRequest(requestId, proxiedRequest);
|
|
802
818
|
|
|
803
819
|
// lsuakdchgbbaHandleProxiedRequest
|
|
804
820
|
activity.runOnUiThread(
|
|
@@ -841,7 +857,7 @@ public class WebViewDialog extends Dialog {
|
|
|
841
857
|
return proxiedRequest.response;
|
|
842
858
|
} else {
|
|
843
859
|
Log.e("InAppBrowserProxy", "Semaphore timed out");
|
|
844
|
-
|
|
860
|
+
removeProxiedRequest(requestId); // prevent mem leak
|
|
845
861
|
}
|
|
846
862
|
} catch (InterruptedException e) {
|
|
847
863
|
Log.e("InAppBrowserProxy", "Semaphore wait error", e);
|
|
@@ -1068,99 +1084,97 @@ public class WebViewDialog extends Dialog {
|
|
|
1068
1084
|
}
|
|
1069
1085
|
|
|
1070
1086
|
public static String getReasonPhrase(int statusCode) {
|
|
1071
|
-
switch (statusCode) {
|
|
1072
|
-
case (200)
|
|
1073
|
-
|
|
1074
|
-
case (
|
|
1075
|
-
|
|
1076
|
-
case (
|
|
1077
|
-
|
|
1078
|
-
case (
|
|
1079
|
-
|
|
1080
|
-
case (
|
|
1081
|
-
|
|
1082
|
-
case (
|
|
1083
|
-
|
|
1084
|
-
case (
|
|
1085
|
-
|
|
1086
|
-
case (
|
|
1087
|
-
|
|
1088
|
-
case (
|
|
1089
|
-
|
|
1090
|
-
case (
|
|
1091
|
-
|
|
1092
|
-
case (
|
|
1093
|
-
|
|
1094
|
-
case (
|
|
1095
|
-
|
|
1096
|
-
case (
|
|
1097
|
-
|
|
1098
|
-
case (
|
|
1099
|
-
|
|
1100
|
-
case (
|
|
1101
|
-
|
|
1102
|
-
case (
|
|
1103
|
-
|
|
1104
|
-
case (
|
|
1105
|
-
|
|
1106
|
-
case (
|
|
1107
|
-
|
|
1108
|
-
case (
|
|
1109
|
-
|
|
1110
|
-
case (
|
|
1111
|
-
|
|
1112
|
-
case (
|
|
1113
|
-
|
|
1114
|
-
case (
|
|
1115
|
-
|
|
1116
|
-
case (
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
default:
|
|
1163
|
-
return "";
|
|
1087
|
+
return switch (statusCode) {
|
|
1088
|
+
case (200) -> "OK";
|
|
1089
|
+
case (201) -> "Created";
|
|
1090
|
+
case (202) -> "Accepted";
|
|
1091
|
+
case (203) -> "Non Authoritative Information";
|
|
1092
|
+
case (204) -> "No Content";
|
|
1093
|
+
case (205) -> "Reset Content";
|
|
1094
|
+
case (206) -> "Partial Content";
|
|
1095
|
+
case (207) -> "Partial Update OK";
|
|
1096
|
+
case (300) -> "Mutliple Choices";
|
|
1097
|
+
case (301) -> "Moved Permanently";
|
|
1098
|
+
case (302) -> "Moved Temporarily";
|
|
1099
|
+
case (303) -> "See Other";
|
|
1100
|
+
case (304) -> "Not Modified";
|
|
1101
|
+
case (305) -> "Use Proxy";
|
|
1102
|
+
case (307) -> "Temporary Redirect";
|
|
1103
|
+
case (400) -> "Bad Request";
|
|
1104
|
+
case (401) -> "Unauthorized";
|
|
1105
|
+
case (402) -> "Payment Required";
|
|
1106
|
+
case (403) -> "Forbidden";
|
|
1107
|
+
case (404) -> "Not Found";
|
|
1108
|
+
case (405) -> "Method Not Allowed";
|
|
1109
|
+
case (406) -> "Not Acceptable";
|
|
1110
|
+
case (407) -> "Proxy Authentication Required";
|
|
1111
|
+
case (408) -> "Request Timeout";
|
|
1112
|
+
case (409) -> "Conflict";
|
|
1113
|
+
case (410) -> "Gone";
|
|
1114
|
+
case (411) -> "Length Required";
|
|
1115
|
+
case (412) -> "Precondition Failed";
|
|
1116
|
+
case (413) -> "Request Entity Too Large";
|
|
1117
|
+
case (414) -> "Request-URI Too Long";
|
|
1118
|
+
case (415) -> "Unsupported Media Type";
|
|
1119
|
+
case (416) -> "Requested Range Not Satisfiable";
|
|
1120
|
+
case (417) -> "Expectation Failed";
|
|
1121
|
+
case (418) -> "Reauthentication Required";
|
|
1122
|
+
case (419) -> "Proxy Reauthentication Required";
|
|
1123
|
+
case (422) -> "Unprocessable Entity";
|
|
1124
|
+
case (423) -> "Locked";
|
|
1125
|
+
case (424) -> "Failed Dependency";
|
|
1126
|
+
case (500) -> "Server Error";
|
|
1127
|
+
case (501) -> "Not Implemented";
|
|
1128
|
+
case (502) -> "Bad Gateway";
|
|
1129
|
+
case (503) -> "Service Unavailable";
|
|
1130
|
+
case (504) -> "Gateway Timeout";
|
|
1131
|
+
case (505) -> "HTTP Version Not Supported";
|
|
1132
|
+
case (507) -> "Insufficient Storage";
|
|
1133
|
+
default -> "";
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
@Override
|
|
1138
|
+
public void dismiss() {
|
|
1139
|
+
if (_webView != null) {
|
|
1140
|
+
_webView.loadUrl("about:blank");
|
|
1141
|
+
_webView.onPause();
|
|
1142
|
+
_webView.removeAllViews();
|
|
1143
|
+
_webView.destroy();
|
|
1144
|
+
_webView = null;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (executorService != null && !executorService.isShutdown()) {
|
|
1148
|
+
executorService.shutdown();
|
|
1149
|
+
try {
|
|
1150
|
+
if (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
|
|
1151
|
+
executorService.shutdownNow();
|
|
1152
|
+
}
|
|
1153
|
+
} catch (InterruptedException e) {
|
|
1154
|
+
executorService.shutdownNow();
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
super.dismiss();
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
public void addProxiedRequest(String key, ProxiedRequest request) {
|
|
1162
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1163
|
+
proxiedRequestsHashmap.put(key, request);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
public ProxiedRequest getProxiedRequest(String key) {
|
|
1168
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1169
|
+
ProxiedRequest request = proxiedRequestsHashmap.get(key);
|
|
1170
|
+
proxiedRequestsHashmap.remove(key);
|
|
1171
|
+
return request;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
public void removeProxiedRequest(String key) {
|
|
1176
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1177
|
+
proxiedRequestsHashmap.remove(key);
|
|
1164
1178
|
}
|
|
1165
1179
|
}
|
|
1166
1180
|
}
|
|
@@ -60,7 +60,12 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
func presentView(isAnimated: Bool = true) {
|
|
63
|
-
self.
|
|
63
|
+
guard let navigationController = self.navigationWebViewController else {
|
|
64
|
+
self.currentPluginCall?.reject("Navigation controller is not initialized")
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
self.bridge?.viewController?.present(navigationController, animated: isAnimated, completion: {
|
|
64
69
|
self.currentPluginCall?.resolve()
|
|
65
70
|
})
|
|
66
71
|
}
|
|
@@ -98,18 +103,19 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
98
103
|
|
|
99
104
|
DispatchQueue.main.async {
|
|
100
105
|
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
|
|
106
|
+
let group = DispatchGroup()
|
|
101
107
|
for cookie in cookies {
|
|
102
|
-
|
|
103
108
|
if cookie.domain == host || cookie.domain.hasSuffix(".\(host)") || host.hasSuffix(cookie.domain) {
|
|
104
|
-
|
|
109
|
+
group.enter()
|
|
105
110
|
WKWebsiteDataStore.default().httpCookieStore.delete(cookie) {
|
|
106
|
-
|
|
111
|
+
group.leave()
|
|
107
112
|
}
|
|
108
|
-
semaphore.wait()
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
|
|
116
|
+
group.notify(queue: .main) {
|
|
117
|
+
call.resolve()
|
|
118
|
+
}
|
|
113
119
|
}
|
|
114
120
|
}
|
|
115
121
|
}
|
|
@@ -211,43 +217,45 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
211
217
|
let credentials = self.readCredentials(call)
|
|
212
218
|
|
|
213
219
|
DispatchQueue.main.async {
|
|
214
|
-
let url = URL(string: urlString)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else {
|
|
218
|
-
self.webViewController = WKWebViewController.init()
|
|
219
|
-
self.webViewController?.setHeaders(headers: headers)
|
|
220
|
-
self.webViewController?.setCredentials(credentials: credentials)
|
|
221
|
-
self.webViewController?.setPreventDeeplink(preventDeeplink: preventDeeplink)
|
|
220
|
+
guard let url = URL(string: urlString) else {
|
|
221
|
+
call.reject("Invalid URL format")
|
|
222
|
+
return
|
|
222
223
|
}
|
|
223
224
|
|
|
224
|
-
self.webViewController
|
|
225
|
-
self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
|
|
226
|
-
self.webViewController?.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType)
|
|
227
|
-
self.webViewController?.toolbarItemTypes = []
|
|
228
|
-
self.webViewController?.doneBarButtonItemPosition = .right
|
|
225
|
+
self.webViewController = WKWebViewController.init(url: url, headers: headers, isInspectable: isInspectable, credentials: credentials, preventDeeplink: preventDeeplink, blankNavigationTab: toolbarType == "blank")
|
|
229
226
|
|
|
230
|
-
self.webViewController
|
|
227
|
+
guard let webViewController = self.webViewController else {
|
|
228
|
+
call.reject("Failed to initialize WebViewController")
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
webViewController.source = .remote(url)
|
|
233
|
+
webViewController.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
|
|
234
|
+
webViewController.toolbarItemTypes = []
|
|
235
|
+
webViewController.doneBarButtonItemPosition = .right
|
|
236
|
+
|
|
237
|
+
webViewController.buttonNearDoneIcon = buttonNearDoneIcon
|
|
231
238
|
|
|
232
239
|
if call.getBool("showArrow", false) {
|
|
233
|
-
|
|
240
|
+
webViewController.stopBarButtonItemImage = UIImage(named: "Forward@3x", in: Bundle(for: InAppBrowserPlugin.self), compatibleWith: nil)
|
|
234
241
|
}
|
|
235
242
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
webViewController.capBrowserPlugin = self
|
|
244
|
+
webViewController.title = call.getString("title", "New Window")
|
|
245
|
+
webViewController.shareSubject = call.getString("shareSubject")
|
|
246
|
+
webViewController.shareDisclaimer = disclaimerContent
|
|
247
|
+
webViewController.preShowScript = call.getString("preShowScript")
|
|
248
|
+
webViewController.websiteTitleInNavigationBar = call.getBool("visibleTitle", true)
|
|
242
249
|
if closeModal {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
250
|
+
webViewController.closeModal = true
|
|
251
|
+
webViewController.closeModalTitle = closeModalTitle
|
|
252
|
+
webViewController.closeModalDescription = closeModalDescription
|
|
253
|
+
webViewController.closeModalOk = closeModalOk
|
|
254
|
+
webViewController.closeModalCancel = closeModalCancel
|
|
248
255
|
}
|
|
249
|
-
|
|
250
|
-
|
|
256
|
+
webViewController.ignoreUntrustedSSLError = ignoreUntrustedSSLError
|
|
257
|
+
|
|
258
|
+
self.navigationWebViewController = UINavigationController.init(rootViewController: webViewController)
|
|
251
259
|
self.navigationWebViewController?.navigationBar.isTranslucent = false
|
|
252
260
|
self.navigationWebViewController?.toolbar.isTranslucent = false
|
|
253
261
|
self.navigationWebViewController?.navigationBar.backgroundColor = backgroundColor
|
|
@@ -256,11 +264,11 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
256
264
|
self.navigationWebViewController?.modalPresentationStyle = .fullScreen
|
|
257
265
|
if toolbarType == "blank" {
|
|
258
266
|
self.navigationWebViewController?.navigationBar.isHidden = true
|
|
259
|
-
|
|
267
|
+
webViewController.blankNavigationTab = true
|
|
260
268
|
}
|
|
261
269
|
if showReloadButton {
|
|
262
270
|
let toolbarItems = self.getToolbarItems(toolbarType: toolbarType)
|
|
263
|
-
|
|
271
|
+
webViewController.leftNavigationBarItemTypes = toolbarItems + [.reload]
|
|
264
272
|
}
|
|
265
273
|
if !self.isPresentAfterPageLoad {
|
|
266
274
|
self.presentView(isAnimated: isAnimated)
|
|
@@ -75,7 +75,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
75
75
|
self.setPreventDeeplink(preventDeeplink: preventDeeplink)
|
|
76
76
|
self.initWebview(isInspectable: isInspectable)
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool) {
|
|
80
80
|
super.init(nibName: nil, bundle: nil)
|
|
81
81
|
self.blankNavigationTab = blankNavigationTab
|
|
@@ -111,7 +111,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
111
111
|
open var ignoreUntrustedSSLError = false
|
|
112
112
|
var viewWasPresented = false
|
|
113
113
|
var preventDeeplink: Bool = false
|
|
114
|
-
var blankNavigationTab: Bool = false
|
|
114
|
+
var blankNavigationTab: Bool = false
|
|
115
115
|
|
|
116
116
|
internal var preShowSemaphore: DispatchSemaphore?
|
|
117
117
|
internal var preShowError: String?
|
|
@@ -326,10 +326,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
326
326
|
webView.perform(Selector(("setInspectable:")), with: isInspectable)
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
if
|
|
329
|
+
if self.blankNavigationTab {
|
|
330
330
|
// First add the webView to view hierarchy
|
|
331
331
|
self.view.addSubview(webView)
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
// Then set up constraints
|
|
334
334
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
335
335
|
NSLayoutConstraint.activate([
|
|
@@ -352,7 +352,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
352
352
|
}
|
|
353
353
|
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.url), options: .new, context: nil)
|
|
354
354
|
|
|
355
|
-
if
|
|
355
|
+
if !self.blankNavigationTab {
|
|
356
356
|
self.view = webView
|
|
357
357
|
}
|
|
358
358
|
self.webView = webView
|
|
@@ -841,7 +841,20 @@ fileprivate extension WKWebViewController {
|
|
|
841
841
|
canDismiss = delegate?.webViewController?(self, canDismiss: url) ?? true
|
|
842
842
|
}
|
|
843
843
|
if canDismiss {
|
|
844
|
-
//
|
|
844
|
+
// Cleanup webView
|
|
845
|
+
webView?.stopLoading()
|
|
846
|
+
webView?.removeObserver(self, forKeyPath: estimatedProgressKeyPath)
|
|
847
|
+
if websiteTitleInNavigationBar {
|
|
848
|
+
webView?.removeObserver(self, forKeyPath: titleKeyPath)
|
|
849
|
+
}
|
|
850
|
+
webView?.removeObserver(self, forKeyPath: #keyPath(WKWebView.url))
|
|
851
|
+
webView?.configuration.userContentController.removeAllUserScripts()
|
|
852
|
+
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "messageHandler")
|
|
853
|
+
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "close")
|
|
854
|
+
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptSuccess")
|
|
855
|
+
webView?.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptError")
|
|
856
|
+
webView = nil
|
|
857
|
+
|
|
845
858
|
self.capBrowserPlugin?.notifyListeners("closeEvent", data: ["url": webView?.url?.absoluteString ?? ""])
|
|
846
859
|
dismiss(animated: true, completion: nil)
|
|
847
860
|
}
|