@capgo/inappbrowser 7.0.0 → 7.1.6
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/CapgoInappbrowser.podspec +1 -1
- package/README.md +448 -54
- package/android/build.gradle +15 -13
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +530 -35
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +251 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +4 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +904 -20
- package/android/src/main/res/drawable/ic_refresh.xml +9 -0
- package/android/src/main/res/layout/tool_bar.xml +25 -3
- package/android/src/main/res/values/strings.xml +2 -0
- package/dist/docs.json +1365 -67
- package/dist/esm/definitions.d.ts +218 -9
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +10 -2
- package/dist/esm/web.js +26 -2
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +26 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +26 -2
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/InAppBrowserPlugin.m +5 -1
- package/ios/Plugin/InAppBrowserPlugin.swift +247 -12
- package/ios/Plugin/WKWebViewController.swift +303 -55
- package/package.json +26 -27
|
@@ -1,47 +1,180 @@
|
|
|
1
1
|
package ee.forgr.capacitor_inappbrowser;
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
4
|
+
import android.app.Activity;
|
|
5
|
+
import android.app.AlertDialog;
|
|
3
6
|
import android.app.Dialog;
|
|
7
|
+
import android.content.ActivityNotFoundException;
|
|
4
8
|
import android.content.Context;
|
|
9
|
+
import android.content.DialogInterface;
|
|
10
|
+
import android.content.Intent;
|
|
11
|
+
import android.content.res.AssetManager;
|
|
5
12
|
import android.graphics.Bitmap;
|
|
13
|
+
import android.graphics.Color;
|
|
14
|
+
import android.graphics.Picture;
|
|
15
|
+
import android.graphics.drawable.PictureDrawable;
|
|
16
|
+
import android.net.Uri;
|
|
17
|
+
import android.net.http.SslError;
|
|
18
|
+
import android.os.Build;
|
|
6
19
|
import android.text.TextUtils;
|
|
20
|
+
import android.util.Base64;
|
|
21
|
+
import android.util.Log;
|
|
7
22
|
import android.view.View;
|
|
8
23
|
import android.view.Window;
|
|
9
24
|
import android.view.WindowManager;
|
|
25
|
+
import android.webkit.HttpAuthHandler;
|
|
26
|
+
import android.webkit.JavascriptInterface;
|
|
27
|
+
import android.webkit.PermissionRequest;
|
|
28
|
+
import android.webkit.SslErrorHandler;
|
|
29
|
+
import android.webkit.ValueCallback;
|
|
30
|
+
import android.webkit.WebChromeClient;
|
|
10
31
|
import android.webkit.WebResourceError;
|
|
11
32
|
import android.webkit.WebResourceRequest;
|
|
33
|
+
import android.webkit.WebResourceResponse;
|
|
12
34
|
import android.webkit.WebView;
|
|
13
35
|
import android.webkit.WebViewClient;
|
|
14
36
|
import android.widget.ImageButton;
|
|
15
37
|
import android.widget.TextView;
|
|
38
|
+
import android.widget.Toast;
|
|
16
39
|
import android.widget.Toolbar;
|
|
40
|
+
import androidx.annotation.RequiresApi;
|
|
41
|
+
import androidx.core.view.WindowInsetsControllerCompat;
|
|
42
|
+
import com.caverock.androidsvg.SVG;
|
|
43
|
+
import com.caverock.androidsvg.SVGParseException;
|
|
44
|
+
import com.getcapacitor.JSObject;
|
|
45
|
+
import java.io.ByteArrayInputStream;
|
|
46
|
+
import java.io.IOException;
|
|
47
|
+
import java.io.InputStream;
|
|
48
|
+
import java.net.CookiePolicy;
|
|
17
49
|
import java.net.URI;
|
|
18
50
|
import java.net.URISyntaxException;
|
|
51
|
+
import java.net.URL;
|
|
52
|
+
import java.nio.charset.StandardCharsets;
|
|
53
|
+
import java.util.Arrays;
|
|
19
54
|
import java.util.HashMap;
|
|
20
55
|
import java.util.Iterator;
|
|
56
|
+
import java.util.List;
|
|
21
57
|
import java.util.Map;
|
|
58
|
+
import java.util.Objects;
|
|
59
|
+
import java.util.UUID;
|
|
60
|
+
import java.util.concurrent.ExecutorService;
|
|
61
|
+
import java.util.concurrent.Executors;
|
|
62
|
+
import java.util.concurrent.Semaphore;
|
|
63
|
+
import java.util.concurrent.TimeUnit;
|
|
64
|
+
import java.util.function.Consumer;
|
|
65
|
+
import java.util.regex.Matcher;
|
|
66
|
+
import java.util.regex.Pattern;
|
|
67
|
+
import org.json.JSONException;
|
|
68
|
+
import org.json.JSONObject;
|
|
22
69
|
|
|
23
70
|
public class WebViewDialog extends Dialog {
|
|
24
71
|
|
|
72
|
+
private class ProxiedRequest {
|
|
73
|
+
|
|
74
|
+
private WebResourceResponse response;
|
|
75
|
+
private Semaphore semaphore;
|
|
76
|
+
|
|
77
|
+
public WebResourceResponse getResponse() {
|
|
78
|
+
return response;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public ProxiedRequest() {
|
|
82
|
+
this.semaphore = new Semaphore(0);
|
|
83
|
+
this.response = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
25
87
|
private WebView _webView;
|
|
26
88
|
private Toolbar _toolbar;
|
|
27
89
|
private Options _options;
|
|
90
|
+
private Context _context;
|
|
91
|
+
public Activity activity;
|
|
28
92
|
private boolean isInitialized = false;
|
|
93
|
+
private WebView capacitorWebView;
|
|
94
|
+
private HashMap<String, ProxiedRequest> proxiedRequestsHashmap;
|
|
95
|
+
|
|
96
|
+
Semaphore preShowSemaphore = null;
|
|
97
|
+
String preshowError = null;
|
|
98
|
+
|
|
99
|
+
public PermissionRequest currentPermissionRequest;
|
|
100
|
+
public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
|
|
101
|
+
public ValueCallback<Uri> mUploadMessage;
|
|
102
|
+
public ValueCallback<Uri[]> mFilePathCallback;
|
|
103
|
+
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
|
104
|
+
|
|
105
|
+
public interface PermissionHandler {
|
|
106
|
+
void handleCameraPermissionRequest(PermissionRequest request);
|
|
107
|
+
|
|
108
|
+
void handleMicrophonePermissionRequest(PermissionRequest request);
|
|
109
|
+
}
|
|
29
110
|
|
|
30
|
-
|
|
111
|
+
private PermissionHandler permissionHandler;
|
|
112
|
+
|
|
113
|
+
public WebViewDialog(
|
|
114
|
+
Context context,
|
|
115
|
+
int theme,
|
|
116
|
+
Options options,
|
|
117
|
+
PermissionHandler permissionHandler,
|
|
118
|
+
WebView capacitorWebView
|
|
119
|
+
) {
|
|
31
120
|
super(context, theme);
|
|
32
121
|
this._options = options;
|
|
122
|
+
this._context = context;
|
|
123
|
+
this.permissionHandler = permissionHandler;
|
|
33
124
|
this.isInitialized = false;
|
|
125
|
+
this.capacitorWebView = capacitorWebView;
|
|
126
|
+
this.proxiedRequestsHashmap = new HashMap<>();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public class JavaScriptInterface {
|
|
130
|
+
|
|
131
|
+
@JavascriptInterface
|
|
132
|
+
public void postMessage(String message) {
|
|
133
|
+
// Handle message from JavaScript
|
|
134
|
+
_options.getCallbacks().javascriptCallback(message);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public class PreShowScriptInterface {
|
|
139
|
+
|
|
140
|
+
@JavascriptInterface
|
|
141
|
+
public void error(String error) {
|
|
142
|
+
// Handle message from JavaScript
|
|
143
|
+
if (preShowSemaphore != null) {
|
|
144
|
+
preshowError = error;
|
|
145
|
+
preShowSemaphore.release();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@JavascriptInterface
|
|
150
|
+
public void success() {
|
|
151
|
+
// Handle message from JavaScript
|
|
152
|
+
if (preShowSemaphore != null) {
|
|
153
|
+
preShowSemaphore.release();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
34
156
|
}
|
|
35
157
|
|
|
158
|
+
@SuppressLint("SetJavaScriptEnabled")
|
|
36
159
|
public void presentWebView() {
|
|
37
160
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
38
161
|
setCancelable(true);
|
|
39
|
-
getWindow()
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
162
|
+
Objects.requireNonNull(getWindow()).setFlags(
|
|
163
|
+
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
|
164
|
+
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
|
165
|
+
);
|
|
44
166
|
setContentView(R.layout.activity_browser);
|
|
167
|
+
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
168
|
+
|
|
169
|
+
WindowInsetsControllerCompat insetsController =
|
|
170
|
+
new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());
|
|
171
|
+
insetsController.setAppearanceLightStatusBars(false);
|
|
172
|
+
getWindow()
|
|
173
|
+
.getDecorView()
|
|
174
|
+
.post(() -> {
|
|
175
|
+
getWindow().setStatusBarColor(Color.BLACK);
|
|
176
|
+
});
|
|
177
|
+
|
|
45
178
|
getWindow()
|
|
46
179
|
.setLayout(
|
|
47
180
|
WindowManager.LayoutParams.MATCH_PARENT,
|
|
@@ -49,23 +182,104 @@ public class WebViewDialog extends Dialog {
|
|
|
49
182
|
);
|
|
50
183
|
|
|
51
184
|
this._webView = findViewById(R.id.browser_view);
|
|
52
|
-
|
|
185
|
+
_webView.addJavascriptInterface(
|
|
186
|
+
new JavaScriptInterface(),
|
|
187
|
+
"AndroidInterface"
|
|
188
|
+
);
|
|
189
|
+
_webView.addJavascriptInterface(
|
|
190
|
+
new PreShowScriptInterface(),
|
|
191
|
+
"PreShowScriptInterface"
|
|
192
|
+
);
|
|
53
193
|
_webView.getSettings().setJavaScriptEnabled(true);
|
|
54
194
|
_webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
|
|
55
195
|
_webView.getSettings().setDatabaseEnabled(true);
|
|
56
196
|
_webView.getSettings().setDomStorageEnabled(true);
|
|
197
|
+
_webView.getSettings().setAllowFileAccess(true);
|
|
57
198
|
_webView
|
|
58
199
|
.getSettings()
|
|
59
200
|
.setPluginState(android.webkit.WebSettings.PluginState.ON);
|
|
60
201
|
_webView.getSettings().setLoadWithOverviewMode(true);
|
|
61
202
|
_webView.getSettings().setUseWideViewPort(true);
|
|
203
|
+
_webView.getSettings().setAllowFileAccessFromFileURLs(true);
|
|
204
|
+
_webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
|
|
205
|
+
_webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
|
|
206
|
+
|
|
207
|
+
_webView.setWebViewClient(new WebViewClient());
|
|
208
|
+
|
|
209
|
+
_webView.setWebChromeClient(
|
|
210
|
+
new WebChromeClient() {
|
|
211
|
+
// Enable file open dialog
|
|
212
|
+
@Override
|
|
213
|
+
public boolean onShowFileChooser(
|
|
214
|
+
WebView webView,
|
|
215
|
+
ValueCallback<Uri[]> filePathCallback,
|
|
216
|
+
WebChromeClient.FileChooserParams fileChooserParams
|
|
217
|
+
) {
|
|
218
|
+
openFileChooser(
|
|
219
|
+
filePathCallback,
|
|
220
|
+
fileChooserParams.getAcceptTypes()[0],
|
|
221
|
+
fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE
|
|
222
|
+
);
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Grant permissions for cam
|
|
227
|
+
@Override
|
|
228
|
+
public void onPermissionRequest(final PermissionRequest request) {
|
|
229
|
+
Log.i(
|
|
230
|
+
"INAPPBROWSER",
|
|
231
|
+
"onPermissionRequest " + Arrays.toString(request.getResources())
|
|
232
|
+
);
|
|
233
|
+
final String[] requestedResources = request.getResources();
|
|
234
|
+
for (String r : requestedResources) {
|
|
235
|
+
Log.i("INAPPBROWSER", "requestedResources " + r);
|
|
236
|
+
if (r.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
|
|
237
|
+
Log.i("INAPPBROWSER", "RESOURCE_VIDEO_CAPTURE req");
|
|
238
|
+
// Store the permission request
|
|
239
|
+
currentPermissionRequest = request;
|
|
240
|
+
// Initiate the permission request through the plugin
|
|
241
|
+
if (permissionHandler != null) {
|
|
242
|
+
permissionHandler.handleCameraPermissionRequest(request);
|
|
243
|
+
}
|
|
244
|
+
return; // Return here to avoid denying the request
|
|
245
|
+
} else if (r.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) {
|
|
246
|
+
Log.i("INAPPBROWSER", "RESOURCE_AUDIO_CAPTURE req");
|
|
247
|
+
// Store the permission request
|
|
248
|
+
currentPermissionRequest = request;
|
|
249
|
+
// Initiate the permission request through the plugin
|
|
250
|
+
if (permissionHandler != null) {
|
|
251
|
+
permissionHandler.handleMicrophonePermissionRequest(request);
|
|
252
|
+
}
|
|
253
|
+
return; // Return here to avoid denying the request
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// If no matching permission is found, deny the request
|
|
257
|
+
request.deny();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@Override
|
|
261
|
+
public void onPermissionRequestCanceled(PermissionRequest request) {
|
|
262
|
+
super.onPermissionRequestCanceled(request);
|
|
263
|
+
Toast.makeText(
|
|
264
|
+
WebViewDialog.this.activity,
|
|
265
|
+
"Permission Denied",
|
|
266
|
+
Toast.LENGTH_SHORT
|
|
267
|
+
).show();
|
|
268
|
+
// Handle the denied permission
|
|
269
|
+
if (currentPermissionRequest != null) {
|
|
270
|
+
currentPermissionRequest.deny();
|
|
271
|
+
currentPermissionRequest = null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
);
|
|
62
276
|
|
|
63
277
|
Map<String, String> requestHeaders = new HashMap<>();
|
|
64
278
|
if (_options.getHeaders() != null) {
|
|
65
279
|
Iterator<String> keys = _options.getHeaders().keys();
|
|
66
280
|
while (keys.hasNext()) {
|
|
67
281
|
String key = keys.next();
|
|
68
|
-
if (TextUtils.equals(key, "
|
|
282
|
+
if (TextUtils.equals(key.toLowerCase(), "user-agent")) {
|
|
69
283
|
_webView
|
|
70
284
|
.getSettings()
|
|
71
285
|
.setUserAgentString(_options.getHeaders().getString(key));
|
|
@@ -88,13 +302,134 @@ public class WebViewDialog extends Dialog {
|
|
|
88
302
|
}
|
|
89
303
|
}
|
|
90
304
|
|
|
305
|
+
public void postMessageToJS(Object detail) {
|
|
306
|
+
if (_webView != null) {
|
|
307
|
+
try {
|
|
308
|
+
JSONObject jsonObject = new JSONObject();
|
|
309
|
+
jsonObject.put("detail", detail);
|
|
310
|
+
String jsonDetail = jsonObject.toString();
|
|
311
|
+
String script =
|
|
312
|
+
"window.dispatchEvent(new CustomEvent('messageFromNative', " +
|
|
313
|
+
jsonDetail +
|
|
314
|
+
"));";
|
|
315
|
+
_webView.post(() -> _webView.evaluateJavascript(script, null));
|
|
316
|
+
} catch (Exception e) {
|
|
317
|
+
Log.e(
|
|
318
|
+
"postMessageToJS",
|
|
319
|
+
"Error sending message to JS: " + e.getMessage()
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private void injectJavaScriptInterface() {
|
|
326
|
+
String script =
|
|
327
|
+
"if (!window.mobileApp) { " +
|
|
328
|
+
" window.mobileApp = { " +
|
|
329
|
+
" postMessage: function(message) { " +
|
|
330
|
+
" if (window.AndroidInterface) { " +
|
|
331
|
+
" window.AndroidInterface.postMessage(JSON.stringify(message)); " +
|
|
332
|
+
" } " +
|
|
333
|
+
" } " +
|
|
334
|
+
" }; " +
|
|
335
|
+
"}";
|
|
336
|
+
_webView.evaluateJavascript(script, null);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private void injectPreShowScript() {
|
|
340
|
+
// String script =
|
|
341
|
+
// "import('https://unpkg.com/darkreader@4.9.89/darkreader.js').then(() => {DarkReader.enable({ brightness: 100, contrast: 90, sepia: 10 });window.PreLoadScriptInterface.finished()})";
|
|
342
|
+
|
|
343
|
+
if (preShowSemaphore != null) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
String script =
|
|
348
|
+
"async function preShowFunction() {\n" +
|
|
349
|
+
_options.getPreShowScript() +
|
|
350
|
+
'\n' +
|
|
351
|
+
"};\n" +
|
|
352
|
+
"preShowFunction().then(() => window.PreShowScriptInterface.success()).catch(err => { console.error('Preshow error', err); window.PreShowScriptInterface.error(JSON.stringify(err, Object.getOwnPropertyNames(err))) })";
|
|
353
|
+
|
|
354
|
+
Log.i(
|
|
355
|
+
"InjectPreShowScript",
|
|
356
|
+
String.format("PreShowScript script:\n%s", script)
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
preShowSemaphore = new Semaphore(0);
|
|
360
|
+
activity.runOnUiThread(
|
|
361
|
+
new Runnable() {
|
|
362
|
+
@Override
|
|
363
|
+
public void run() {
|
|
364
|
+
_webView.evaluateJavascript(script, null);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
if (!preShowSemaphore.tryAcquire(10, TimeUnit.SECONDS)) {
|
|
371
|
+
Log.e(
|
|
372
|
+
"InjectPreShowScript",
|
|
373
|
+
"PreShowScript running for over 10 seconds. The plugin will not wait any longer!"
|
|
374
|
+
);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (preshowError != null && !preshowError.isEmpty()) {
|
|
378
|
+
Log.e(
|
|
379
|
+
"InjectPreShowScript",
|
|
380
|
+
"Error within the user-provided preShowFunction: " + preshowError
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
} catch (InterruptedException e) {
|
|
384
|
+
Log.e(
|
|
385
|
+
"InjectPreShowScript",
|
|
386
|
+
"Error when calling InjectPreShowScript: " + e.getMessage()
|
|
387
|
+
);
|
|
388
|
+
} finally {
|
|
389
|
+
preShowSemaphore = null;
|
|
390
|
+
preshowError = null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private void openFileChooser(
|
|
395
|
+
ValueCallback<Uri[]> filePathCallback,
|
|
396
|
+
String acceptType,
|
|
397
|
+
boolean isMultiple
|
|
398
|
+
) {
|
|
399
|
+
mFilePathCallback = filePathCallback;
|
|
400
|
+
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
401
|
+
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
402
|
+
intent.setType(acceptType); // Default to */*
|
|
403
|
+
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultiple);
|
|
404
|
+
activity.startActivityForResult(
|
|
405
|
+
Intent.createChooser(intent, "Select File"),
|
|
406
|
+
FILE_CHOOSER_REQUEST_CODE
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
public void reload() {
|
|
411
|
+
_webView.reload();
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
public void destroy() {
|
|
415
|
+
_webView.destroy();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
public String getUrl() {
|
|
419
|
+
return _webView.getUrl();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public void executeScript(String script) {
|
|
423
|
+
_webView.evaluateJavascript(script, null);
|
|
424
|
+
}
|
|
425
|
+
|
|
91
426
|
public void setUrl(String url) {
|
|
92
427
|
Map<String, String> requestHeaders = new HashMap<>();
|
|
93
428
|
if (_options.getHeaders() != null) {
|
|
94
429
|
Iterator<String> keys = _options.getHeaders().keys();
|
|
95
430
|
while (keys.hasNext()) {
|
|
96
431
|
String key = keys.next();
|
|
97
|
-
if (TextUtils.equals(key, "
|
|
432
|
+
if (TextUtils.equals(key.toLowerCase(), "user-agent")) {
|
|
98
433
|
_webView
|
|
99
434
|
.getSettings()
|
|
100
435
|
.setUserAgentString(_options.getHeaders().getString(key));
|
|
@@ -108,11 +443,27 @@ public class WebViewDialog extends Dialog {
|
|
|
108
443
|
|
|
109
444
|
private void setTitle(String newTitleText) {
|
|
110
445
|
TextView textView = (TextView) _toolbar.findViewById(R.id.titleText);
|
|
111
|
-
|
|
446
|
+
if (_options.getVisibleTitle()) {
|
|
447
|
+
textView.setText(newTitleText);
|
|
448
|
+
} else {
|
|
449
|
+
textView.setText("");
|
|
450
|
+
}
|
|
112
451
|
}
|
|
113
452
|
|
|
114
453
|
private void setupToolbar() {
|
|
115
454
|
_toolbar = this.findViewById(R.id.tool_bar);
|
|
455
|
+
int color = Color.parseColor("#ffffff");
|
|
456
|
+
try {
|
|
457
|
+
color = Color.parseColor(_options.getToolbarColor());
|
|
458
|
+
} catch (IllegalArgumentException e) {
|
|
459
|
+
// Do nothing
|
|
460
|
+
}
|
|
461
|
+
_toolbar.setBackgroundColor(color);
|
|
462
|
+
_toolbar.findViewById(R.id.backButton).setBackgroundColor(color);
|
|
463
|
+
_toolbar.findViewById(R.id.forwardButton).setBackgroundColor(color);
|
|
464
|
+
_toolbar.findViewById(R.id.closeButton).setBackgroundColor(color);
|
|
465
|
+
_toolbar.findViewById(R.id.reloadButton).setBackgroundColor(color);
|
|
466
|
+
|
|
116
467
|
if (!TextUtils.isEmpty(_options.getTitle())) {
|
|
117
468
|
this.setTitle(_options.getTitle());
|
|
118
469
|
} else {
|
|
@@ -148,29 +499,203 @@ public class WebViewDialog extends Dialog {
|
|
|
148
499
|
}
|
|
149
500
|
);
|
|
150
501
|
|
|
151
|
-
|
|
502
|
+
ImageButton closeButton = _toolbar.findViewById(R.id.closeButton);
|
|
152
503
|
closeButton.setOnClickListener(
|
|
153
504
|
new View.OnClickListener() {
|
|
154
505
|
@Override
|
|
155
506
|
public void onClick(View view) {
|
|
156
|
-
|
|
157
|
-
_options.
|
|
507
|
+
// if closeModal true then display a native modal to check if the user is sure to close the browser
|
|
508
|
+
if (_options.getCloseModal()) {
|
|
509
|
+
new AlertDialog.Builder(_context)
|
|
510
|
+
.setTitle(_options.getCloseModalTitle())
|
|
511
|
+
.setMessage(_options.getCloseModalDescription())
|
|
512
|
+
.setPositiveButton(
|
|
513
|
+
_options.getCloseModalOk(),
|
|
514
|
+
new DialogInterface.OnClickListener() {
|
|
515
|
+
public void onClick(DialogInterface dialog, int which) {
|
|
516
|
+
// Close button clicked, do something
|
|
517
|
+
dismiss();
|
|
518
|
+
_options.getCallbacks().closeEvent(_webView.getUrl());
|
|
519
|
+
_webView.destroy();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
.setNegativeButton(_options.getCloseModalCancel(), null)
|
|
524
|
+
.show();
|
|
525
|
+
} else {
|
|
526
|
+
dismiss();
|
|
527
|
+
_options.getCallbacks().closeEvent(_webView.getUrl());
|
|
528
|
+
_webView.destroy();
|
|
529
|
+
}
|
|
158
530
|
}
|
|
159
531
|
}
|
|
160
532
|
);
|
|
161
533
|
|
|
534
|
+
if (_options.showArrow()) {
|
|
535
|
+
closeButton.setImageResource(R.drawable.arrow_back_enabled);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (_options.getShowReloadButton()) {
|
|
539
|
+
View reloadButton = _toolbar.findViewById(R.id.reloadButton);
|
|
540
|
+
reloadButton.setVisibility(View.VISIBLE);
|
|
541
|
+
reloadButton.setOnClickListener(
|
|
542
|
+
new View.OnClickListener() {
|
|
543
|
+
@Override
|
|
544
|
+
public void onClick(View view) {
|
|
545
|
+
_webView.reload();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
162
551
|
if (TextUtils.equals(_options.getToolbarType(), "activity")) {
|
|
163
552
|
_toolbar.findViewById(R.id.forwardButton).setVisibility(View.GONE);
|
|
164
553
|
_toolbar.findViewById(R.id.backButton).setVisibility(View.GONE);
|
|
554
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
555
|
+
R.id.buttonNearDone
|
|
556
|
+
);
|
|
557
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
165
558
|
//TODO: Add share button functionality
|
|
166
559
|
} else if (TextUtils.equals(_options.getToolbarType(), "navigation")) {
|
|
560
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
561
|
+
R.id.buttonNearDone
|
|
562
|
+
);
|
|
563
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
167
564
|
//TODO: Remove share button when implemented
|
|
168
565
|
} else if (TextUtils.equals(_options.getToolbarType(), "blank")) {
|
|
169
566
|
_toolbar.setVisibility(View.GONE);
|
|
170
567
|
} else {
|
|
171
568
|
_toolbar.findViewById(R.id.forwardButton).setVisibility(View.GONE);
|
|
172
569
|
_toolbar.findViewById(R.id.backButton).setVisibility(View.GONE);
|
|
570
|
+
|
|
571
|
+
Options.ButtonNearDone buttonNearDone = _options.getButtonNearDone();
|
|
572
|
+
if (buttonNearDone != null) {
|
|
573
|
+
AssetManager assetManager = _context.getAssets();
|
|
574
|
+
|
|
575
|
+
// Open the SVG file from assets
|
|
576
|
+
InputStream inputStream = null;
|
|
577
|
+
try {
|
|
578
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
579
|
+
R.id.buttonNearDone
|
|
580
|
+
);
|
|
581
|
+
buttonNearDoneView.setVisibility(View.VISIBLE);
|
|
582
|
+
|
|
583
|
+
inputStream = assetManager.open(buttonNearDone.getIcon());
|
|
584
|
+
|
|
585
|
+
SVG svg = SVG.getFromInputStream(inputStream);
|
|
586
|
+
Picture picture = svg.renderToPicture(
|
|
587
|
+
buttonNearDone.getWidth(),
|
|
588
|
+
buttonNearDone.getHeight()
|
|
589
|
+
);
|
|
590
|
+
PictureDrawable pictureDrawable = new PictureDrawable(picture);
|
|
591
|
+
|
|
592
|
+
buttonNearDoneView.setImageDrawable(pictureDrawable);
|
|
593
|
+
buttonNearDoneView.setOnClickListener(view ->
|
|
594
|
+
_options.getCallbacks().buttonNearDoneClicked()
|
|
595
|
+
);
|
|
596
|
+
} catch (IOException | SVGParseException e) {
|
|
597
|
+
throw new RuntimeException(e);
|
|
598
|
+
} finally {
|
|
599
|
+
if (inputStream != null) {
|
|
600
|
+
try {
|
|
601
|
+
inputStream.close();
|
|
602
|
+
} catch (IOException e) {
|
|
603
|
+
throw new RuntimeException(e);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
} else {
|
|
608
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
609
|
+
R.id.buttonNearDone
|
|
610
|
+
);
|
|
611
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
public void handleProxyResultError(String result, String id) {
|
|
617
|
+
Log.i(
|
|
618
|
+
"InAppBrowserProxy",
|
|
619
|
+
String.format(
|
|
620
|
+
"handleProxyResultError: %s, ok: %s id: %s",
|
|
621
|
+
result,
|
|
622
|
+
false,
|
|
623
|
+
id
|
|
624
|
+
)
|
|
625
|
+
);
|
|
626
|
+
ProxiedRequest proxiedRequest = proxiedRequestsHashmap.get(id);
|
|
627
|
+
if (proxiedRequest == null) {
|
|
628
|
+
Log.e("InAppBrowserProxy", "proxiedRequest is null");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
proxiedRequestsHashmap.remove(id);
|
|
632
|
+
proxiedRequest.semaphore.release();
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
public void handleProxyResultOk(JSONObject result, String id) {
|
|
636
|
+
Log.i(
|
|
637
|
+
"InAppBrowserProxy",
|
|
638
|
+
String.format("handleProxyResultOk: %s, ok: %s, id: %s", result, true, id)
|
|
639
|
+
);
|
|
640
|
+
ProxiedRequest proxiedRequest = proxiedRequestsHashmap.get(id);
|
|
641
|
+
if (proxiedRequest == null) {
|
|
642
|
+
Log.e("InAppBrowserProxy", "proxiedRequest is null");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
proxiedRequestsHashmap.remove(id);
|
|
646
|
+
|
|
647
|
+
if (result == null) {
|
|
648
|
+
proxiedRequest.semaphore.release();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
Map<String, String> responseHeaders = new HashMap<>();
|
|
653
|
+
String body;
|
|
654
|
+
int code;
|
|
655
|
+
|
|
656
|
+
try {
|
|
657
|
+
body = result.getString("body");
|
|
658
|
+
code = result.getInt("code");
|
|
659
|
+
JSONObject headers = result.getJSONObject("headers");
|
|
660
|
+
for (Iterator<String> it = headers.keys(); it.hasNext();) {
|
|
661
|
+
String headerName = it.next();
|
|
662
|
+
String header = headers.getString(headerName);
|
|
663
|
+
responseHeaders.put(headerName, header);
|
|
664
|
+
}
|
|
665
|
+
} catch (JSONException e) {
|
|
666
|
+
Log.e("InAppBrowserProxy", "Cannot parse OK result", e);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
String contentType = responseHeaders.get("Content-Type");
|
|
671
|
+
if (contentType == null) {
|
|
672
|
+
contentType = responseHeaders.get("content-type");
|
|
673
|
+
}
|
|
674
|
+
if (contentType == null) {
|
|
675
|
+
Log.e("InAppBrowserProxy", "'Content-Type' header is required");
|
|
676
|
+
return;
|
|
173
677
|
}
|
|
678
|
+
|
|
679
|
+
if (!((100 <= code && code <= 299) || (400 <= code && code <= 599))) {
|
|
680
|
+
Log.e(
|
|
681
|
+
"InAppBrowserProxy",
|
|
682
|
+
String.format("Status code %s outside of the allowed range", code)
|
|
683
|
+
);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
WebResourceResponse webResourceResponse = new WebResourceResponse(
|
|
688
|
+
contentType,
|
|
689
|
+
"utf-8",
|
|
690
|
+
new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8))
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
webResourceResponse.setStatusCodeAndReasonPhrase(
|
|
694
|
+
code,
|
|
695
|
+
getReasonPhrase(code)
|
|
696
|
+
);
|
|
697
|
+
proxiedRequest.response = webResourceResponse;
|
|
698
|
+
proxiedRequest.semaphore.release();
|
|
174
699
|
}
|
|
175
700
|
|
|
176
701
|
private void setWebViewClient() {
|
|
@@ -181,9 +706,199 @@ public class WebViewDialog extends Dialog {
|
|
|
181
706
|
WebView view,
|
|
182
707
|
WebResourceRequest request
|
|
183
708
|
) {
|
|
709
|
+
// HashMap<String, String> map = new HashMap<>();
|
|
710
|
+
// map.put("x-requested-with", null);
|
|
711
|
+
// view.loadUrl(request.getUrl().toString(), map);
|
|
712
|
+
Context context = view.getContext();
|
|
713
|
+
String url = request.getUrl().toString();
|
|
714
|
+
|
|
715
|
+
if (!url.startsWith("https://") && !url.startsWith("http://")) {
|
|
716
|
+
try {
|
|
717
|
+
Intent intent;
|
|
718
|
+
if (url.startsWith("intent://")) {
|
|
719
|
+
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
|
|
720
|
+
} else {
|
|
721
|
+
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
725
|
+
context.startActivity(intent);
|
|
726
|
+
return true;
|
|
727
|
+
} catch (ActivityNotFoundException e) {
|
|
728
|
+
// Do nothing
|
|
729
|
+
} catch (URISyntaxException e) {
|
|
730
|
+
// Do nothing
|
|
731
|
+
}
|
|
732
|
+
}
|
|
184
733
|
return false;
|
|
185
734
|
}
|
|
186
735
|
|
|
736
|
+
private String randomRequestId() {
|
|
737
|
+
return UUID.randomUUID().toString();
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
private String toBase64(String raw) {
|
|
741
|
+
String s = Base64.encodeToString(raw.getBytes(), Base64.NO_WRAP);
|
|
742
|
+
if (s.endsWith("=")) {
|
|
743
|
+
s = s.substring(0, s.length() - 2);
|
|
744
|
+
}
|
|
745
|
+
return s;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
//
|
|
749
|
+
// void handleRedirect(String currentUrl, Response response) {
|
|
750
|
+
// String loc = response.header("Location");
|
|
751
|
+
// _webView.evaluateJavascript("");
|
|
752
|
+
// }
|
|
753
|
+
//
|
|
754
|
+
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
|
755
|
+
@Override
|
|
756
|
+
public WebResourceResponse shouldInterceptRequest(
|
|
757
|
+
WebView view,
|
|
758
|
+
WebResourceRequest request
|
|
759
|
+
) {
|
|
760
|
+
Pattern pattern = _options.getProxyRequestsPattern();
|
|
761
|
+
if (pattern == null) {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
Matcher matcher = pattern.matcher(request.getUrl().toString());
|
|
765
|
+
if (!matcher.find()) {
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Requests matches the regex
|
|
770
|
+
if (Objects.equals(request.getMethod(), "POST")) {
|
|
771
|
+
// Log.e("HTTP", String.format("returned null (ok) %s", request.getUrl().toString()));
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
Log.i(
|
|
776
|
+
"InAppBrowserProxy",
|
|
777
|
+
String.format("Proxying request: %s", request.getUrl().toString())
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
// We need to call a JS function
|
|
781
|
+
String requestId = randomRequestId();
|
|
782
|
+
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
783
|
+
proxiedRequestsHashmap.put(requestId, proxiedRequest);
|
|
784
|
+
|
|
785
|
+
// lsuakdchgbbaHandleProxiedRequest
|
|
786
|
+
activity.runOnUiThread(
|
|
787
|
+
new Runnable() {
|
|
788
|
+
@Override
|
|
789
|
+
public void run() {
|
|
790
|
+
StringBuilder headers = new StringBuilder();
|
|
791
|
+
Map<String, String> requestHeaders =
|
|
792
|
+
request.getRequestHeaders();
|
|
793
|
+
for (Map.Entry<
|
|
794
|
+
String,
|
|
795
|
+
String
|
|
796
|
+
> header : requestHeaders.entrySet()) {
|
|
797
|
+
headers.append(
|
|
798
|
+
String.format(
|
|
799
|
+
"h[atob('%s')]=atob('%s');",
|
|
800
|
+
toBase64(header.getKey()),
|
|
801
|
+
toBase64(header.getValue())
|
|
802
|
+
)
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
String s = String.format(
|
|
806
|
+
"try {function getHeaders() {const h = {}; %s return h}; window.InAppBrowserProxyRequest(new Request(atob('%s'), {headers: getHeaders(), method: '%s'})).then(async (res) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: true, result: (!!res ? {headers: Object.fromEntries(res.headers.entries()), code: res.status, body: (await res.text())} : null), id: '%s'})).catch((e) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: false, result: e.toString(), id: '%s'}))} catch (e) {Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: false, result: e.toString(), id: '%s'})}",
|
|
807
|
+
headers,
|
|
808
|
+
toBase64(request.getUrl().toString()),
|
|
809
|
+
request.getMethod(),
|
|
810
|
+
requestId,
|
|
811
|
+
requestId,
|
|
812
|
+
requestId
|
|
813
|
+
);
|
|
814
|
+
// Log.i("HTTP", s);
|
|
815
|
+
capacitorWebView.evaluateJavascript(s, null);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
// 10 seconds wait max
|
|
821
|
+
try {
|
|
822
|
+
if (proxiedRequest.semaphore.tryAcquire(1, 10, TimeUnit.SECONDS)) {
|
|
823
|
+
return proxiedRequest.response;
|
|
824
|
+
} else {
|
|
825
|
+
Log.e("InAppBrowserProxy", "Semaphore timed out");
|
|
826
|
+
proxiedRequestsHashmap.remove(requestId); // prevent mem leak
|
|
827
|
+
}
|
|
828
|
+
} catch (InterruptedException e) {
|
|
829
|
+
Log.e("InAppBrowserProxy", "Semaphore wait error", e);
|
|
830
|
+
}
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
@Override
|
|
835
|
+
public void onReceivedHttpAuthRequest(
|
|
836
|
+
WebView view,
|
|
837
|
+
HttpAuthHandler handler,
|
|
838
|
+
String host,
|
|
839
|
+
String realm
|
|
840
|
+
) {
|
|
841
|
+
final String sourceUrl = _options.getUrl();
|
|
842
|
+
final String url = view.getUrl();
|
|
843
|
+
final JSObject credentials = _options.getCredentials();
|
|
844
|
+
|
|
845
|
+
if (
|
|
846
|
+
credentials != null &&
|
|
847
|
+
credentials.getString("username") != null &&
|
|
848
|
+
credentials.getString("password") != null &&
|
|
849
|
+
sourceUrl != null &&
|
|
850
|
+
url != null
|
|
851
|
+
) {
|
|
852
|
+
String sourceProtocol = "";
|
|
853
|
+
String sourceHost = "";
|
|
854
|
+
int sourcePort = -1;
|
|
855
|
+
try {
|
|
856
|
+
URI uri = new URI(sourceUrl);
|
|
857
|
+
sourceProtocol = uri.getScheme();
|
|
858
|
+
sourceHost = uri.getHost();
|
|
859
|
+
sourcePort = uri.getPort();
|
|
860
|
+
if (
|
|
861
|
+
sourcePort == -1 && Objects.equals(sourceProtocol, "https")
|
|
862
|
+
) sourcePort = 443;
|
|
863
|
+
else if (
|
|
864
|
+
sourcePort == -1 && Objects.equals(sourceProtocol, "http")
|
|
865
|
+
) sourcePort = 80;
|
|
866
|
+
} catch (URISyntaxException e) {
|
|
867
|
+
e.printStackTrace();
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
String protocol = "";
|
|
871
|
+
int port = -1;
|
|
872
|
+
try {
|
|
873
|
+
URI uri = new URI(url);
|
|
874
|
+
protocol = uri.getScheme();
|
|
875
|
+
port = uri.getPort();
|
|
876
|
+
if (port == -1 && Objects.equals(protocol, "https")) port = 443;
|
|
877
|
+
else if (port == -1 && Objects.equals(protocol, "http")) port =
|
|
878
|
+
80;
|
|
879
|
+
} catch (URISyntaxException e) {
|
|
880
|
+
e.printStackTrace();
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (
|
|
884
|
+
Objects.equals(sourceHost, host) &&
|
|
885
|
+
Objects.equals(sourceProtocol, protocol) &&
|
|
886
|
+
sourcePort == port
|
|
887
|
+
) {
|
|
888
|
+
final String username = Objects.requireNonNull(
|
|
889
|
+
credentials.getString("username")
|
|
890
|
+
);
|
|
891
|
+
final String password = Objects.requireNonNull(
|
|
892
|
+
credentials.getString("password")
|
|
893
|
+
);
|
|
894
|
+
handler.proceed(username, password);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
super.onReceivedHttpAuthRequest(view, handler, host, realm);
|
|
900
|
+
}
|
|
901
|
+
|
|
187
902
|
@Override
|
|
188
903
|
public void onLoadResource(WebView view, String url) {
|
|
189
904
|
super.onLoadResource(view, url);
|
|
@@ -194,24 +909,77 @@ public class WebViewDialog extends Dialog {
|
|
|
194
909
|
super.onPageStarted(view, url, favicon);
|
|
195
910
|
try {
|
|
196
911
|
URI uri = new URI(url);
|
|
197
|
-
|
|
912
|
+
if (TextUtils.isEmpty(_options.getTitle())) {
|
|
913
|
+
setTitle(uri.getHost());
|
|
914
|
+
}
|
|
198
915
|
} catch (URISyntaxException e) {
|
|
199
916
|
// Do nothing
|
|
200
917
|
}
|
|
201
|
-
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
public void doUpdateVisitedHistory(
|
|
921
|
+
WebView view,
|
|
922
|
+
String url,
|
|
923
|
+
boolean isReload
|
|
924
|
+
) {
|
|
925
|
+
if (!isReload) {
|
|
926
|
+
_options.getCallbacks().urlChangeEvent(url);
|
|
927
|
+
}
|
|
928
|
+
super.doUpdateVisitedHistory(view, url, isReload);
|
|
929
|
+
injectJavaScriptInterface();
|
|
202
930
|
}
|
|
203
931
|
|
|
204
932
|
@Override
|
|
205
933
|
public void onPageFinished(WebView view, String url) {
|
|
206
934
|
super.onPageFinished(view, url);
|
|
207
|
-
_options.getCallbacks().pageLoaded();
|
|
208
935
|
if (!isInitialized) {
|
|
209
936
|
isInitialized = true;
|
|
210
937
|
_webView.clearHistory();
|
|
211
938
|
if (_options.isPresentAfterPageLoad()) {
|
|
212
|
-
|
|
213
|
-
|
|
939
|
+
boolean usePreShowScript =
|
|
940
|
+
_options.getPreShowScript() != null &&
|
|
941
|
+
!_options.getPreShowScript().isEmpty();
|
|
942
|
+
if (!usePreShowScript) {
|
|
943
|
+
show();
|
|
944
|
+
_options.getPluginCall().resolve();
|
|
945
|
+
} else {
|
|
946
|
+
executorService.execute(
|
|
947
|
+
new Runnable() {
|
|
948
|
+
@Override
|
|
949
|
+
public void run() {
|
|
950
|
+
if (
|
|
951
|
+
_options.getPreShowScript() != null &&
|
|
952
|
+
!_options.getPreShowScript().isEmpty()
|
|
953
|
+
) {
|
|
954
|
+
injectPreShowScript();
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
activity.runOnUiThread(
|
|
958
|
+
new Runnable() {
|
|
959
|
+
@Override
|
|
960
|
+
public void run() {
|
|
961
|
+
show();
|
|
962
|
+
_options.getPluginCall().resolve();
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
);
|
|
969
|
+
}
|
|
214
970
|
}
|
|
971
|
+
} else if (
|
|
972
|
+
_options.getPreShowScript() != null &&
|
|
973
|
+
!_options.getPreShowScript().isEmpty()
|
|
974
|
+
) {
|
|
975
|
+
executorService.execute(
|
|
976
|
+
new Runnable() {
|
|
977
|
+
@Override
|
|
978
|
+
public void run() {
|
|
979
|
+
injectPreShowScript();
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
);
|
|
215
983
|
}
|
|
216
984
|
|
|
217
985
|
ImageButton backButton = _toolbar.findViewById(R.id.backButton);
|
|
@@ -233,6 +1001,7 @@ public class WebViewDialog extends Dialog {
|
|
|
233
1001
|
}
|
|
234
1002
|
|
|
235
1003
|
_options.getCallbacks().pageLoaded();
|
|
1004
|
+
injectJavaScriptInterface();
|
|
236
1005
|
}
|
|
237
1006
|
|
|
238
1007
|
@Override
|
|
@@ -244,6 +1013,23 @@ public class WebViewDialog extends Dialog {
|
|
|
244
1013
|
super.onReceivedError(view, request, error);
|
|
245
1014
|
_options.getCallbacks().pageLoadError();
|
|
246
1015
|
}
|
|
1016
|
+
|
|
1017
|
+
@SuppressLint("WebViewClientOnReceivedSslError")
|
|
1018
|
+
@Override
|
|
1019
|
+
public void onReceivedSslError(
|
|
1020
|
+
WebView view,
|
|
1021
|
+
SslErrorHandler handler,
|
|
1022
|
+
SslError error
|
|
1023
|
+
) {
|
|
1024
|
+
boolean ignoreSSLUntrustedError = _options.ignoreUntrustedSSLError();
|
|
1025
|
+
if (
|
|
1026
|
+
ignoreSSLUntrustedError &&
|
|
1027
|
+
error.getPrimaryError() == SslError.SSL_UNTRUSTED
|
|
1028
|
+
) handler.proceed();
|
|
1029
|
+
else {
|
|
1030
|
+
super.onReceivedSslError(view, handler, error);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
247
1033
|
}
|
|
248
1034
|
);
|
|
249
1035
|
}
|
|
@@ -252,11 +1038,109 @@ public class WebViewDialog extends Dialog {
|
|
|
252
1038
|
public void onBackPressed() {
|
|
253
1039
|
if (
|
|
254
1040
|
_webView.canGoBack() &&
|
|
255
|
-
TextUtils.equals(_options.getToolbarType(), "navigation")
|
|
1041
|
+
(TextUtils.equals(_options.getToolbarType(), "navigation") ||
|
|
1042
|
+
_options.getActiveNativeNavigationForWebview())
|
|
256
1043
|
) {
|
|
257
1044
|
_webView.goBack();
|
|
258
|
-
} else {
|
|
1045
|
+
} else if (!_options.getDisableGoBackOnNativeApplication()) {
|
|
259
1046
|
super.onBackPressed();
|
|
260
1047
|
}
|
|
261
1048
|
}
|
|
1049
|
+
|
|
1050
|
+
public static String getReasonPhrase(int statusCode) {
|
|
1051
|
+
switch (statusCode) {
|
|
1052
|
+
case (200):
|
|
1053
|
+
return "OK";
|
|
1054
|
+
case (201):
|
|
1055
|
+
return "Created";
|
|
1056
|
+
case (202):
|
|
1057
|
+
return "Accepted";
|
|
1058
|
+
case (203):
|
|
1059
|
+
return "Non Authoritative Information";
|
|
1060
|
+
case (204):
|
|
1061
|
+
return "No Content";
|
|
1062
|
+
case (205):
|
|
1063
|
+
return "Reset Content";
|
|
1064
|
+
case (206):
|
|
1065
|
+
return "Partial Content";
|
|
1066
|
+
case (207):
|
|
1067
|
+
return "Partial Update OK";
|
|
1068
|
+
case (300):
|
|
1069
|
+
return "Mutliple Choices";
|
|
1070
|
+
case (301):
|
|
1071
|
+
return "Moved Permanently";
|
|
1072
|
+
case (302):
|
|
1073
|
+
return "Moved Temporarily";
|
|
1074
|
+
case (303):
|
|
1075
|
+
return "See Other";
|
|
1076
|
+
case (304):
|
|
1077
|
+
return "Not Modified";
|
|
1078
|
+
case (305):
|
|
1079
|
+
return "Use Proxy";
|
|
1080
|
+
case (307):
|
|
1081
|
+
return "Temporary Redirect";
|
|
1082
|
+
case (400):
|
|
1083
|
+
return "Bad Request";
|
|
1084
|
+
case (401):
|
|
1085
|
+
return "Unauthorized";
|
|
1086
|
+
case (402):
|
|
1087
|
+
return "Payment Required";
|
|
1088
|
+
case (403):
|
|
1089
|
+
return "Forbidden";
|
|
1090
|
+
case (404):
|
|
1091
|
+
return "Not Found";
|
|
1092
|
+
case (405):
|
|
1093
|
+
return "Method Not Allowed";
|
|
1094
|
+
case (406):
|
|
1095
|
+
return "Not Acceptable";
|
|
1096
|
+
case (407):
|
|
1097
|
+
return "Proxy Authentication Required";
|
|
1098
|
+
case (408):
|
|
1099
|
+
return "Request Timeout";
|
|
1100
|
+
case (409):
|
|
1101
|
+
return "Conflict";
|
|
1102
|
+
case (410):
|
|
1103
|
+
return "Gone";
|
|
1104
|
+
case (411):
|
|
1105
|
+
return "Length Required";
|
|
1106
|
+
case (412):
|
|
1107
|
+
return "Precondition Failed";
|
|
1108
|
+
case (413):
|
|
1109
|
+
return "Request Entity Too Large";
|
|
1110
|
+
case (414):
|
|
1111
|
+
return "Request-URI Too Long";
|
|
1112
|
+
case (415):
|
|
1113
|
+
return "Unsupported Media Type";
|
|
1114
|
+
case (416):
|
|
1115
|
+
return "Requested Range Not Satisfiable";
|
|
1116
|
+
case (417):
|
|
1117
|
+
return "Expectation Failed";
|
|
1118
|
+
case (418):
|
|
1119
|
+
return "Reauthentication Required";
|
|
1120
|
+
case (419):
|
|
1121
|
+
return "Proxy Reauthentication Required";
|
|
1122
|
+
case (422):
|
|
1123
|
+
return "Unprocessable Entity";
|
|
1124
|
+
case (423):
|
|
1125
|
+
return "Locked";
|
|
1126
|
+
case (424):
|
|
1127
|
+
return "Failed Dependency";
|
|
1128
|
+
case (500):
|
|
1129
|
+
return "Server Error";
|
|
1130
|
+
case (501):
|
|
1131
|
+
return "Not Implemented";
|
|
1132
|
+
case (502):
|
|
1133
|
+
return "Bad Gateway";
|
|
1134
|
+
case (503):
|
|
1135
|
+
return "Service Unavailable";
|
|
1136
|
+
case (504):
|
|
1137
|
+
return "Gateway Timeout";
|
|
1138
|
+
case (505):
|
|
1139
|
+
return "HTTP Version Not Supported";
|
|
1140
|
+
case (507):
|
|
1141
|
+
return "Insufficient Storage";
|
|
1142
|
+
default:
|
|
1143
|
+
return "";
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
262
1146
|
}
|