@capgo/inappbrowser 7.22.0 → 7.22.3

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.
@@ -40,1065 +40,880 @@ import org.json.JSONException;
40
40
  import org.json.JSONObject;
41
41
 
42
42
  @CapacitorPlugin(
43
- name = "InAppBrowser",
44
- permissions = {
45
- @Permission(alias = "camera", strings = { Manifest.permission.CAMERA }),
46
- @Permission(
47
- alias = "microphone",
48
- strings = { Manifest.permission.RECORD_AUDIO }
49
- ),
50
- @Permission(
51
- alias = "storage",
52
- strings = { Manifest.permission.READ_EXTERNAL_STORAGE }
53
- ),
54
- },
55
- requestCodes = { WebViewDialog.FILE_CHOOSER_REQUEST_CODE }
43
+ name = "InAppBrowser",
44
+ permissions = {
45
+ @Permission(alias = "camera", strings = { Manifest.permission.CAMERA }),
46
+ @Permission(alias = "microphone", strings = { Manifest.permission.RECORD_AUDIO }),
47
+ @Permission(alias = "storage", strings = { Manifest.permission.READ_EXTERNAL_STORAGE })
48
+ },
49
+ requestCodes = { WebViewDialog.FILE_CHOOSER_REQUEST_CODE }
56
50
  )
57
- public class InAppBrowserPlugin
58
- extends Plugin
59
- implements WebViewDialog.PermissionHandler {
60
-
61
- public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
62
- private CustomTabsClient customTabsClient;
63
- private CustomTabsSession currentSession;
64
- private WebViewDialog webViewDialog = null;
65
- private String currentUrl = "";
66
-
67
- private PermissionRequest currentPermissionRequest;
68
-
69
- private ActivityResultLauncher<Intent> fileChooserLauncher;
70
-
71
- @Override
72
- public void load() {
73
- super.load();
74
- fileChooserLauncher = getActivity()
75
- .registerForActivityResult(
76
- new ActivityResultContracts.StartActivityForResult(),
77
- this::handleFileChooserResult
78
- );
79
- }
80
-
81
- private void handleFileChooserResult(ActivityResult result) {
82
- if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
83
- Uri[] results = null;
84
- Intent data = result.getData();
85
-
86
- if (result.getResultCode() == Activity.RESULT_OK) {
87
- // Handle camera capture result
88
- if (
89
- webViewDialog.tempCameraUri != null &&
90
- (data == null || data.getData() == null)
91
- ) {
92
- results = new Uri[] { webViewDialog.tempCameraUri };
93
- }
94
- // Handle regular file picker result
95
- else if (data != null) {
96
- if (data.getClipData() != null) {
97
- // Handle multiple files
98
- int count = data.getClipData().getItemCount();
99
- results = new Uri[count];
100
- for (int i = 0; i < count; i++) {
101
- results[i] = data.getClipData().getItemAt(i).getUri();
102
- }
103
- } else if (data.getData() != null) {
104
- // Handle single file
105
- results = new Uri[] { data.getData() };
106
- }
107
- }
108
- }
51
+ public class InAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
109
52
 
110
- // Send the result to WebView and clean up
111
- webViewDialog.mFilePathCallback.onReceiveValue(results);
112
- webViewDialog.mFilePathCallback = null;
113
- webViewDialog.tempCameraUri = null;
114
- }
115
- }
116
-
117
- public void handleMicrophonePermissionRequest(PermissionRequest request) {
118
- this.currentPermissionRequest = request;
119
- if (getPermissionState("microphone") != PermissionState.GRANTED) {
120
- requestPermissionForAlias(
121
- "microphone",
122
- null,
123
- "microphonePermissionCallback"
124
- );
125
- } else {
126
- grantMicrophonePermission();
127
- }
128
- }
129
-
130
- private void grantMicrophonePermission() {
131
- if (currentPermissionRequest != null) {
132
- currentPermissionRequest.grant(
133
- new String[] { PermissionRequest.RESOURCE_AUDIO_CAPTURE }
134
- );
135
- currentPermissionRequest = null;
136
- }
137
- }
138
-
139
- @PermissionCallback
140
- private void microphonePermissionCallback(PluginCall call) {
141
- if (getPermissionState("microphone") == PermissionState.GRANTED) {
142
- grantCameraAndMicrophonePermission();
143
- } else {
144
- if (currentPermissionRequest != null) {
145
- currentPermissionRequest.deny();
146
- currentPermissionRequest = null;
147
- }
148
- if (call != null) {
149
- call.reject("Microphone permission is required");
150
- }
151
- }
152
- }
153
-
154
- private void grantCameraAndMicrophonePermission() {
155
- if (currentPermissionRequest != null) {
156
- currentPermissionRequest.grant(
157
- new String[] {
158
- PermissionRequest.RESOURCE_VIDEO_CAPTURE,
159
- PermissionRequest.RESOURCE_AUDIO_CAPTURE,
160
- }
161
- );
162
- currentPermissionRequest = null;
163
- }
164
- }
165
-
166
- public void handleCameraPermissionRequest(PermissionRequest request) {
167
- this.currentPermissionRequest = request;
168
- if (getPermissionState("camera") != PermissionState.GRANTED) {
169
- requestPermissionForAlias("camera", null, "cameraPermissionCallback");
170
- } else if (getPermissionState("microphone") != PermissionState.GRANTED) {
171
- requestPermissionForAlias(
172
- "microphone",
173
- null,
174
- "microphonePermissionCallback"
175
- );
176
- } else {
177
- grantCameraAndMicrophonePermission();
178
- }
179
- }
180
-
181
- @PermissionCallback
182
- private void cameraPermissionCallback(PluginCall call) {
183
- if (getPermissionState("camera") == PermissionState.GRANTED) {
184
- if (getPermissionState("microphone") != PermissionState.GRANTED) {
185
- requestPermissionForAlias(
186
- "microphone",
187
- null,
188
- "microphonePermissionCallback"
189
- );
190
- } else {
191
- grantCameraAndMicrophonePermission();
192
- }
193
- } else {
194
- if (currentPermissionRequest != null) {
195
- currentPermissionRequest.deny();
196
- currentPermissionRequest = null;
197
- }
53
+ public static final String CUSTOM_TAB_PACKAGE_NAME = "com.android.chrome"; // Change when in stable
54
+ private CustomTabsClient customTabsClient;
55
+ private CustomTabsSession currentSession;
56
+ private WebViewDialog webViewDialog = null;
57
+ private String currentUrl = "";
198
58
 
199
- // Reject only if there's a call - could be null for WebViewDialog flow
200
- if (call != null) {
201
- call.reject("Camera permission is required");
202
- }
203
- }
204
- }
205
-
206
- @PermissionCallback
207
- private void cameraPermissionCallback() {
208
- if (getPermissionState("camera") == PermissionState.GRANTED) {
209
- grantCameraPermission();
210
- } else {
211
- if (currentPermissionRequest != null) {
212
- currentPermissionRequest.deny();
213
- currentPermissionRequest = null;
214
- }
215
- }
216
- }
217
-
218
- private void grantCameraPermission() {
219
- if (currentPermissionRequest != null) {
220
- currentPermissionRequest.grant(
221
- new String[] { PermissionRequest.RESOURCE_VIDEO_CAPTURE }
222
- );
223
- currentPermissionRequest = null;
224
- }
225
- }
59
+ private PermissionRequest currentPermissionRequest;
226
60
 
227
- CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
228
- @Override
229
- public void onCustomTabsServiceConnected(
230
- ComponentName name,
231
- CustomTabsClient client
232
- ) {
233
- customTabsClient = client;
234
- }
61
+ private ActivityResultLauncher<Intent> fileChooserLauncher;
235
62
 
236
63
  @Override
237
- public void onServiceDisconnected(ComponentName name) {
238
- customTabsClient = null;
239
- }
240
- };
241
-
242
- @PluginMethod
243
- public void requestCameraPermission(PluginCall call) {
244
- if (getPermissionState("camera") != PermissionState.GRANTED) {
245
- requestPermissionForAlias("camera", call, "cameraPermissionCallback");
246
- } else {
247
- call.resolve();
248
- }
249
- }
250
-
251
- @PluginMethod
252
- public void setUrl(PluginCall call) {
253
- String url = call.getString("url");
254
- if (url == null || TextUtils.isEmpty(url)) {
255
- call.reject("Invalid URL");
256
- return;
64
+ public void load() {
65
+ super.load();
66
+ fileChooserLauncher = getActivity().registerForActivityResult(
67
+ new ActivityResultContracts.StartActivityForResult(),
68
+ this::handleFileChooserResult
69
+ );
257
70
  }
258
71
 
259
- if (webViewDialog == null) {
260
- call.reject("WebView is not initialized");
261
- return;
262
- }
72
+ private void handleFileChooserResult(ActivityResult result) {
73
+ if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
74
+ Uri[] results = null;
75
+ Intent data = result.getData();
263
76
 
264
- currentUrl = url;
265
- this.getActivity()
266
- .runOnUiThread(
267
- new Runnable() {
268
- @Override
269
- public void run() {
270
- try {
271
- if (webViewDialog != null) {
272
- webViewDialog.setUrl(url);
273
- call.resolve();
274
- } else {
275
- call.reject("WebView is not initialized");
276
- }
277
- } catch (Exception e) {
278
- Log.e("InAppBrowser", "Error setting URL: " + e.getMessage());
279
- call.reject("Failed to set URL: " + e.getMessage());
77
+ if (result.getResultCode() == Activity.RESULT_OK) {
78
+ // Handle camera capture result
79
+ if (webViewDialog.tempCameraUri != null && (data == null || data.getData() == null)) {
80
+ results = new Uri[] { webViewDialog.tempCameraUri };
81
+ }
82
+ // Handle regular file picker result
83
+ else if (data != null) {
84
+ if (data.getClipData() != null) {
85
+ // Handle multiple files
86
+ int count = data.getClipData().getItemCount();
87
+ results = new Uri[count];
88
+ for (int i = 0; i < count; i++) {
89
+ results[i] = data.getClipData().getItemAt(i).getUri();
90
+ }
91
+ } else if (data.getData() != null) {
92
+ // Handle single file
93
+ results = new Uri[] { data.getData() };
94
+ }
95
+ }
280
96
  }
281
- }
97
+
98
+ // Send the result to WebView and clean up
99
+ webViewDialog.mFilePathCallback.onReceiveValue(results);
100
+ webViewDialog.mFilePathCallback = null;
101
+ webViewDialog.tempCameraUri = null;
282
102
  }
283
- );
284
- }
285
-
286
- @PluginMethod
287
- public void open(PluginCall call) {
288
- String url = call.getString("url");
289
- if (url == null) {
290
- call.reject("URL is required");
291
- return;
292
103
  }
293
104
 
294
- // get the deeplink prevention, if provided
295
- Boolean preventDeeplink = call.getBoolean("preventDeeplink", false);
296
- Boolean isPresentAfterPageLoad = call.getBoolean(
297
- "isPresentAfterPageLoad",
298
- false
299
- );
300
-
301
- if (url == null || TextUtils.isEmpty(url)) {
302
- call.reject("Invalid URL");
303
- }
304
- currentUrl = url;
305
- CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(
306
- getCustomTabsSession()
307
- );
308
- CustomTabsIntent tabsIntent = builder.build();
309
- tabsIntent.intent.putExtra(
310
- Intent.EXTRA_REFERRER,
311
- Uri.parse(
312
- Intent.URI_ANDROID_APP_SCHEME + "//" + getContext().getPackageName()
313
- )
314
- );
315
- tabsIntent.intent.putExtra(
316
- android.provider.Browser.EXTRA_HEADERS,
317
- this.getHeaders(call)
318
- );
319
-
320
- if (preventDeeplink != false) {
321
- String browserPackageName = "";
322
- Intent browserIntent = new Intent(
323
- Intent.ACTION_VIEW,
324
- Uri.parse("http://")
325
- );
326
- ResolveInfo resolveInfo = getContext()
327
- .getPackageManager()
328
- .resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
329
-
330
- if (resolveInfo != null) {
331
- browserPackageName = resolveInfo.activityInfo.packageName;
332
-
333
- if (!browserPackageName.isEmpty()) {
334
- tabsIntent.intent.setPackage(browserPackageName);
105
+ public void handleMicrophonePermissionRequest(PermissionRequest request) {
106
+ this.currentPermissionRequest = request;
107
+ if (getPermissionState("microphone") != PermissionState.GRANTED) {
108
+ requestPermissionForAlias("microphone", null, "microphonePermissionCallback");
109
+ } else {
110
+ grantMicrophonePermission();
335
111
  }
336
- }
337
112
  }
338
113
 
339
- if (isPresentAfterPageLoad) {
340
- tabsIntent.intent.putExtra("isPresentAfterPageLoad", true);
114
+ private void grantMicrophonePermission() {
115
+ if (currentPermissionRequest != null) {
116
+ currentPermissionRequest.grant(new String[] { PermissionRequest.RESOURCE_AUDIO_CAPTURE });
117
+ currentPermissionRequest = null;
118
+ }
341
119
  }
342
120
 
343
- tabsIntent.launchUrl(getContext(), Uri.parse(url));
344
-
345
- call.resolve();
346
- }
347
-
348
- @PluginMethod
349
- public void clearCache(PluginCall call) {
350
- CookieManager cookieManager = CookieManager.getInstance();
351
- cookieManager.removeAllCookies(null);
352
- cookieManager.flush();
353
- call.resolve();
354
- }
355
-
356
- @PluginMethod
357
- public void clearAllCookies(PluginCall call) {
358
- CookieManager cookieManager = CookieManager.getInstance();
359
- cookieManager.removeAllCookies(null);
360
- cookieManager.flush();
361
- call.resolve();
362
- }
363
-
364
- @PluginMethod
365
- public void clearCookies(PluginCall call) {
366
- String url = call.getString("url", currentUrl);
367
- if (url == null || TextUtils.isEmpty(url)) {
368
- call.reject("Invalid URL");
369
- return;
121
+ @PermissionCallback
122
+ private void microphonePermissionCallback(PluginCall call) {
123
+ if (getPermissionState("microphone") == PermissionState.GRANTED) {
124
+ grantCameraAndMicrophonePermission();
125
+ } else {
126
+ if (currentPermissionRequest != null) {
127
+ currentPermissionRequest.deny();
128
+ currentPermissionRequest = null;
129
+ }
130
+ if (call != null) {
131
+ call.reject("Microphone permission is required");
132
+ }
133
+ }
370
134
  }
371
135
 
372
- Uri uri = Uri.parse(url);
373
- String host = uri.getHost();
374
- if (host == null || TextUtils.isEmpty(host)) {
375
- call.reject("Invalid URL (Host is null)");
376
- return;
136
+ private void grantCameraAndMicrophonePermission() {
137
+ if (currentPermissionRequest != null) {
138
+ currentPermissionRequest.grant(
139
+ new String[] { PermissionRequest.RESOURCE_VIDEO_CAPTURE, PermissionRequest.RESOURCE_AUDIO_CAPTURE }
140
+ );
141
+ currentPermissionRequest = null;
142
+ }
377
143
  }
378
144
 
379
- CookieManager cookieManager = CookieManager.getInstance();
380
- String cookieString = cookieManager.getCookie(url);
381
- ArrayList<String> cookiesToRemove = new ArrayList<>();
145
+ public void handleCameraPermissionRequest(PermissionRequest request) {
146
+ this.currentPermissionRequest = request;
147
+ if (getPermissionState("camera") != PermissionState.GRANTED) {
148
+ requestPermissionForAlias("camera", null, "cameraPermissionCallback");
149
+ } else if (getPermissionState("microphone") != PermissionState.GRANTED) {
150
+ requestPermissionForAlias("microphone", null, "microphonePermissionCallback");
151
+ } else {
152
+ grantCameraAndMicrophonePermission();
153
+ }
154
+ }
382
155
 
383
- if (cookieString != null) {
384
- String[] cookies = cookieString.split("; ");
156
+ @PermissionCallback
157
+ private void cameraPermissionCallback(PluginCall call) {
158
+ if (getPermissionState("camera") == PermissionState.GRANTED) {
159
+ if (getPermissionState("microphone") != PermissionState.GRANTED) {
160
+ requestPermissionForAlias("microphone", null, "microphonePermissionCallback");
161
+ } else {
162
+ grantCameraAndMicrophonePermission();
163
+ }
164
+ } else {
165
+ if (currentPermissionRequest != null) {
166
+ currentPermissionRequest.deny();
167
+ currentPermissionRequest = null;
168
+ }
385
169
 
386
- String domain = uri.getHost();
170
+ // Reject only if there's a call - could be null for WebViewDialog flow
171
+ if (call != null) {
172
+ call.reject("Camera permission is required");
173
+ }
174
+ }
175
+ }
387
176
 
388
- for (String cookie : cookies) {
389
- String[] parts = cookie.split("=");
390
- if (parts.length > 0) {
391
- cookiesToRemove.add(parts[0].trim());
392
- CookieManager.getInstance()
393
- .setCookie(url, String.format("%s=del;", parts[0].trim()));
177
+ @PermissionCallback
178
+ private void cameraPermissionCallback() {
179
+ if (getPermissionState("camera") == PermissionState.GRANTED) {
180
+ grantCameraPermission();
181
+ } else {
182
+ if (currentPermissionRequest != null) {
183
+ currentPermissionRequest.deny();
184
+ currentPermissionRequest = null;
185
+ }
394
186
  }
395
- }
396
187
  }
397
188
 
398
- StringBuilder scriptToRun = new StringBuilder();
399
- for (String cookieToRemove : cookiesToRemove) {
400
- scriptToRun.append(
401
- String.format(
402
- "window.cookieStore.delete('%s', {name: '%s', domain: '%s'});",
403
- cookieToRemove,
404
- cookieToRemove,
405
- url
406
- )
407
- );
189
+ private void grantCameraPermission() {
190
+ if (currentPermissionRequest != null) {
191
+ currentPermissionRequest.grant(new String[] { PermissionRequest.RESOURCE_VIDEO_CAPTURE });
192
+ currentPermissionRequest = null;
193
+ }
408
194
  }
409
195
 
410
- Log.i("DelCookies", String.format("Script to run:\n%s", scriptToRun));
196
+ CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
197
+ @Override
198
+ public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
199
+ customTabsClient = client;
200
+ }
411
201
 
412
- this.getActivity()
413
- .runOnUiThread(
414
- new Runnable() {
415
- @Override
416
- public void run() {
417
- try {
418
- if (webViewDialog != null) {
419
- webViewDialog.executeScript(scriptToRun.toString());
420
- call.resolve();
421
- } else {
422
- call.reject("WebView is not initialized");
423
- }
424
- } catch (Exception e) {
425
- Log.e(
426
- "InAppBrowser",
427
- "Error clearing cookies: " + e.getMessage()
428
- );
429
- call.reject("Failed to clear cookies: " + e.getMessage());
430
- }
431
- }
202
+ @Override
203
+ public void onServiceDisconnected(ComponentName name) {
204
+ customTabsClient = null;
432
205
  }
433
- );
434
- }
435
-
436
- @PluginMethod
437
- public void getCookies(PluginCall call) {
438
- String url = call.getString("url");
439
- if (url == null || TextUtils.isEmpty(url)) {
440
- call.reject("Invalid URL");
441
- return;
442
- }
443
- CookieManager cookieManager = CookieManager.getInstance();
444
- String cookieString = cookieManager.getCookie(url);
445
- JSObject result = new JSObject();
446
- if (cookieString != null) {
447
- String[] cookiePairs = cookieString.split("; ");
448
- for (String cookie : cookiePairs) {
449
- String[] parts = cookie.split("=", 2);
450
- if (parts.length == 2) {
451
- result.put(parts[0], parts[1]);
206
+ };
207
+
208
+ @PluginMethod
209
+ public void requestCameraPermission(PluginCall call) {
210
+ if (getPermissionState("camera") != PermissionState.GRANTED) {
211
+ requestPermissionForAlias("camera", call, "cameraPermissionCallback");
212
+ } else {
213
+ call.resolve();
452
214
  }
453
- }
454
- }
455
- call.resolve(result);
456
- }
457
-
458
- @PluginMethod
459
- public void openWebView(PluginCall call) {
460
- String url = call.getString("url");
461
- if (url == null || TextUtils.isEmpty(url)) {
462
- call.reject("Invalid URL");
463
- }
464
- currentUrl = url;
465
- final Options options = new Options();
466
- options.setUrl(url);
467
- options.setHeaders(call.getObject("headers"));
468
- options.setCredentials(call.getObject("credentials"));
469
- options.setShowReloadButton(
470
- Boolean.TRUE.equals(call.getBoolean("showReloadButton", false))
471
- );
472
- options.setVisibleTitle(
473
- Boolean.TRUE.equals(call.getBoolean("visibleTitle", true))
474
- );
475
- if (Boolean.TRUE.equals(options.getVisibleTitle())) {
476
- options.setTitle(call.getString("title", "New Window"));
477
- } else {
478
- options.setTitle(call.getString("title", ""));
479
- }
480
- options.setToolbarColor(call.getString("toolbarColor", "#ffffff"));
481
- options.setBackgroundColor(call.getString("backgroundColor", "white"));
482
- options.setToolbarTextColor(call.getString("toolbarTextColor"));
483
- options.setArrow(Boolean.TRUE.equals(call.getBoolean("showArrow", false)));
484
- options.setIgnoreUntrustedSSLError(
485
- Boolean.TRUE.equals(call.getBoolean("ignoreUntrustedSSLError", false))
486
- );
487
-
488
- // Set text zoom if specified in options (default is 100)
489
- Integer textZoom = call.getInt("textZoom");
490
- if (textZoom != null) {
491
- options.setTextZoom(textZoom);
492
215
  }
493
216
 
494
- String proxyRequestsStr = call.getString("proxyRequests");
495
- if (proxyRequestsStr != null) {
496
- try {
497
- options.setProxyRequestsPattern(Pattern.compile(proxyRequestsStr));
498
- } catch (PatternSyntaxException e) {
499
- Log.e(
500
- "WebViewDialog",
501
- String.format("Pattern '%s' is not a valid pattern", proxyRequestsStr)
217
+ @PluginMethod
218
+ public void setUrl(PluginCall call) {
219
+ String url = call.getString("url");
220
+ if (url == null || TextUtils.isEmpty(url)) {
221
+ call.reject("Invalid URL");
222
+ return;
223
+ }
224
+
225
+ if (webViewDialog == null) {
226
+ call.reject("WebView is not initialized");
227
+ return;
228
+ }
229
+
230
+ currentUrl = url;
231
+ this.getActivity().runOnUiThread(
232
+ new Runnable() {
233
+ @Override
234
+ public void run() {
235
+ try {
236
+ if (webViewDialog != null) {
237
+ webViewDialog.setUrl(url);
238
+ call.resolve();
239
+ } else {
240
+ call.reject("WebView is not initialized");
241
+ }
242
+ } catch (Exception e) {
243
+ Log.e("InAppBrowser", "Error setting URL: " + e.getMessage());
244
+ call.reject("Failed to set URL: " + e.getMessage());
245
+ }
246
+ }
247
+ }
502
248
  );
503
- }
504
249
  }
505
250
 
506
- try {
507
- // Try to set buttonNearDone if present, with better error handling
508
- JSObject buttonNearDoneObj = call.getObject("buttonNearDone");
509
- if (buttonNearDoneObj != null) {
510
- try {
511
- // Provide better debugging for buttonNearDone
512
- JSObject androidObj = buttonNearDoneObj.getJSObject("android");
513
- if (androidObj != null) {
514
- String iconType = androidObj.getString("iconType", "asset");
515
- String icon = androidObj.getString("icon", "");
516
- Log.d(
517
- "InAppBrowser",
518
- "ButtonNearDone config - iconType: " +
519
- iconType +
520
- ", icon: " +
521
- icon
522
- );
251
+ @PluginMethod
252
+ public void open(PluginCall call) {
253
+ String url = call.getString("url");
254
+ if (url == null) {
255
+ call.reject("URL is required");
256
+ return;
257
+ }
523
258
 
524
- // For vector type, verify if resource exists
525
- if ("vector".equals(iconType)) {
526
- int resourceId = getContext()
527
- .getResources()
528
- .getIdentifier(icon, "drawable", getContext().getPackageName());
529
- if (resourceId == 0) {
530
- Log.e("InAppBrowser", "Vector resource not found: " + icon);
531
- // List available drawable resources to help debugging
532
- try {
533
- final StringBuilder availableResources = getStringBuilder();
534
- Log.d("InAppBrowser", availableResources.toString());
535
- } catch (Exception e) {
536
- Log.e(
537
- "InAppBrowser",
538
- "Error listing resources: " + e.getMessage()
539
- );
259
+ // get the deeplink prevention, if provided
260
+ Boolean preventDeeplink = call.getBoolean("preventDeeplink", false);
261
+ Boolean isPresentAfterPageLoad = call.getBoolean("isPresentAfterPageLoad", false);
262
+
263
+ if (url == null || TextUtils.isEmpty(url)) {
264
+ call.reject("Invalid URL");
265
+ }
266
+ currentUrl = url;
267
+ CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getCustomTabsSession());
268
+ CustomTabsIntent tabsIntent = builder.build();
269
+ tabsIntent.intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(Intent.URI_ANDROID_APP_SCHEME + "//" + getContext().getPackageName()));
270
+ tabsIntent.intent.putExtra(android.provider.Browser.EXTRA_HEADERS, this.getHeaders(call));
271
+
272
+ if (preventDeeplink != false) {
273
+ String browserPackageName = "";
274
+ Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
275
+ ResolveInfo resolveInfo = getContext().getPackageManager().resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
276
+
277
+ if (resolveInfo != null) {
278
+ browserPackageName = resolveInfo.activityInfo.packageName;
279
+
280
+ if (!browserPackageName.isEmpty()) {
281
+ tabsIntent.intent.setPackage(browserPackageName);
540
282
  }
541
- } else {
542
- Log.d(
543
- "InAppBrowser",
544
- "Vector resource found with ID: " + resourceId
545
- );
546
- }
547
283
  }
548
- }
284
+ }
549
285
 
550
- // Try to create the ButtonNearDone object
551
- Options.ButtonNearDone buttonNearDone =
552
- Options.ButtonNearDone.generateFromPluginCall(
553
- call,
554
- getContext().getAssets()
555
- );
556
- options.setButtonNearDone(buttonNearDone);
557
- } catch (Exception e) {
558
- Log.e(
559
- "InAppBrowser",
560
- "Error setting buttonNearDone: " + e.getMessage(),
561
- e
562
- );
286
+ if (isPresentAfterPageLoad) {
287
+ tabsIntent.intent.putExtra("isPresentAfterPageLoad", true);
563
288
  }
564
- }
565
- } catch (Exception e) {
566
- Log.e(
567
- "InAppBrowser",
568
- "Error processing buttonNearDone: " + e.getMessage(),
569
- e
570
- );
571
- }
572
289
 
573
- options.setShareDisclaimer(call.getObject("shareDisclaimer", null));
574
- options.setPreShowScript(call.getString("preShowScript", null));
575
- options.setShareSubject(call.getString("shareSubject", null));
576
- options.setToolbarType(call.getString("toolbarType", ""));
577
- options.setPreventDeeplink(
578
- Boolean.TRUE.equals(call.getBoolean("preventDeeplink", false))
579
- );
580
-
581
- // Validate preShowScript requires isPresentAfterPageLoad
582
- if (
583
- call.getData().has("preShowScript") &&
584
- !Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false))
585
- ) {
586
- call.reject("preShowScript requires isPresentAfterPageLoad to be true");
587
- return;
290
+ tabsIntent.launchUrl(getContext(), Uri.parse(url));
291
+
292
+ call.resolve();
588
293
  }
589
294
 
590
- // Validate closeModal options
591
- if (Boolean.TRUE.equals(call.getBoolean("closeModal", false))) {
592
- options.setCloseModal(true);
593
- options.setCloseModalTitle(call.getString("closeModalTitle", "Close"));
594
- options.setCloseModalDescription(
595
- call.getString("closeModalDescription", "Are you sure ?")
596
- );
597
- options.setCloseModalOk(call.getString("closeModalOk", "Ok"));
598
- options.setCloseModalCancel(call.getString("closeModalCancel", "Cancel"));
599
- } else {
600
- // Reject if closeModal is false but closeModal options are provided
601
- if (
602
- call.getData().has("closeModalTitle") ||
603
- call.getData().has("closeModalDescription") ||
604
- call.getData().has("closeModalOk") ||
605
- call.getData().has("closeModalCancel")
606
- ) {
607
- call.reject("closeModal options require closeModal to be true");
608
- return;
609
- }
610
- options.setCloseModal(false);
295
+ @PluginMethod
296
+ public void clearCache(PluginCall call) {
297
+ CookieManager cookieManager = CookieManager.getInstance();
298
+ cookieManager.removeAllCookies(null);
299
+ cookieManager.flush();
300
+ call.resolve();
611
301
  }
612
302
 
613
- // Validate shareDisclaimer requires shareSubject
614
- if (
615
- call.getData().has("shareDisclaimer") &&
616
- !call.getData().has("shareSubject")
617
- ) {
618
- call.reject("shareDisclaimer requires shareSubject to be provided");
619
- return;
303
+ @PluginMethod
304
+ public void clearAllCookies(PluginCall call) {
305
+ CookieManager cookieManager = CookieManager.getInstance();
306
+ cookieManager.removeAllCookies(null);
307
+ cookieManager.flush();
308
+ call.resolve();
620
309
  }
621
310
 
622
- // Validate buttonNearDone compatibility with toolbar type
623
- if (call.getData().has("buttonNearDone")) {
624
- String toolbarType = options.getToolbarType();
625
- if (
626
- TextUtils.equals(toolbarType, "activity") ||
627
- TextUtils.equals(toolbarType, "navigation") ||
628
- TextUtils.equals(toolbarType, "blank")
629
- ) {
630
- call.reject(
631
- "buttonNearDone is not compatible with toolbarType: " + toolbarType
311
+ @PluginMethod
312
+ public void clearCookies(PluginCall call) {
313
+ String url = call.getString("url", currentUrl);
314
+ if (url == null || TextUtils.isEmpty(url)) {
315
+ call.reject("Invalid URL");
316
+ return;
317
+ }
318
+
319
+ Uri uri = Uri.parse(url);
320
+ String host = uri.getHost();
321
+ if (host == null || TextUtils.isEmpty(host)) {
322
+ call.reject("Invalid URL (Host is null)");
323
+ return;
324
+ }
325
+
326
+ CookieManager cookieManager = CookieManager.getInstance();
327
+ String cookieString = cookieManager.getCookie(url);
328
+ ArrayList<String> cookiesToRemove = new ArrayList<>();
329
+
330
+ if (cookieString != null) {
331
+ String[] cookies = cookieString.split("; ");
332
+
333
+ String domain = uri.getHost();
334
+
335
+ for (String cookie : cookies) {
336
+ String[] parts = cookie.split("=");
337
+ if (parts.length > 0) {
338
+ cookiesToRemove.add(parts[0].trim());
339
+ CookieManager.getInstance().setCookie(url, String.format("%s=del;", parts[0].trim()));
340
+ }
341
+ }
342
+ }
343
+
344
+ StringBuilder scriptToRun = new StringBuilder();
345
+ for (String cookieToRemove : cookiesToRemove) {
346
+ scriptToRun.append(
347
+ String.format("window.cookieStore.delete('%s', {name: '%s', domain: '%s'});", cookieToRemove, cookieToRemove, url)
348
+ );
349
+ }
350
+
351
+ Log.i("DelCookies", String.format("Script to run:\n%s", scriptToRun));
352
+
353
+ this.getActivity().runOnUiThread(
354
+ new Runnable() {
355
+ @Override
356
+ public void run() {
357
+ try {
358
+ if (webViewDialog != null) {
359
+ webViewDialog.executeScript(scriptToRun.toString());
360
+ call.resolve();
361
+ } else {
362
+ call.reject("WebView is not initialized");
363
+ }
364
+ } catch (Exception e) {
365
+ Log.e("InAppBrowser", "Error clearing cookies: " + e.getMessage());
366
+ call.reject("Failed to clear cookies: " + e.getMessage());
367
+ }
368
+ }
369
+ }
632
370
  );
633
- return;
634
- }
635
371
  }
636
372
 
637
- options.setActiveNativeNavigationForWebview(
638
- Boolean.TRUE.equals(
639
- call.getBoolean("activeNativeNavigationForWebview", false)
640
- )
641
- );
642
- options.setDisableGoBackOnNativeApplication(
643
- Boolean.TRUE.equals(
644
- call.getBoolean("disableGoBackOnNativeApplication", false)
645
- )
646
- );
647
- options.setPresentAfterPageLoad(
648
- Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false))
649
- );
650
- options.setPluginCall(call);
651
-
652
- // Set Material Design picker option
653
- options.setMaterialPicker(
654
- Boolean.TRUE.equals(call.getBoolean("materialPicker", false))
655
- );
656
-
657
- // Set enabledSafeBottomMargin option
658
- options.setEnabledSafeMargin(
659
- Boolean.TRUE.equals(call.getBoolean("enabledSafeBottomMargin", false))
660
- );
661
-
662
- // Use system top inset for WebView margin when explicitly enabled
663
- options.setUseTopInset(
664
- Boolean.TRUE.equals(call.getBoolean("useTopInset", false))
665
- );
666
-
667
- // options.getToolbarItemTypes().add(ToolbarItemType.RELOAD); TODO: fix this
668
- options.setCallbacks(
669
- new WebViewCallbacks() {
670
- @Override
671
- public void urlChangeEvent(String url) {
672
- notifyListeners("urlChangeEvent", new JSObject().put("url", url));
373
+ @PluginMethod
374
+ public void getCookies(PluginCall call) {
375
+ String url = call.getString("url");
376
+ if (url == null || TextUtils.isEmpty(url)) {
377
+ call.reject("Invalid URL");
378
+ return;
673
379
  }
380
+ CookieManager cookieManager = CookieManager.getInstance();
381
+ String cookieString = cookieManager.getCookie(url);
382
+ JSObject result = new JSObject();
383
+ if (cookieString != null) {
384
+ String[] cookiePairs = cookieString.split("; ");
385
+ for (String cookie : cookiePairs) {
386
+ String[] parts = cookie.split("=", 2);
387
+ if (parts.length == 2) {
388
+ result.put(parts[0], parts[1]);
389
+ }
390
+ }
391
+ }
392
+ call.resolve(result);
393
+ }
674
394
 
675
- @Override
676
- public void closeEvent(String url) {
677
- notifyListeners("closeEvent", new JSObject().put("url", url));
395
+ @PluginMethod
396
+ public void openWebView(PluginCall call) {
397
+ String url = call.getString("url");
398
+ if (url == null || TextUtils.isEmpty(url)) {
399
+ call.reject("Invalid URL");
400
+ }
401
+ currentUrl = url;
402
+ final Options options = new Options();
403
+ options.setUrl(url);
404
+ options.setHeaders(call.getObject("headers"));
405
+ options.setCredentials(call.getObject("credentials"));
406
+ options.setShowReloadButton(Boolean.TRUE.equals(call.getBoolean("showReloadButton", false)));
407
+ options.setVisibleTitle(Boolean.TRUE.equals(call.getBoolean("visibleTitle", true)));
408
+ if (Boolean.TRUE.equals(options.getVisibleTitle())) {
409
+ options.setTitle(call.getString("title", "New Window"));
410
+ } else {
411
+ options.setTitle(call.getString("title", ""));
412
+ }
413
+ options.setToolbarColor(call.getString("toolbarColor", "#ffffff"));
414
+ options.setBackgroundColor(call.getString("backgroundColor", "white"));
415
+ options.setToolbarTextColor(call.getString("toolbarTextColor"));
416
+ options.setArrow(Boolean.TRUE.equals(call.getBoolean("showArrow", false)));
417
+ options.setIgnoreUntrustedSSLError(Boolean.TRUE.equals(call.getBoolean("ignoreUntrustedSSLError", false)));
418
+
419
+ // Set text zoom if specified in options (default is 100)
420
+ Integer textZoom = call.getInt("textZoom");
421
+ if (textZoom != null) {
422
+ options.setTextZoom(textZoom);
678
423
  }
679
424
 
680
- @Override
681
- public void pageLoaded() {
682
- notifyListeners("browserPageLoaded", new JSObject());
425
+ String proxyRequestsStr = call.getString("proxyRequests");
426
+ if (proxyRequestsStr != null) {
427
+ try {
428
+ options.setProxyRequestsPattern(Pattern.compile(proxyRequestsStr));
429
+ } catch (PatternSyntaxException e) {
430
+ Log.e("WebViewDialog", String.format("Pattern '%s' is not a valid pattern", proxyRequestsStr));
431
+ }
683
432
  }
684
433
 
685
- @Override
686
- public void pageLoadError() {
687
- notifyListeners("pageLoadError", new JSObject());
434
+ try {
435
+ // Try to set buttonNearDone if present, with better error handling
436
+ JSObject buttonNearDoneObj = call.getObject("buttonNearDone");
437
+ if (buttonNearDoneObj != null) {
438
+ try {
439
+ // Provide better debugging for buttonNearDone
440
+ JSObject androidObj = buttonNearDoneObj.getJSObject("android");
441
+ if (androidObj != null) {
442
+ String iconType = androidObj.getString("iconType", "asset");
443
+ String icon = androidObj.getString("icon", "");
444
+ Log.d("InAppBrowser", "ButtonNearDone config - iconType: " + iconType + ", icon: " + icon);
445
+
446
+ // For vector type, verify if resource exists
447
+ if ("vector".equals(iconType)) {
448
+ int resourceId = getContext().getResources().getIdentifier(icon, "drawable", getContext().getPackageName());
449
+ if (resourceId == 0) {
450
+ Log.e("InAppBrowser", "Vector resource not found: " + icon);
451
+ // List available drawable resources to help debugging
452
+ try {
453
+ final StringBuilder availableResources = getStringBuilder();
454
+ Log.d("InAppBrowser", availableResources.toString());
455
+ } catch (Exception e) {
456
+ Log.e("InAppBrowser", "Error listing resources: " + e.getMessage());
457
+ }
458
+ } else {
459
+ Log.d("InAppBrowser", "Vector resource found with ID: " + resourceId);
460
+ }
461
+ }
462
+ }
463
+
464
+ // Try to create the ButtonNearDone object
465
+ Options.ButtonNearDone buttonNearDone = Options.ButtonNearDone.generateFromPluginCall(call, getContext().getAssets());
466
+ options.setButtonNearDone(buttonNearDone);
467
+ } catch (Exception e) {
468
+ Log.e("InAppBrowser", "Error setting buttonNearDone: " + e.getMessage(), e);
469
+ }
470
+ }
471
+ } catch (Exception e) {
472
+ Log.e("InAppBrowser", "Error processing buttonNearDone: " + e.getMessage(), e);
688
473
  }
689
474
 
690
- @Override
691
- public void buttonNearDoneClicked() {
692
- notifyListeners("buttonNearDoneClick", new JSObject());
475
+ options.setShareDisclaimer(call.getObject("shareDisclaimer", null));
476
+ options.setPreShowScript(call.getString("preShowScript", null));
477
+ options.setShareSubject(call.getString("shareSubject", null));
478
+ options.setToolbarType(call.getString("toolbarType", ""));
479
+ options.setPreventDeeplink(Boolean.TRUE.equals(call.getBoolean("preventDeeplink", false)));
480
+
481
+ // Validate preShowScript requires isPresentAfterPageLoad
482
+ if (call.getData().has("preShowScript") && !Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false))) {
483
+ call.reject("preShowScript requires isPresentAfterPageLoad to be true");
484
+ return;
693
485
  }
694
486
 
695
- @Override
696
- public void confirmBtnClicked(String url) {
697
- notifyListeners("confirmBtnClicked", new JSObject().put("url", url));
487
+ // Validate closeModal options
488
+ if (Boolean.TRUE.equals(call.getBoolean("closeModal", false))) {
489
+ options.setCloseModal(true);
490
+ options.setCloseModalTitle(call.getString("closeModalTitle", "Close"));
491
+ options.setCloseModalDescription(call.getString("closeModalDescription", "Are you sure ?"));
492
+ options.setCloseModalOk(call.getString("closeModalOk", "Ok"));
493
+ options.setCloseModalCancel(call.getString("closeModalCancel", "Cancel"));
494
+ } else {
495
+ // Reject if closeModal is false but closeModal options are provided
496
+ if (
497
+ call.getData().has("closeModalTitle") ||
498
+ call.getData().has("closeModalDescription") ||
499
+ call.getData().has("closeModalOk") ||
500
+ call.getData().has("closeModalCancel")
501
+ ) {
502
+ call.reject("closeModal options require closeModal to be true");
503
+ return;
504
+ }
505
+ options.setCloseModal(false);
698
506
  }
699
507
 
700
- @Override
701
- public void javascriptCallback(String message) {
702
- // Handle the message received from JavaScript
703
- Log.d(
704
- "WebViewDialog",
705
- "Received message from JavaScript: " + message
706
- );
707
- // Process the message as needed
708
- try {
709
- // Parse the received message as a JSON object
710
- JSONObject jsonMessage = new JSONObject(message);
711
-
712
- // Create a new JSObject to send to the Capacitor plugin
713
- JSObject jsObject = new JSObject();
714
-
715
- // Iterate through the keys in the JSON object and add them to the JSObject
716
- Iterator<String> keys = jsonMessage.keys();
717
- while (keys.hasNext()) {
718
- String key = keys.next();
719
- jsObject.put(key, jsonMessage.get(key));
508
+ // Validate shareDisclaimer requires shareSubject
509
+ if (call.getData().has("shareDisclaimer") && !call.getData().has("shareSubject")) {
510
+ call.reject("shareDisclaimer requires shareSubject to be provided");
511
+ return;
512
+ }
513
+
514
+ // Validate buttonNearDone compatibility with toolbar type
515
+ if (call.getData().has("buttonNearDone")) {
516
+ String toolbarType = options.getToolbarType();
517
+ if (
518
+ TextUtils.equals(toolbarType, "activity") ||
519
+ TextUtils.equals(toolbarType, "navigation") ||
520
+ TextUtils.equals(toolbarType, "blank")
521
+ ) {
522
+ call.reject("buttonNearDone is not compatible with toolbarType: " + toolbarType);
523
+ return;
720
524
  }
525
+ }
721
526
 
722
- // Notify listeners with the parsed message
723
- notifyListeners("messageFromWebview", jsObject);
724
- } catch (JSONException e) {
725
- Log.e(
726
- "WebViewDialog",
727
- "Error parsing JSON message: " + e.getMessage()
728
- );
527
+ options.setActiveNativeNavigationForWebview(Boolean.TRUE.equals(call.getBoolean("activeNativeNavigationForWebview", false)));
528
+ options.setDisableGoBackOnNativeApplication(Boolean.TRUE.equals(call.getBoolean("disableGoBackOnNativeApplication", false)));
529
+ options.setPresentAfterPageLoad(Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false)));
530
+ options.setPluginCall(call);
531
+
532
+ // Set Material Design picker option
533
+ options.setMaterialPicker(Boolean.TRUE.equals(call.getBoolean("materialPicker", false)));
534
+
535
+ // Set enabledSafeBottomMargin option
536
+ options.setEnabledSafeMargin(Boolean.TRUE.equals(call.getBoolean("enabledSafeBottomMargin", false)));
537
+
538
+ // Use system top inset for WebView margin when explicitly enabled
539
+ options.setUseTopInset(Boolean.TRUE.equals(call.getBoolean("useTopInset", false)));
729
540
 
730
- // If JSON parsing fails, send the raw message as a string
731
- JSObject jsObject = new JSObject();
732
- jsObject.put("rawMessage", message);
733
- notifyListeners("messageFromWebview", jsObject);
734
- }
541
+ // options.getToolbarItemTypes().add(ToolbarItemType.RELOAD); TODO: fix this
542
+ options.setCallbacks(
543
+ new WebViewCallbacks() {
544
+ @Override
545
+ public void urlChangeEvent(String url) {
546
+ notifyListeners("urlChangeEvent", new JSObject().put("url", url));
547
+ }
548
+
549
+ @Override
550
+ public void closeEvent(String url) {
551
+ notifyListeners("closeEvent", new JSObject().put("url", url));
552
+ }
553
+
554
+ @Override
555
+ public void pageLoaded() {
556
+ notifyListeners("browserPageLoaded", new JSObject());
557
+ }
558
+
559
+ @Override
560
+ public void pageLoadError() {
561
+ notifyListeners("pageLoadError", new JSObject());
562
+ }
563
+
564
+ @Override
565
+ public void buttonNearDoneClicked() {
566
+ notifyListeners("buttonNearDoneClick", new JSObject());
567
+ }
568
+
569
+ @Override
570
+ public void confirmBtnClicked(String url) {
571
+ notifyListeners("confirmBtnClicked", new JSObject().put("url", url));
572
+ }
573
+
574
+ @Override
575
+ public void javascriptCallback(String message) {
576
+ // Handle the message received from JavaScript
577
+ Log.d("WebViewDialog", "Received message from JavaScript: " + message);
578
+ // Process the message as needed
579
+ try {
580
+ // Parse the received message as a JSON object
581
+ JSONObject jsonMessage = new JSONObject(message);
582
+
583
+ // Create a new JSObject to send to the Capacitor plugin
584
+ JSObject jsObject = new JSObject();
585
+
586
+ // Iterate through the keys in the JSON object and add them to the JSObject
587
+ Iterator<String> keys = jsonMessage.keys();
588
+ while (keys.hasNext()) {
589
+ String key = keys.next();
590
+ jsObject.put(key, jsonMessage.get(key));
591
+ }
592
+
593
+ // Notify listeners with the parsed message
594
+ notifyListeners("messageFromWebview", jsObject);
595
+ } catch (JSONException e) {
596
+ Log.e("WebViewDialog", "Error parsing JSON message: " + e.getMessage());
597
+
598
+ // If JSON parsing fails, send the raw message as a string
599
+ JSObject jsObject = new JSObject();
600
+ jsObject.put("rawMessage", message);
601
+ notifyListeners("messageFromWebview", jsObject);
602
+ }
603
+ }
604
+ }
605
+ );
606
+
607
+ JSArray jsAuthorizedLinks = call.getArray("authorizedAppLinks");
608
+ if (jsAuthorizedLinks != null && jsAuthorizedLinks.length() > 0) {
609
+ List<String> authorizedLinks = new ArrayList<>();
610
+ for (int i = 0; i < jsAuthorizedLinks.length(); i++) {
611
+ try {
612
+ String link = jsAuthorizedLinks.getString(i);
613
+ if (link != null && !link.trim().isEmpty()) {
614
+ authorizedLinks.add(link);
615
+ }
616
+ } catch (Exception e) {
617
+ Log.w("InAppBrowserPlugin", "Error reading authorized app link at index " + i, e);
618
+ }
619
+ }
620
+ Log.d("InAppBrowserPlugin", "Parsed authorized app links: " + authorizedLinks);
621
+ options.setAuthorizedAppLinks(authorizedLinks);
622
+ } else {
623
+ Log.d("InAppBrowserPlugin", "No authorized app links provided.");
735
624
  }
736
- }
737
- );
738
625
 
739
- JSArray jsAuthorizedLinks = call.getArray("authorizedAppLinks");
740
- if (jsAuthorizedLinks != null && jsAuthorizedLinks.length() > 0) {
741
- List<String> authorizedLinks = new ArrayList<>();
742
- for (int i = 0; i < jsAuthorizedLinks.length(); i++) {
743
- try {
744
- String link = jsAuthorizedLinks.getString(i);
745
- if (link != null && !link.trim().isEmpty()) {
746
- authorizedLinks.add(link);
747
- }
748
- } catch (Exception e) {
749
- Log.w(
750
- "InAppBrowserPlugin",
751
- "Error reading authorized app link at index " + i,
752
- e
753
- );
626
+ JSArray blockedHostsRaw = call.getArray("blockedHosts");
627
+ if (blockedHostsRaw != null && blockedHostsRaw.length() > 0) {
628
+ List<String> blockedHosts = new ArrayList<>();
629
+ for (int i = 0; i < blockedHostsRaw.length(); i++) {
630
+ try {
631
+ String host = blockedHostsRaw.getString(i);
632
+ if (host != null && !host.trim().isEmpty()) {
633
+ blockedHosts.add(host);
634
+ }
635
+ } catch (Exception e) {
636
+ Log.w("InAppBrowserPlugin", "Error reading blocked host at index " + i, e);
637
+ }
638
+ }
639
+ Log.d("InAppBrowserPlugin", "Parsed blocked hosts: " + blockedHosts);
640
+ options.setBlockedHosts(blockedHosts);
641
+ } else {
642
+ Log.d("InAppBrowserPlugin", "No blocked hosts provided.");
754
643
  }
755
- }
756
- Log.d(
757
- "InAppBrowserPlugin",
758
- "Parsed authorized app links: " + authorizedLinks
759
- );
760
- options.setAuthorizedAppLinks(authorizedLinks);
761
- } else {
762
- Log.d("InAppBrowserPlugin", "No authorized app links provided.");
644
+
645
+ // Set Google Pay support option
646
+ options.setEnableGooglePaySupport(Boolean.TRUE.equals(call.getBoolean("enableGooglePaySupport", false)));
647
+
648
+ this.getActivity().runOnUiThread(
649
+ new Runnable() {
650
+ @Override
651
+ public void run() {
652
+ webViewDialog = new WebViewDialog(
653
+ getContext(),
654
+ android.R.style.Theme_NoTitleBar,
655
+ options,
656
+ InAppBrowserPlugin.this,
657
+ getBridge().getWebView()
658
+ );
659
+ webViewDialog.activity = InAppBrowserPlugin.this.getActivity();
660
+ webViewDialog.presentWebView();
661
+ }
662
+ }
663
+ );
763
664
  }
764
665
 
765
- JSArray blockedHostsRaw = call.getArray("blockedHosts");
766
- if (blockedHostsRaw != null && blockedHostsRaw.length() > 0) {
767
- List<String> blockedHosts = new ArrayList<>();
768
- for (int i = 0; i < blockedHostsRaw.length(); i++) {
769
- try {
770
- String host = blockedHostsRaw.getString(i);
771
- if (host != null && !host.trim().isEmpty()) {
772
- blockedHosts.add(host);
773
- }
774
- } catch (Exception e) {
775
- Log.w(
776
- "InAppBrowserPlugin",
777
- "Error reading blocked host at index " + i,
778
- e
779
- );
666
+ @NonNull
667
+ private static StringBuilder getStringBuilder() {
668
+ Field[] drawables = R.drawable.class.getFields();
669
+ StringBuilder availableResources = new StringBuilder("Available resources: ");
670
+ for (int i = 0; i < Math.min(10, drawables.length); i++) {
671
+ availableResources.append(drawables[i].getName()).append(", ");
780
672
  }
781
- }
782
- Log.d("InAppBrowserPlugin", "Parsed blocked hosts: " + blockedHosts);
783
- options.setBlockedHosts(blockedHosts);
784
- } else {
785
- Log.d("InAppBrowserPlugin", "No blocked hosts provided.");
673
+ if (drawables.length > 10) {
674
+ availableResources.append("... (").append(drawables.length - 10).append(" more)");
675
+ }
676
+ return availableResources;
786
677
  }
787
678
 
788
- // Set Google Pay support option
789
- options.setEnableGooglePaySupport(
790
- Boolean.TRUE.equals(call.getBoolean("enableGooglePaySupport", false))
791
- );
792
-
793
- this.getActivity()
794
- .runOnUiThread(
795
- new Runnable() {
796
- @Override
797
- public void run() {
798
- webViewDialog = new WebViewDialog(
799
- getContext(),
800
- android.R.style.Theme_NoTitleBar,
801
- options,
802
- InAppBrowserPlugin.this,
803
- getBridge().getWebView()
804
- );
805
- webViewDialog.activity = InAppBrowserPlugin.this.getActivity();
806
- webViewDialog.presentWebView();
807
- }
679
+ @PluginMethod
680
+ public void postMessage(PluginCall call) {
681
+ if (webViewDialog == null) {
682
+ call.reject("WebView is not initialized");
683
+ return;
684
+ }
685
+ JSObject eventData = call.getObject("detail");
686
+ // Log event data
687
+ if (eventData == null) {
688
+ call.reject("No event data provided");
689
+ return;
808
690
  }
809
- );
810
- }
811
-
812
- @NonNull
813
- private static StringBuilder getStringBuilder() {
814
- Field[] drawables = R.drawable.class.getFields();
815
- StringBuilder availableResources = new StringBuilder(
816
- "Available resources: "
817
- );
818
- for (int i = 0; i < Math.min(10, drawables.length); i++) {
819
- availableResources.append(drawables[i].getName()).append(", ");
691
+
692
+ Log.d("InAppBrowserPlugin", "Event data: " + eventData.toString());
693
+ this.getActivity().runOnUiThread(
694
+ new Runnable() {
695
+ @Override
696
+ public void run() {
697
+ if (webViewDialog != null) {
698
+ webViewDialog.postMessageToJS(eventData);
699
+ call.resolve();
700
+ } else {
701
+ call.reject("WebView is not initialized");
702
+ }
703
+ }
704
+ }
705
+ );
820
706
  }
821
- if (drawables.length > 10) {
822
- availableResources
823
- .append("... (")
824
- .append(drawables.length - 10)
825
- .append(" more)");
707
+
708
+ @PluginMethod
709
+ public void executeScript(PluginCall call) {
710
+ String script = call.getString("code");
711
+ if (script == null || script.trim().isEmpty()) {
712
+ call.reject("Script is required");
713
+ return;
714
+ }
715
+
716
+ if (webViewDialog == null) {
717
+ call.reject("WebView is not initialized");
718
+ return;
719
+ }
720
+
721
+ this.getActivity().runOnUiThread(
722
+ new Runnable() {
723
+ @Override
724
+ public void run() {
725
+ try {
726
+ if (webViewDialog != null) {
727
+ webViewDialog.executeScript(script);
728
+ call.resolve();
729
+ } else {
730
+ call.reject("WebView is not initialized");
731
+ }
732
+ } catch (Exception e) {
733
+ Log.e("InAppBrowser", "Error executing script: " + e.getMessage());
734
+ call.reject("Failed to execute script: " + e.getMessage());
735
+ }
736
+ }
737
+ }
738
+ );
826
739
  }
827
- return availableResources;
828
- }
829
-
830
- @PluginMethod
831
- public void postMessage(PluginCall call) {
832
- if (webViewDialog == null) {
833
- call.reject("WebView is not initialized");
834
- return;
740
+
741
+ @PluginMethod
742
+ public void goBack(PluginCall call) {
743
+ this.getActivity().runOnUiThread(
744
+ new Runnable() {
745
+ @Override
746
+ public void run() {
747
+ if (webViewDialog != null) {
748
+ boolean canGoBack = webViewDialog.goBack();
749
+ JSObject result = new JSObject();
750
+ result.put("canGoBack", canGoBack);
751
+ call.resolve(result);
752
+ } else {
753
+ JSObject result = new JSObject();
754
+ result.put("canGoBack", false);
755
+ call.resolve(result);
756
+ }
757
+ }
758
+ }
759
+ );
835
760
  }
836
- JSObject eventData = call.getObject("detail");
837
- // Log event data
838
- if (eventData == null) {
839
- call.reject("No event data provided");
840
- return;
761
+
762
+ @PluginMethod
763
+ public void reload(PluginCall call) {
764
+ this.getActivity().runOnUiThread(
765
+ new Runnable() {
766
+ @Override
767
+ public void run() {
768
+ if (webViewDialog != null) {
769
+ webViewDialog.reload();
770
+ call.resolve();
771
+ } else {
772
+ call.reject("WebView is not initialized");
773
+ }
774
+ }
775
+ }
776
+ );
841
777
  }
842
778
 
843
- Log.d("InAppBrowserPlugin", "Event data: " + eventData.toString());
844
- this.getActivity()
845
- .runOnUiThread(
846
- new Runnable() {
847
- @Override
848
- public void run() {
849
- if (webViewDialog != null) {
850
- webViewDialog.postMessageToJS(eventData);
851
- call.resolve();
779
+ @PluginMethod
780
+ public void lsuakdchgbbaHandleProxiedRequest(PluginCall call) {
781
+ if (webViewDialog != null) {
782
+ Boolean ok = call.getBoolean("ok", false);
783
+ String id = call.getString("id");
784
+ if (id == null) {
785
+ Log.e("InAppBrowserProxy", "CRITICAL ERROR, proxy id = null");
786
+ return;
787
+ }
788
+ if (Boolean.FALSE.equals(ok)) {
789
+ String result = call.getString("result", "");
790
+ webViewDialog.handleProxyResultError(result, id);
852
791
  } else {
853
- call.reject("WebView is not initialized");
792
+ JSONObject object = call.getObject("result");
793
+ webViewDialog.handleProxyResultOk(object, id);
854
794
  }
855
- }
856
795
  }
857
- );
858
- }
859
-
860
- @PluginMethod
861
- public void executeScript(PluginCall call) {
862
- String script = call.getString("code");
863
- if (script == null || script.trim().isEmpty()) {
864
- call.reject("Script is required");
865
- return;
866
- }
867
-
868
- if (webViewDialog == null) {
869
- call.reject("WebView is not initialized");
870
- return;
796
+ call.resolve();
871
797
  }
872
798
 
873
- this.getActivity()
874
- .runOnUiThread(
875
- new Runnable() {
876
- @Override
877
- public void run() {
799
+ @PluginMethod
800
+ public void close(PluginCall call) {
801
+ if (webViewDialog == null) {
802
+ // Fallback: try to bring main activity to foreground
878
803
  try {
879
- if (webViewDialog != null) {
880
- webViewDialog.executeScript(script);
804
+ Intent intent = new Intent(getContext(), getBridge().getActivity().getClass());
805
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
806
+ getContext().startActivity(intent);
881
807
  call.resolve();
882
- } else {
883
- call.reject("WebView is not initialized");
884
- }
885
808
  } catch (Exception e) {
886
- Log.e(
887
- "InAppBrowser",
888
- "Error executing script: " + e.getMessage()
889
- );
890
- call.reject("Failed to execute script: " + e.getMessage());
809
+ Log.e("InAppBrowser", "Error bringing main activity to foreground: " + e.getMessage());
810
+ call.reject("WebView is not initialized and failed to restore main activity");
891
811
  }
892
- }
812
+ return;
893
813
  }
894
- );
895
- }
896
-
897
- @PluginMethod
898
- public void goBack(PluginCall call) {
899
- this.getActivity()
900
- .runOnUiThread(
901
- new Runnable() {
902
- @Override
903
- public void run() {
904
- if (webViewDialog != null) {
905
- boolean canGoBack = webViewDialog.goBack();
906
- JSObject result = new JSObject();
907
- result.put("canGoBack", canGoBack);
908
- call.resolve(result);
909
- } else {
910
- JSObject result = new JSObject();
911
- result.put("canGoBack", false);
912
- call.resolve(result);
913
- }
914
- }
915
- }
916
- );
917
- }
918
-
919
- @PluginMethod
920
- public void reload(PluginCall call) {
921
- this.getActivity()
922
- .runOnUiThread(
923
- new Runnable() {
924
- @Override
925
- public void run() {
926
- if (webViewDialog != null) {
927
- webViewDialog.reload();
928
- call.resolve();
929
- } else {
930
- call.reject("WebView is not initialized");
814
+
815
+ this.getActivity().runOnUiThread(
816
+ new Runnable() {
817
+ @Override
818
+ public void run() {
819
+ try {
820
+ if (webViewDialog != null) {
821
+ String currentUrl = "";
822
+ try {
823
+ currentUrl = webViewDialog.getUrl();
824
+ if (currentUrl == null) {
825
+ currentUrl = "";
826
+ }
827
+ } catch (Exception e) {
828
+ Log.e("InAppBrowser", "Error getting URL before close: " + e.getMessage());
829
+ currentUrl = "";
830
+ }
831
+
832
+ // Notify listeners about the close event
833
+ notifyListeners("closeEvent", new JSObject().put("url", currentUrl));
834
+
835
+ webViewDialog.dismiss();
836
+ webViewDialog = null;
837
+ call.resolve();
838
+ } else {
839
+ // Secondary fallback inside UI thread
840
+ try {
841
+ Intent intent = new Intent(getContext(), getBridge().getActivity().getClass());
842
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
843
+ getContext().startActivity(intent);
844
+ call.resolve();
845
+ } catch (Exception e) {
846
+ Log.e("InAppBrowser", "Error in secondary fallback: " + e.getMessage());
847
+ call.reject("WebView is not initialized");
848
+ }
849
+ }
850
+ } catch (Exception e) {
851
+ Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
852
+ call.reject("Failed to close WebView: " + e.getMessage());
853
+ }
854
+ }
931
855
  }
932
- }
933
- }
934
- );
935
- }
936
-
937
- @PluginMethod
938
- public void lsuakdchgbbaHandleProxiedRequest(PluginCall call) {
939
- if (webViewDialog != null) {
940
- Boolean ok = call.getBoolean("ok", false);
941
- String id = call.getString("id");
942
- if (id == null) {
943
- Log.e("InAppBrowserProxy", "CRITICAL ERROR, proxy id = null");
944
- return;
945
- }
946
- if (Boolean.FALSE.equals(ok)) {
947
- String result = call.getString("result", "");
948
- webViewDialog.handleProxyResultError(result, id);
949
- } else {
950
- JSONObject object = call.getObject("result");
951
- webViewDialog.handleProxyResultOk(object, id);
952
- }
953
- }
954
- call.resolve();
955
- }
956
-
957
- @PluginMethod
958
- public void close(PluginCall call) {
959
- if (webViewDialog == null) {
960
- // Fallback: try to bring main activity to foreground
961
- try {
962
- Intent intent = new Intent(
963
- getContext(),
964
- getBridge().getActivity().getClass()
965
856
  );
966
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
967
- getContext().startActivity(intent);
968
- call.resolve();
969
- } catch (Exception e) {
970
- Log.e(
971
- "InAppBrowser",
972
- "Error bringing main activity to foreground: " + e.getMessage()
973
- );
974
- call.reject(
975
- "WebView is not initialized and failed to restore main activity"
976
- );
977
- }
978
- return;
979
857
  }
980
858
 
981
- this.getActivity()
982
- .runOnUiThread(
983
- new Runnable() {
984
- @Override
985
- public void run() {
986
- try {
987
- if (webViewDialog != null) {
988
- String currentUrl = "";
989
- try {
990
- currentUrl = webViewDialog.getUrl();
991
- if (currentUrl == null) {
992
- currentUrl = "";
993
- }
994
- } catch (Exception e) {
995
- Log.e(
996
- "InAppBrowser",
997
- "Error getting URL before close: " + e.getMessage()
998
- );
999
- currentUrl = "";
1000
- }
1001
-
1002
- // Notify listeners about the close event
1003
- notifyListeners(
1004
- "closeEvent",
1005
- new JSObject().put("url", currentUrl)
1006
- );
1007
-
1008
- webViewDialog.dismiss();
1009
- webViewDialog = null;
1010
- call.resolve();
1011
- } else {
1012
- // Secondary fallback inside UI thread
1013
- try {
1014
- Intent intent = new Intent(
1015
- getContext(),
1016
- getBridge().getActivity().getClass()
1017
- );
1018
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1019
- getContext().startActivity(intent);
1020
- call.resolve();
1021
- } catch (Exception e) {
1022
- Log.e(
1023
- "InAppBrowser",
1024
- "Error in secondary fallback: " + e.getMessage()
1025
- );
1026
- call.reject("WebView is not initialized");
1027
- }
1028
- }
1029
- } catch (Exception e) {
1030
- Log.e("InAppBrowser", "Error closing WebView: " + e.getMessage());
1031
- call.reject("Failed to close WebView: " + e.getMessage());
859
+ private Bundle getHeaders(PluginCall pluginCall) {
860
+ JSObject headersProvided = pluginCall.getObject("headers");
861
+ Bundle headers = new Bundle();
862
+ if (headersProvided != null) {
863
+ Iterator<String> keys = headersProvided.keys();
864
+ while (keys.hasNext()) {
865
+ String key = keys.next();
866
+ headers.putString(key, headersProvided.getString(key));
1032
867
  }
1033
- }
1034
868
  }
1035
- );
1036
- }
1037
-
1038
- private Bundle getHeaders(PluginCall pluginCall) {
1039
- JSObject headersProvided = pluginCall.getObject("headers");
1040
- Bundle headers = new Bundle();
1041
- if (headersProvided != null) {
1042
- Iterator<String> keys = headersProvided.keys();
1043
- while (keys.hasNext()) {
1044
- String key = keys.next();
1045
- headers.putString(key, headersProvided.getString(key));
1046
- }
869
+ return headers;
870
+ }
871
+
872
+ protected void handleOnResume() {
873
+ boolean ok = CustomTabsClient.bindCustomTabsService(getContext(), CUSTOM_TAB_PACKAGE_NAME, connection);
874
+ if (!ok) {
875
+ Log.e(getLogTag(), "Error binding to custom tabs service");
876
+ }
1047
877
  }
1048
- return headers;
1049
- }
1050
-
1051
- protected void handleOnResume() {
1052
- boolean ok = CustomTabsClient.bindCustomTabsService(
1053
- getContext(),
1054
- CUSTOM_TAB_PACKAGE_NAME,
1055
- connection
1056
- );
1057
- if (!ok) {
1058
- Log.e(getLogTag(), "Error binding to custom tabs service");
878
+
879
+ protected void handleOnPause() {
880
+ getContext().unbindService(connection);
1059
881
  }
1060
- }
1061
882
 
1062
- protected void handleOnPause() {
1063
- getContext().unbindService(connection);
1064
- }
883
+ public CustomTabsSession getCustomTabsSession() {
884
+ if (customTabsClient == null) {
885
+ return null;
886
+ }
1065
887
 
1066
- public CustomTabsSession getCustomTabsSession() {
1067
- if (customTabsClient == null) {
1068
- return null;
888
+ if (currentSession == null) {
889
+ currentSession = customTabsClient.newSession(
890
+ new CustomTabsCallback() {
891
+ @Override
892
+ public void onNavigationEvent(int navigationEvent, Bundle extras) {
893
+ // Only fire browserPageLoaded for Custom Tabs, not for WebView
894
+ if (navigationEvent == NAVIGATION_FINISHED && webViewDialog == null) {
895
+ notifyListeners("browserPageLoaded", new JSObject());
896
+ }
897
+ }
898
+ }
899
+ );
900
+ }
901
+ return currentSession;
1069
902
  }
1070
903
 
1071
- if (currentSession == null) {
1072
- currentSession = customTabsClient.newSession(
1073
- new CustomTabsCallback() {
1074
- @Override
1075
- public void onNavigationEvent(int navigationEvent, Bundle extras) {
1076
- // Only fire browserPageLoaded for Custom Tabs, not for WebView
1077
- if (
1078
- navigationEvent == NAVIGATION_FINISHED && webViewDialog == null
1079
- ) {
1080
- notifyListeners("browserPageLoaded", new JSObject());
904
+ @Override
905
+ protected void handleOnDestroy() {
906
+ if (webViewDialog != null) {
907
+ try {
908
+ webViewDialog.dismiss();
909
+ } catch (Exception e) {
910
+ // Ignore, dialog may already be dismissed
1081
911
  }
1082
- }
912
+ webViewDialog = null;
1083
913
  }
1084
- );
1085
- }
1086
- return currentSession;
1087
- }
1088
-
1089
- @Override
1090
- protected void handleOnDestroy() {
1091
- if (webViewDialog != null) {
1092
- try {
1093
- webViewDialog.dismiss();
1094
- } catch (Exception e) {
1095
- // Ignore, dialog may already be dismissed
1096
- }
1097
- webViewDialog = null;
914
+ currentPermissionRequest = null;
915
+ customTabsClient = null;
916
+ currentSession = null;
917
+ super.handleOnDestroy();
1098
918
  }
1099
- currentPermissionRequest = null;
1100
- customTabsClient = null;
1101
- currentSession = null;
1102
- super.handleOnDestroy();
1103
- }
1104
919
  }