@capgo/inappbrowser 7.2.21 → 7.3.2
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 +166 -149
- 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,45 @@ 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
|
+
String currentUrl = _webView != null ? _webView.getUrl() : "";
|
|
149
|
+
dismiss();
|
|
150
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
151
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
152
|
+
}
|
|
153
|
+
} catch (Exception e) {
|
|
154
|
+
Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
|
|
155
|
+
}
|
|
156
|
+
});
|
|
148
157
|
}
|
|
149
|
-
)
|
|
158
|
+
} catch (Exception e) {
|
|
159
|
+
Log.e("InAppBrowser", "Error in close: " + e.getMessage());
|
|
160
|
+
}
|
|
150
161
|
}
|
|
151
162
|
}
|
|
152
163
|
|
|
@@ -154,23 +165,31 @@ public class WebViewDialog extends Dialog {
|
|
|
154
165
|
|
|
155
166
|
@JavascriptInterface
|
|
156
167
|
public void error(String error) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
try {
|
|
169
|
+
// Handle message from JavaScript
|
|
170
|
+
if (preShowSemaphore != null) {
|
|
171
|
+
preShowError = error;
|
|
172
|
+
preShowSemaphore.release();
|
|
173
|
+
}
|
|
174
|
+
} catch (Exception e) {
|
|
175
|
+
Log.e("InAppBrowser", "Error in error callback: " + e.getMessage());
|
|
161
176
|
}
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
@JavascriptInterface
|
|
165
180
|
public void success() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
preShowSemaphore
|
|
181
|
+
try {
|
|
182
|
+
// Handle message from JavaScript
|
|
183
|
+
if (preShowSemaphore != null) {
|
|
184
|
+
preShowSemaphore.release();
|
|
185
|
+
}
|
|
186
|
+
} catch (Exception e) {
|
|
187
|
+
Log.e("InAppBrowser", "Error in success callback: " + e.getMessage());
|
|
169
188
|
}
|
|
170
189
|
}
|
|
171
190
|
}
|
|
172
191
|
|
|
173
|
-
@SuppressLint("SetJavaScriptEnabled")
|
|
192
|
+
@SuppressLint({ "SetJavaScriptEnabled", "AddJavascriptInterface" })
|
|
174
193
|
public void presentWebView() {
|
|
175
194
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
176
195
|
setCancelable(true);
|
|
@@ -210,9 +229,6 @@ public class WebViewDialog extends Dialog {
|
|
|
210
229
|
_webView.getSettings().setDatabaseEnabled(true);
|
|
211
230
|
_webView.getSettings().setDomStorageEnabled(true);
|
|
212
231
|
_webView.getSettings().setAllowFileAccess(true);
|
|
213
|
-
_webView
|
|
214
|
-
.getSettings()
|
|
215
|
-
.setPluginState(android.webkit.WebSettings.PluginState.ON);
|
|
216
232
|
_webView.getSettings().setLoadWithOverviewMode(true);
|
|
217
233
|
_webView.getSettings().setUseWideViewPort(true);
|
|
218
234
|
_webView.getSettings().setAllowFileAccessFromFileURLs(true);
|
|
@@ -228,7 +244,7 @@ public class WebViewDialog extends Dialog {
|
|
|
228
244
|
public boolean onShowFileChooser(
|
|
229
245
|
WebView webView,
|
|
230
246
|
ValueCallback<Uri[]> filePathCallback,
|
|
231
|
-
|
|
247
|
+
FileChooserParams fileChooserParams
|
|
232
248
|
) {
|
|
233
249
|
openFileChooser(
|
|
234
250
|
filePathCallback,
|
|
@@ -392,10 +408,10 @@ public class WebViewDialog extends Dialog {
|
|
|
392
408
|
);
|
|
393
409
|
return;
|
|
394
410
|
}
|
|
395
|
-
if (
|
|
411
|
+
if (preShowError != null && !preShowError.isEmpty()) {
|
|
396
412
|
Log.e(
|
|
397
413
|
"InjectPreShowScript",
|
|
398
|
-
"Error within the user-provided preShowFunction: " +
|
|
414
|
+
"Error within the user-provided preShowFunction: " + preShowError
|
|
399
415
|
);
|
|
400
416
|
}
|
|
401
417
|
} catch (InterruptedException e) {
|
|
@@ -405,7 +421,7 @@ public class WebViewDialog extends Dialog {
|
|
|
405
421
|
);
|
|
406
422
|
} finally {
|
|
407
423
|
preShowSemaphore = null;
|
|
408
|
-
|
|
424
|
+
preShowError = null;
|
|
409
425
|
}
|
|
410
426
|
}
|
|
411
427
|
|
|
@@ -529,21 +545,27 @@ public class WebViewDialog extends Dialog {
|
|
|
529
545
|
.setMessage(_options.getCloseModalDescription())
|
|
530
546
|
.setPositiveButton(
|
|
531
547
|
_options.getCloseModalOk(),
|
|
532
|
-
new
|
|
548
|
+
new OnClickListener() {
|
|
533
549
|
public void onClick(DialogInterface dialog, int which) {
|
|
534
550
|
// Close button clicked, do something
|
|
551
|
+
String currentUrl = _webView != null
|
|
552
|
+
? _webView.getUrl()
|
|
553
|
+
: "";
|
|
535
554
|
dismiss();
|
|
536
|
-
_options.getCallbacks()
|
|
537
|
-
|
|
555
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
556
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
557
|
+
}
|
|
538
558
|
}
|
|
539
559
|
}
|
|
540
560
|
)
|
|
541
561
|
.setNegativeButton(_options.getCloseModalCancel(), null)
|
|
542
562
|
.show();
|
|
543
563
|
} else {
|
|
564
|
+
String currentUrl = _webView != null ? _webView.getUrl() : "";
|
|
544
565
|
dismiss();
|
|
545
|
-
_options.getCallbacks()
|
|
546
|
-
|
|
566
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
567
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
568
|
+
}
|
|
547
569
|
}
|
|
548
570
|
}
|
|
549
571
|
}
|
|
@@ -618,7 +640,7 @@ public class WebViewDialog extends Dialog {
|
|
|
618
640
|
try {
|
|
619
641
|
inputStream.close();
|
|
620
642
|
} catch (IOException e) {
|
|
621
|
-
|
|
643
|
+
e.printStackTrace();
|
|
622
644
|
}
|
|
623
645
|
}
|
|
624
646
|
}
|
|
@@ -742,9 +764,7 @@ public class WebViewDialog extends Dialog {
|
|
|
742
764
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
743
765
|
context.startActivity(intent);
|
|
744
766
|
return true;
|
|
745
|
-
} catch (ActivityNotFoundException e) {
|
|
746
|
-
// Do nothing
|
|
747
|
-
} catch (URISyntaxException e) {
|
|
767
|
+
} catch (ActivityNotFoundException | URISyntaxException e) {
|
|
748
768
|
// Do nothing
|
|
749
769
|
}
|
|
750
770
|
}
|
|
@@ -769,7 +789,6 @@ public class WebViewDialog extends Dialog {
|
|
|
769
789
|
// _webView.evaluateJavascript("");
|
|
770
790
|
// }
|
|
771
791
|
//
|
|
772
|
-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
|
773
792
|
@Override
|
|
774
793
|
public WebResourceResponse shouldInterceptRequest(
|
|
775
794
|
WebView view,
|
|
@@ -798,7 +817,7 @@ public class WebViewDialog extends Dialog {
|
|
|
798
817
|
// We need to call a JS function
|
|
799
818
|
String requestId = randomRequestId();
|
|
800
819
|
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
801
|
-
|
|
820
|
+
addProxiedRequest(requestId, proxiedRequest);
|
|
802
821
|
|
|
803
822
|
// lsuakdchgbbaHandleProxiedRequest
|
|
804
823
|
activity.runOnUiThread(
|
|
@@ -841,7 +860,7 @@ public class WebViewDialog extends Dialog {
|
|
|
841
860
|
return proxiedRequest.response;
|
|
842
861
|
} else {
|
|
843
862
|
Log.e("InAppBrowserProxy", "Semaphore timed out");
|
|
844
|
-
|
|
863
|
+
removeProxiedRequest(requestId); // prevent mem leak
|
|
845
864
|
}
|
|
846
865
|
} catch (InterruptedException e) {
|
|
847
866
|
Log.e("InAppBrowserProxy", "Semaphore wait error", e);
|
|
@@ -1068,99 +1087,97 @@ public class WebViewDialog extends Dialog {
|
|
|
1068
1087
|
}
|
|
1069
1088
|
|
|
1070
1089
|
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 "";
|
|
1090
|
+
return switch (statusCode) {
|
|
1091
|
+
case (200) -> "OK";
|
|
1092
|
+
case (201) -> "Created";
|
|
1093
|
+
case (202) -> "Accepted";
|
|
1094
|
+
case (203) -> "Non Authoritative Information";
|
|
1095
|
+
case (204) -> "No Content";
|
|
1096
|
+
case (205) -> "Reset Content";
|
|
1097
|
+
case (206) -> "Partial Content";
|
|
1098
|
+
case (207) -> "Partial Update OK";
|
|
1099
|
+
case (300) -> "Mutliple Choices";
|
|
1100
|
+
case (301) -> "Moved Permanently";
|
|
1101
|
+
case (302) -> "Moved Temporarily";
|
|
1102
|
+
case (303) -> "See Other";
|
|
1103
|
+
case (304) -> "Not Modified";
|
|
1104
|
+
case (305) -> "Use Proxy";
|
|
1105
|
+
case (307) -> "Temporary Redirect";
|
|
1106
|
+
case (400) -> "Bad Request";
|
|
1107
|
+
case (401) -> "Unauthorized";
|
|
1108
|
+
case (402) -> "Payment Required";
|
|
1109
|
+
case (403) -> "Forbidden";
|
|
1110
|
+
case (404) -> "Not Found";
|
|
1111
|
+
case (405) -> "Method Not Allowed";
|
|
1112
|
+
case (406) -> "Not Acceptable";
|
|
1113
|
+
case (407) -> "Proxy Authentication Required";
|
|
1114
|
+
case (408) -> "Request Timeout";
|
|
1115
|
+
case (409) -> "Conflict";
|
|
1116
|
+
case (410) -> "Gone";
|
|
1117
|
+
case (411) -> "Length Required";
|
|
1118
|
+
case (412) -> "Precondition Failed";
|
|
1119
|
+
case (413) -> "Request Entity Too Large";
|
|
1120
|
+
case (414) -> "Request-URI Too Long";
|
|
1121
|
+
case (415) -> "Unsupported Media Type";
|
|
1122
|
+
case (416) -> "Requested Range Not Satisfiable";
|
|
1123
|
+
case (417) -> "Expectation Failed";
|
|
1124
|
+
case (418) -> "Reauthentication Required";
|
|
1125
|
+
case (419) -> "Proxy Reauthentication Required";
|
|
1126
|
+
case (422) -> "Unprocessable Entity";
|
|
1127
|
+
case (423) -> "Locked";
|
|
1128
|
+
case (424) -> "Failed Dependency";
|
|
1129
|
+
case (500) -> "Server Error";
|
|
1130
|
+
case (501) -> "Not Implemented";
|
|
1131
|
+
case (502) -> "Bad Gateway";
|
|
1132
|
+
case (503) -> "Service Unavailable";
|
|
1133
|
+
case (504) -> "Gateway Timeout";
|
|
1134
|
+
case (505) -> "HTTP Version Not Supported";
|
|
1135
|
+
case (507) -> "Insufficient Storage";
|
|
1136
|
+
default -> "";
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
@Override
|
|
1141
|
+
public void dismiss() {
|
|
1142
|
+
if (_webView != null) {
|
|
1143
|
+
_webView.loadUrl("about:blank");
|
|
1144
|
+
_webView.onPause();
|
|
1145
|
+
_webView.removeAllViews();
|
|
1146
|
+
_webView.destroy();
|
|
1147
|
+
_webView = null;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
if (executorService != null && !executorService.isShutdown()) {
|
|
1151
|
+
executorService.shutdown();
|
|
1152
|
+
try {
|
|
1153
|
+
if (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
|
|
1154
|
+
executorService.shutdownNow();
|
|
1155
|
+
}
|
|
1156
|
+
} catch (InterruptedException e) {
|
|
1157
|
+
executorService.shutdownNow();
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
super.dismiss();
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
public void addProxiedRequest(String key, ProxiedRequest request) {
|
|
1165
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1166
|
+
proxiedRequestsHashmap.put(key, request);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
public ProxiedRequest getProxiedRequest(String key) {
|
|
1171
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1172
|
+
ProxiedRequest request = proxiedRequestsHashmap.get(key);
|
|
1173
|
+
proxiedRequestsHashmap.remove(key);
|
|
1174
|
+
return request;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
public void removeProxiedRequest(String key) {
|
|
1179
|
+
synchronized (proxiedRequestsHashmap) {
|
|
1180
|
+
proxiedRequestsHashmap.remove(key);
|
|
1164
1181
|
}
|
|
1165
1182
|
}
|
|
1166
1183
|
}
|
|
@@ -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
|
}
|