@capgo/capacitor-inappbrowser 8.14.3 → 8.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -2
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/BundledAssetSupport.java +397 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +43 -7
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/FileChooserRequestSupport.java +57 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +39 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +410 -278
- package/dist/docs.json +14 -2
- package/dist/esm/bundled-asset-support.d.ts +40 -0
- package/dist/esm/bundled-asset-support.js +157 -0
- package/dist/esm/bundled-asset-support.js.map +1 -0
- package/dist/esm/definitions.d.ts +17 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +43 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/plugin.cjs.js +199 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +199 -1
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/BundledAssetSchemeHandler.swift +188 -0
- package/ios/Sources/InAppBrowserPlugin/BundledAssetSupport.swift +221 -0
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +26 -4
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +21 -0
- package/package.json +2 -2
|
@@ -81,6 +81,7 @@ import androidx.core.view.WindowInsetsControllerCompat;
|
|
|
81
81
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
82
82
|
import androidx.webkit.WebMessageCompat;
|
|
83
83
|
import androidx.webkit.WebSettingsCompat;
|
|
84
|
+
import androidx.webkit.WebViewAssetLoader;
|
|
84
85
|
import androidx.webkit.WebViewCompat;
|
|
85
86
|
import androidx.webkit.WebViewFeature;
|
|
86
87
|
import com.caverock.androidsvg.SVG;
|
|
@@ -344,6 +345,8 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
344
345
|
private String instanceId = "";
|
|
345
346
|
private final Map<String, ProxiedRequest> proxiedRequestsHashmap = new ConcurrentHashMap<>();
|
|
346
347
|
private ProxyBridge proxyBridge;
|
|
348
|
+
private volatile WebViewAssetLoader bundledAssetLoader;
|
|
349
|
+
private final Object bundledAssetLoaderLock = new Object();
|
|
347
350
|
private String proxyBridgeScript;
|
|
348
351
|
private String proxyAccessToken;
|
|
349
352
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
|
@@ -409,6 +412,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
409
412
|
public static final int FILE_CHOOSER_REQUEST_CODE = 1000;
|
|
410
413
|
public ValueCallback<Uri> mUploadMessage;
|
|
411
414
|
public ValueCallback<Uri[]> mFilePathCallback;
|
|
415
|
+
FileChooserRequestSupport.FileChooserRequest activeFileChooserRequest;
|
|
412
416
|
private boolean openWebViewResolved;
|
|
413
417
|
private boolean isDismissing = false;
|
|
414
418
|
private PermissionRequest pendingCameraLaunchPermissionRequest;
|
|
@@ -2232,6 +2236,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2232
2236
|
_webView.addJavascriptInterface(proxyBridge, "__capgoProxy");
|
|
2233
2237
|
proxyBridgeScript = loadProxyBridgeScript();
|
|
2234
2238
|
}
|
|
2239
|
+
ensureBundledAssetLoader();
|
|
2235
2240
|
_webView.getSettings().setJavaScriptEnabled(true);
|
|
2236
2241
|
_webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
|
|
2237
2242
|
_webView.getSettings().setDatabaseEnabled(true);
|
|
@@ -2344,12 +2349,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2344
2349
|
);
|
|
2345
2350
|
|
|
2346
2351
|
// Check if the file chooser is already open
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
}
|
|
2351
|
-
|
|
2352
|
-
mFilePathCallback = filePathCallback;
|
|
2352
|
+
final boolean isMultiple = fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE;
|
|
2353
|
+
beginFileChooserRequest(filePathCallback, acceptType, isMultiple);
|
|
2354
|
+
final FileChooserRequestSupport.FileChooserRequest request = activeFileChooserRequest;
|
|
2353
2355
|
|
|
2354
2356
|
// Direct check for capture attribute in URL (fallback method)
|
|
2355
2357
|
boolean isCaptureInUrl;
|
|
@@ -2424,12 +2426,16 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2424
2426
|
""";
|
|
2425
2427
|
|
|
2426
2428
|
webView.evaluateJavascript(js, (value) -> {
|
|
2429
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2427
2433
|
Log.d("InAppBrowser", "Capture attribute JS result: " + value);
|
|
2428
2434
|
|
|
2429
2435
|
// If we already found capture in URL, use that directly
|
|
2430
2436
|
if (isCaptureInUrl) {
|
|
2431
2437
|
Log.d("InAppBrowser", "Using capture from URL: " + captureMode);
|
|
2432
|
-
launchCamera(captureMode.equals("user"));
|
|
2438
|
+
launchCamera(captureMode.equals("user"), request);
|
|
2433
2439
|
return;
|
|
2434
2440
|
}
|
|
2435
2441
|
|
|
@@ -2440,7 +2446,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2440
2446
|
Log.d("InAppBrowser", "Found capture attribute: " + captureValue);
|
|
2441
2447
|
|
|
2442
2448
|
if (!captureValue.isEmpty()) {
|
|
2443
|
-
activity.runOnUiThread(() -> launchCamera(captureValue.equals("user")));
|
|
2449
|
+
activity.runOnUiThread(() -> launchCamera(captureValue.equals("user"), request));
|
|
2444
2450
|
return;
|
|
2445
2451
|
}
|
|
2446
2452
|
}
|
|
@@ -2448,6 +2454,10 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2448
2454
|
// Look for hints in the web page source
|
|
2449
2455
|
Log.d("InAppBrowser", "Looking for camera hints in page content");
|
|
2450
2456
|
webView.evaluateJavascript("(function() { return document.documentElement.innerHTML; })()", (htmlSource) -> {
|
|
2457
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2451
2461
|
if (htmlSource != null && htmlSource.length() > 10) {
|
|
2452
2462
|
boolean hasCameraOrSelfieKeyword =
|
|
2453
2463
|
htmlSource.contains("capture=") || htmlSource.contains("camera") || htmlSource.contains("selfie");
|
|
@@ -2460,25 +2470,21 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2460
2470
|
(currentUrl.contains("selfie") || currentUrl.contains("camera") || currentUrl.contains("photo"))
|
|
2461
2471
|
) {
|
|
2462
2472
|
Log.d("InAppBrowser", "URL suggests camera usage, launching camera");
|
|
2463
|
-
activity.runOnUiThread(() -> launchCamera(currentUrl.contains("selfie")));
|
|
2473
|
+
activity.runOnUiThread(() -> launchCamera(currentUrl.contains("selfie"), request));
|
|
2464
2474
|
return;
|
|
2465
2475
|
}
|
|
2466
2476
|
}
|
|
2467
2477
|
|
|
2468
2478
|
// If all detection methods fail, fall back to regular file picker
|
|
2469
2479
|
Log.d("InAppBrowser", "No capture attribute detected, using file picker");
|
|
2470
|
-
openFileChooser(
|
|
2471
|
-
filePathCallback,
|
|
2472
|
-
acceptType,
|
|
2473
|
-
fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE
|
|
2474
|
-
);
|
|
2480
|
+
openFileChooser(request);
|
|
2475
2481
|
});
|
|
2476
2482
|
});
|
|
2477
2483
|
return true;
|
|
2478
2484
|
}
|
|
2479
2485
|
|
|
2480
2486
|
// For non-image types, use regular file picker
|
|
2481
|
-
openFileChooser(
|
|
2487
|
+
openFileChooser(request);
|
|
2482
2488
|
return true;
|
|
2483
2489
|
}
|
|
2484
2490
|
|
|
@@ -2486,7 +2492,11 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2486
2492
|
* Launch the camera app for capturing images
|
|
2487
2493
|
* @param useFrontCamera true to use front camera, false for back camera
|
|
2488
2494
|
*/
|
|
2489
|
-
private void launchCamera(boolean useFrontCamera) {
|
|
2495
|
+
private void launchCamera(boolean useFrontCamera, FileChooserRequestSupport.FileChooserRequest request) {
|
|
2496
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2490
2500
|
Log.d("InAppBrowser", "Launching camera, front camera: " + useFrontCamera);
|
|
2491
2501
|
|
|
2492
2502
|
// First check if we have camera permission
|
|
@@ -2510,8 +2520,11 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2510
2520
|
Log.d("InAppBrowser", "Ignoring delayed camera permission grant during dismiss");
|
|
2511
2521
|
return;
|
|
2512
2522
|
}
|
|
2523
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2513
2526
|
// Permission granted, now launch the camera
|
|
2514
|
-
launchCameraWithPermission(useFrontCamera);
|
|
2527
|
+
launchCameraWithPermission(useFrontCamera, request);
|
|
2515
2528
|
}
|
|
2516
2529
|
|
|
2517
2530
|
@Override
|
|
@@ -2521,9 +2534,12 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2521
2534
|
Log.d("InAppBrowser", "Ignoring delayed camera permission denial during dismiss");
|
|
2522
2535
|
return;
|
|
2523
2536
|
}
|
|
2537
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
2524
2540
|
// Permission denied, fall back to file picker
|
|
2525
2541
|
Log.e("InAppBrowser", "Camera permission denied, falling back to file picker");
|
|
2526
|
-
fallbackToFilePicker();
|
|
2542
|
+
fallbackToFilePicker(request);
|
|
2527
2543
|
}
|
|
2528
2544
|
};
|
|
2529
2545
|
|
|
@@ -2535,13 +2551,17 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2535
2551
|
}
|
|
2536
2552
|
|
|
2537
2553
|
// If we can't request permission, try launching directly
|
|
2538
|
-
launchCameraWithPermission(useFrontCamera);
|
|
2554
|
+
launchCameraWithPermission(useFrontCamera, request);
|
|
2539
2555
|
}
|
|
2540
2556
|
|
|
2541
2557
|
/**
|
|
2542
2558
|
* Launch camera after permission is granted
|
|
2543
2559
|
*/
|
|
2544
|
-
private void launchCameraWithPermission(boolean useFrontCamera) {
|
|
2560
|
+
private void launchCameraWithPermission(boolean useFrontCamera, FileChooserRequestSupport.FileChooserRequest request) {
|
|
2561
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2545
2565
|
try {
|
|
2546
2566
|
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
|
2547
2567
|
if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
|
|
@@ -2550,17 +2570,18 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2550
2570
|
photoFile = createImageFile();
|
|
2551
2571
|
} catch (IOException ex) {
|
|
2552
2572
|
Log.e("InAppBrowser", "Error creating image file", ex);
|
|
2553
|
-
fallbackToFilePicker();
|
|
2573
|
+
fallbackToFilePicker(request);
|
|
2554
2574
|
return;
|
|
2555
2575
|
}
|
|
2556
2576
|
|
|
2557
2577
|
if (photoFile != null) {
|
|
2558
|
-
tempCameraUri = FileProvider.getUriForFile(
|
|
2578
|
+
request.tempCameraUri = FileProvider.getUriForFile(
|
|
2559
2579
|
activity,
|
|
2560
2580
|
activity.getPackageName() + ".fileprovider",
|
|
2561
2581
|
photoFile
|
|
2562
2582
|
);
|
|
2563
|
-
|
|
2583
|
+
syncFileChooserPublicFields();
|
|
2584
|
+
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, request.tempCameraUri);
|
|
2564
2585
|
|
|
2565
2586
|
if (useFrontCamera) {
|
|
2566
2587
|
takePictureIntent.putExtra("android.intent.extras.CAMERA_FACING", 1);
|
|
@@ -2576,15 +2597,23 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2576
2597
|
"camera_capture",
|
|
2577
2598
|
new androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult(),
|
|
2578
2599
|
(result) -> {
|
|
2579
|
-
if (
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2600
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
Uri[] results = null;
|
|
2604
|
+
if (result.getResultCode() == Activity.RESULT_OK && request.tempCameraUri != null) {
|
|
2605
|
+
results = new Uri[] { request.tempCameraUri };
|
|
2606
|
+
}
|
|
2607
|
+
if (
|
|
2608
|
+
FileChooserRequestSupport.completeIfActive(
|
|
2609
|
+
request,
|
|
2610
|
+
activeFileChooserRequest,
|
|
2611
|
+
results
|
|
2612
|
+
)
|
|
2613
|
+
) {
|
|
2614
|
+
request.tempCameraUri = null;
|
|
2615
|
+
clearActiveFileChooserRequest(request);
|
|
2585
2616
|
}
|
|
2586
|
-
mFilePathCallback = null;
|
|
2587
|
-
tempCameraUri = null;
|
|
2588
2617
|
}
|
|
2589
2618
|
)
|
|
2590
2619
|
.launch(takePictureIntent);
|
|
@@ -2594,26 +2623,27 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
2594
2623
|
}
|
|
2595
2624
|
} catch (SecurityException e) {
|
|
2596
2625
|
Log.e("InAppBrowser", "Security exception launching camera: " + e.getMessage(), e);
|
|
2597
|
-
fallbackToFilePicker();
|
|
2626
|
+
fallbackToFilePicker(request);
|
|
2598
2627
|
}
|
|
2599
2628
|
} else {
|
|
2600
2629
|
Log.e("InAppBrowser", "Failed to create photo URI, falling back to file picker");
|
|
2601
|
-
fallbackToFilePicker();
|
|
2630
|
+
fallbackToFilePicker(request);
|
|
2602
2631
|
}
|
|
2603
2632
|
}
|
|
2604
2633
|
} catch (Exception e) {
|
|
2605
2634
|
Log.e("InAppBrowser", "Camera launch failed: " + e.getMessage(), e);
|
|
2606
|
-
fallbackToFilePicker();
|
|
2635
|
+
fallbackToFilePicker(request);
|
|
2607
2636
|
}
|
|
2608
2637
|
}
|
|
2609
2638
|
|
|
2610
2639
|
/**
|
|
2611
2640
|
* Fall back to file picker when camera launch fails
|
|
2612
2641
|
*/
|
|
2613
|
-
private void fallbackToFilePicker() {
|
|
2614
|
-
if (
|
|
2615
|
-
|
|
2642
|
+
private void fallbackToFilePicker(FileChooserRequestSupport.FileChooserRequest request) {
|
|
2643
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
2644
|
+
return;
|
|
2616
2645
|
}
|
|
2646
|
+
openFileChooser(request);
|
|
2617
2647
|
}
|
|
2618
2648
|
|
|
2619
2649
|
// Grant permissions for cam
|
|
@@ -4061,8 +4091,43 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
4061
4091
|
}
|
|
4062
4092
|
}
|
|
4063
4093
|
|
|
4064
|
-
private void
|
|
4065
|
-
|
|
4094
|
+
private void beginFileChooserRequest(ValueCallback<Uri[]> filePathCallback, String acceptType, boolean isMultiple) {
|
|
4095
|
+
if (activeFileChooserRequest != null) {
|
|
4096
|
+
FileChooserRequestSupport.cancel(activeFileChooserRequest);
|
|
4097
|
+
}
|
|
4098
|
+
activeFileChooserRequest = new FileChooserRequestSupport.FileChooserRequest(filePathCallback, acceptType, isMultiple);
|
|
4099
|
+
syncFileChooserPublicFields();
|
|
4100
|
+
}
|
|
4101
|
+
|
|
4102
|
+
private void clearActiveFileChooserRequest(FileChooserRequestSupport.FileChooserRequest request) {
|
|
4103
|
+
if (activeFileChooserRequest == request) {
|
|
4104
|
+
activeFileChooserRequest = null;
|
|
4105
|
+
syncFileChooserPublicFields();
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
private void syncFileChooserPublicFields() {
|
|
4110
|
+
mFilePathCallback = activeFileChooserRequest != null ? activeFileChooserRequest.callback : null;
|
|
4111
|
+
tempCameraUri = activeFileChooserRequest != null ? activeFileChooserRequest.tempCameraUri : null;
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
void completeLegacyFileChooserResult(Uri[] results) {
|
|
4115
|
+
FileChooserRequestSupport.FileChooserRequest request = activeFileChooserRequest;
|
|
4116
|
+
if (request == null) {
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
if (FileChooserRequestSupport.completeIfActive(request, activeFileChooserRequest, results)) {
|
|
4120
|
+
request.tempCameraUri = null;
|
|
4121
|
+
clearActiveFileChooserRequest(request);
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
private void openFileChooser(FileChooserRequestSupport.FileChooserRequest request) {
|
|
4126
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
4127
|
+
return;
|
|
4128
|
+
}
|
|
4129
|
+
String acceptType = request.acceptType;
|
|
4130
|
+
boolean isMultiple = request.multiple;
|
|
4066
4131
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
4067
4132
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
4068
4133
|
|
|
@@ -4110,26 +4175,29 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
4110
4175
|
"file_chooser",
|
|
4111
4176
|
new androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult(),
|
|
4112
4177
|
(result) -> {
|
|
4178
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
4179
|
+
return;
|
|
4180
|
+
}
|
|
4181
|
+
Uri[] results = null;
|
|
4113
4182
|
if (result.getResultCode() == Activity.RESULT_OK) {
|
|
4114
4183
|
Intent data = result.getData();
|
|
4115
4184
|
if (data != null) {
|
|
4116
4185
|
if (data.getClipData() != null) {
|
|
4117
4186
|
// Handle multiple files
|
|
4118
4187
|
int count = data.getClipData().getItemCount();
|
|
4119
|
-
|
|
4188
|
+
results = new Uri[count];
|
|
4120
4189
|
for (int i = 0; i < count; i++) {
|
|
4121
4190
|
results[i] = data.getClipData().getItemAt(i).getUri();
|
|
4122
4191
|
}
|
|
4123
|
-
mFilePathCallback.onReceiveValue(results);
|
|
4124
4192
|
} else if (data.getData() != null) {
|
|
4125
4193
|
// Handle single file
|
|
4126
|
-
|
|
4194
|
+
results = new Uri[] { data.getData() };
|
|
4127
4195
|
}
|
|
4128
4196
|
}
|
|
4129
|
-
} else {
|
|
4130
|
-
mFilePathCallback.onReceiveValue(null);
|
|
4131
4197
|
}
|
|
4132
|
-
|
|
4198
|
+
if (FileChooserRequestSupport.completeIfActive(request, activeFileChooserRequest, results)) {
|
|
4199
|
+
clearActiveFileChooserRequest(request);
|
|
4200
|
+
}
|
|
4133
4201
|
}
|
|
4134
4202
|
)
|
|
4135
4203
|
.launch(Intent.createChooser(intent, "Select File"));
|
|
@@ -4150,26 +4218,29 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
4150
4218
|
"file_chooser",
|
|
4151
4219
|
new androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult(),
|
|
4152
4220
|
(result) -> {
|
|
4221
|
+
if (!FileChooserRequestSupport.isActive(request, activeFileChooserRequest)) {
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
Uri[] results = null;
|
|
4153
4225
|
if (result.getResultCode() == Activity.RESULT_OK) {
|
|
4154
4226
|
Intent data = result.getData();
|
|
4155
4227
|
if (data != null) {
|
|
4156
4228
|
if (data.getClipData() != null) {
|
|
4157
4229
|
// Handle multiple files
|
|
4158
4230
|
int count = data.getClipData().getItemCount();
|
|
4159
|
-
|
|
4231
|
+
results = new Uri[count];
|
|
4160
4232
|
for (int i = 0; i < count; i++) {
|
|
4161
4233
|
results[i] = data.getClipData().getItemAt(i).getUri();
|
|
4162
4234
|
}
|
|
4163
|
-
mFilePathCallback.onReceiveValue(results);
|
|
4164
4235
|
} else if (data.getData() != null) {
|
|
4165
4236
|
// Handle single file
|
|
4166
|
-
|
|
4237
|
+
results = new Uri[] { data.getData() };
|
|
4167
4238
|
}
|
|
4168
4239
|
}
|
|
4169
|
-
} else {
|
|
4170
|
-
mFilePathCallback.onReceiveValue(null);
|
|
4171
4240
|
}
|
|
4172
|
-
|
|
4241
|
+
if (FileChooserRequestSupport.completeIfActive(request, activeFileChooserRequest, results)) {
|
|
4242
|
+
clearActiveFileChooserRequest(request);
|
|
4243
|
+
}
|
|
4173
4244
|
}
|
|
4174
4245
|
)
|
|
4175
4246
|
.launch(Intent.createChooser(intent, "Select File"));
|
|
@@ -4180,9 +4251,8 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
4180
4251
|
} catch (ActivityNotFoundException ex) {
|
|
4181
4252
|
// If still failing, report error
|
|
4182
4253
|
Log.e("InAppBrowser", "No app can handle file picker", ex);
|
|
4183
|
-
if (
|
|
4184
|
-
|
|
4185
|
-
mFilePathCallback = null;
|
|
4254
|
+
if (FileChooserRequestSupport.cancelIfActive(request, activeFileChooserRequest)) {
|
|
4255
|
+
clearActiveFileChooserRequest(request);
|
|
4186
4256
|
}
|
|
4187
4257
|
}
|
|
4188
4258
|
}
|
|
@@ -4364,6 +4434,60 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
4364
4434
|
return proxyHeaders;
|
|
4365
4435
|
}
|
|
4366
4436
|
|
|
4437
|
+
private void ensureBundledAssetLoader() {
|
|
4438
|
+
synchronized (bundledAssetLoaderLock) {
|
|
4439
|
+
ensureBundledAssetLoaderLocked();
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
|
|
4443
|
+
private void ensureBundledAssetLoaderLocked() {
|
|
4444
|
+
if (bundledAssetLoader != null || _options == null || !_options.getServeBundledAssets()) {
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
bundledAssetLoader = BundledAssetSupport.createAssetLoader(
|
|
4449
|
+
_context,
|
|
4450
|
+
_options.getBundledAssetHost(),
|
|
4451
|
+
_options.getBundledAssetScheme()
|
|
4452
|
+
);
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
public void applyBundledAssetResolution(BundledAssetSupport.Resolution resolution, String localUrl) {
|
|
4456
|
+
if (_options == null || resolution == null) {
|
|
4457
|
+
return;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
synchronized (bundledAssetLoaderLock) {
|
|
4461
|
+
bundledAssetLoader = null;
|
|
4462
|
+
_options.setUrl(resolution.url);
|
|
4463
|
+
if (resolution.needsAssetLoader) {
|
|
4464
|
+
BundledAssetSupport.LocalConfig localConfig = BundledAssetSupport.parseLocalConfig(localUrl);
|
|
4465
|
+
_options.setBundledAssetHost(localConfig != null ? localConfig.host : "localhost");
|
|
4466
|
+
_options.setBundledAssetScheme(localConfig != null ? BundledAssetSupport.assetLoaderScheme(localConfig) : "https");
|
|
4467
|
+
_options.setServeBundledAssets(true);
|
|
4468
|
+
} else {
|
|
4469
|
+
_options.setServeBundledAssets(false);
|
|
4470
|
+
}
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
|
|
4474
|
+
private WebResourceResponse interceptBundledAssetRequest(WebResourceRequest request) {
|
|
4475
|
+
final WebViewAssetLoader loader;
|
|
4476
|
+
synchronized (bundledAssetLoaderLock) {
|
|
4477
|
+
if (_options == null || !_options.getServeBundledAssets()) {
|
|
4478
|
+
return null;
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
ensureBundledAssetLoaderLocked();
|
|
4482
|
+
loader = bundledAssetLoader;
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
if (loader == null) {
|
|
4486
|
+
return null;
|
|
4487
|
+
}
|
|
4488
|
+
return loader.shouldInterceptRequest(request.getUrl());
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4367
4491
|
public void setUrl(String url) {
|
|
4368
4492
|
if (_webView == null) {
|
|
4369
4493
|
Log.w("InAppBrowser", "Cannot set URL - WebView is null");
|
|
@@ -5586,186 +5710,254 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
5586
5710
|
if (view == null || _webView == null) {
|
|
5587
5711
|
return null;
|
|
5588
5712
|
}
|
|
5589
|
-
if (!shouldUseNativeProxy()) {
|
|
5590
|
-
return null;
|
|
5591
|
-
}
|
|
5592
5713
|
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5714
|
+
if (shouldUseNativeProxy()) {
|
|
5715
|
+
String requestUrl = request.getUrl().toString();
|
|
5716
|
+
boolean bridgeBackedRequest = ProxyRequestSupport.isBridgeMarkerRequestUrl(requestUrl);
|
|
5717
|
+
String originalUrl;
|
|
5718
|
+
String method;
|
|
5719
|
+
Map<String, String> requestHeaders = new HashMap<>();
|
|
5720
|
+
String base64Body = "";
|
|
5721
|
+
String credentialsMode = "same-origin";
|
|
5722
|
+
|
|
5723
|
+
if (bridgeBackedRequest) {
|
|
5724
|
+
Uri uri = request.getUrl();
|
|
5725
|
+
originalUrl = uri.getQueryParameter("u");
|
|
5726
|
+
String requestId = uri.getQueryParameter("rid");
|
|
5727
|
+
if (originalUrl == null || requestId == null) {
|
|
5728
|
+
return null;
|
|
5729
|
+
}
|
|
5608
5730
|
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5731
|
+
if (
|
|
5732
|
+
ProxyRequestSupport.usesLegacyJsProxyMode(_options) &&
|
|
5733
|
+
!ProxyRequestSupport.shouldDelegateLegacyJsProxyRequest(_options, originalUrl)
|
|
5734
|
+
) {
|
|
5735
|
+
if (proxyBridge != null) {
|
|
5736
|
+
proxyBridge.getAndRemove(requestId);
|
|
5737
|
+
}
|
|
5738
|
+
Log.w("InAppBrowserProxy", "Ignoring legacy regex miss for bridge-backed request: " + originalUrl);
|
|
5739
|
+
return createCanceledResponse();
|
|
5615
5740
|
}
|
|
5616
|
-
Log.w("InAppBrowserProxy", "Ignoring legacy regex miss for bridge-backed request: " + originalUrl);
|
|
5617
|
-
return createCanceledResponse();
|
|
5618
|
-
}
|
|
5619
5741
|
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
requestHeaders = ProxyRequestSupport.mergeRequestHeaders(null, stored.headersJson);
|
|
5631
|
-
requestHeaders = ProxyRequestSupport.mergeMissingHeaders(requestHeaders, safeMarkerHeaders);
|
|
5632
|
-
} catch (JSONException error) {
|
|
5633
|
-
Log.e("InAppBrowserProxy", "Failed to parse stored proxy headers", error);
|
|
5634
|
-
return createCanceledResponse();
|
|
5635
|
-
}
|
|
5636
|
-
String initiatorUrl = request.getRequestHeaders().get("Referer");
|
|
5637
|
-
if (initiatorUrl == null || initiatorUrl.isBlank()) {
|
|
5638
|
-
initiatorUrl = getWebViewUrlOrFallback(
|
|
5639
|
-
_options != null && _options.getUrl() != null ? _options.getUrl() : originalUrl
|
|
5742
|
+
ProxyBridge.StoredRequest stored = proxyBridge != null ? proxyBridge.getAndRemove(requestId) : null;
|
|
5743
|
+
if (stored == null) {
|
|
5744
|
+
Log.e("InAppBrowserProxy", "Missing stored proxy bridge payload for request id: " + requestId);
|
|
5745
|
+
return createCanceledResponse();
|
|
5746
|
+
}
|
|
5747
|
+
method = stored.method;
|
|
5748
|
+
base64Body = stored.base64Body;
|
|
5749
|
+
credentialsMode = stored.credentialsMode;
|
|
5750
|
+
Map<String, String> safeMarkerHeaders = ProxyRequestSupport.extractSafeMarkerHeaders(
|
|
5751
|
+
request.getRequestHeaders()
|
|
5640
5752
|
);
|
|
5753
|
+
try {
|
|
5754
|
+
requestHeaders = ProxyRequestSupport.mergeRequestHeaders(null, stored.headersJson);
|
|
5755
|
+
requestHeaders = ProxyRequestSupport.mergeMissingHeaders(requestHeaders, safeMarkerHeaders);
|
|
5756
|
+
} catch (JSONException error) {
|
|
5757
|
+
Log.e("InAppBrowserProxy", "Failed to parse stored proxy headers", error);
|
|
5758
|
+
return createCanceledResponse();
|
|
5759
|
+
}
|
|
5760
|
+
String initiatorUrl = request.getRequestHeaders().get("Referer");
|
|
5761
|
+
if (initiatorUrl == null || initiatorUrl.isBlank()) {
|
|
5762
|
+
initiatorUrl = getWebViewUrlOrFallback(
|
|
5763
|
+
_options != null && _options.getUrl() != null ? _options.getUrl() : originalUrl
|
|
5764
|
+
);
|
|
5765
|
+
}
|
|
5766
|
+
String targetCookies = CookieManager.getInstance().getCookie(originalUrl);
|
|
5767
|
+
if (
|
|
5768
|
+
targetCookies != null &&
|
|
5769
|
+
!targetCookies.isBlank() &&
|
|
5770
|
+
ProxyRequestSupport.shouldInjectCookies(credentialsMode, initiatorUrl, originalUrl, requestHeaders)
|
|
5771
|
+
) {
|
|
5772
|
+
requestHeaders.put("Cookie", targetCookies);
|
|
5773
|
+
}
|
|
5774
|
+
} else {
|
|
5775
|
+
if (!ProxyRequestSupport.shouldHandleNonBridgeRequest(_options, requestUrl)) {
|
|
5776
|
+
return interceptBundledAssetRequest(request);
|
|
5777
|
+
}
|
|
5778
|
+
|
|
5779
|
+
originalUrl = requestUrl;
|
|
5780
|
+
method = request.getMethod();
|
|
5781
|
+
if (request.getRequestHeaders() != null) {
|
|
5782
|
+
requestHeaders.putAll(request.getRequestHeaders());
|
|
5783
|
+
}
|
|
5641
5784
|
}
|
|
5642
|
-
|
|
5785
|
+
|
|
5786
|
+
NativeRequestContext requestContext = new NativeRequestContext(
|
|
5787
|
+
originalUrl,
|
|
5788
|
+
method,
|
|
5789
|
+
requestHeaders,
|
|
5790
|
+
base64Body,
|
|
5791
|
+
request.isForMainFrame(),
|
|
5792
|
+
credentialsMode
|
|
5793
|
+
);
|
|
5794
|
+
|
|
5643
5795
|
if (
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5796
|
+
ProxyRequestSupport.shouldLetWebViewHandleMissingBody(
|
|
5797
|
+
requestUrl,
|
|
5798
|
+
requestContext.method,
|
|
5799
|
+
requestContext.base64Body
|
|
5800
|
+
)
|
|
5647
5801
|
) {
|
|
5648
|
-
|
|
5649
|
-
}
|
|
5650
|
-
} else {
|
|
5651
|
-
if (!ProxyRequestSupport.shouldHandleNonBridgeRequest(_options, requestUrl)) {
|
|
5802
|
+
Log.w("InAppBrowserProxy", "Allowing WebView to handle request with uncaptured body: " + requestContext.url);
|
|
5652
5803
|
return null;
|
|
5653
5804
|
}
|
|
5654
5805
|
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5806
|
+
boolean legacyProxyMode = ProxyRequestSupport.usesLegacyJsProxyMode(_options);
|
|
5807
|
+
boolean shouldDelegateLegacyRequest = ProxyRequestSupport.shouldDelegateLegacyJsProxyRequest(
|
|
5808
|
+
_options,
|
|
5809
|
+
requestContext.url
|
|
5810
|
+
);
|
|
5811
|
+
NativeResponseData directResponseData = null;
|
|
5812
|
+
|
|
5813
|
+
NativeProxyRule outboundRule =
|
|
5814
|
+
legacyProxyMode && shouldDelegateLegacyRequest
|
|
5815
|
+
? new NativeProxyRule(
|
|
5816
|
+
null,
|
|
5817
|
+
null,
|
|
5818
|
+
null,
|
|
5819
|
+
null,
|
|
5820
|
+
null,
|
|
5821
|
+
null,
|
|
5822
|
+
null,
|
|
5823
|
+
null,
|
|
5824
|
+
false,
|
|
5825
|
+
NativeProxyRule.Action.DELEGATE_TO_JS
|
|
5826
|
+
)
|
|
5827
|
+
: findMatchingRule(_options.getOutboundProxyRules(), requestContext, null);
|
|
5828
|
+
|
|
5829
|
+
if (outboundRule != null && outboundRule.getAction() == NativeProxyRule.Action.CANCEL) {
|
|
5830
|
+
return createCanceledResponse();
|
|
5659
5831
|
}
|
|
5660
|
-
}
|
|
5661
|
-
|
|
5662
|
-
NativeRequestContext requestContext = new NativeRequestContext(
|
|
5663
|
-
originalUrl,
|
|
5664
|
-
method,
|
|
5665
|
-
requestHeaders,
|
|
5666
|
-
base64Body,
|
|
5667
|
-
request.isForMainFrame(),
|
|
5668
|
-
credentialsMode
|
|
5669
|
-
);
|
|
5670
|
-
|
|
5671
|
-
if (
|
|
5672
|
-
ProxyRequestSupport.shouldLetWebViewHandleMissingBody(requestUrl, requestContext.method, requestContext.base64Body)
|
|
5673
|
-
) {
|
|
5674
|
-
Log.w("InAppBrowserProxy", "Allowing WebView to handle request with uncaptured body: " + requestContext.url);
|
|
5675
|
-
return null;
|
|
5676
|
-
}
|
|
5677
5832
|
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
: findMatchingRule(_options.getOutboundProxyRules(), requestContext, null);
|
|
5700
|
-
|
|
5701
|
-
if (outboundRule != null && outboundRule.getAction() == NativeProxyRule.Action.CANCEL) {
|
|
5702
|
-
return createCanceledResponse();
|
|
5703
|
-
}
|
|
5704
|
-
|
|
5705
|
-
if (outboundRule != null && outboundRule.getAction() == NativeProxyRule.Action.DELEGATE_TO_JS) {
|
|
5706
|
-
String proxyId = UUID.randomUUID().toString();
|
|
5707
|
-
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
5708
|
-
proxiedRequest.requestContext = requestContext;
|
|
5709
|
-
addProxiedRequest(proxyId, proxiedRequest);
|
|
5710
|
-
|
|
5711
|
-
String dialogId = instanceId != null ? instanceId : "";
|
|
5712
|
-
_options
|
|
5713
|
-
.getCallbacks()
|
|
5714
|
-
.proxyRequestEvent(
|
|
5715
|
-
proxyId,
|
|
5716
|
-
"outbound",
|
|
5717
|
-
requestContext.url,
|
|
5718
|
-
requestContext.method,
|
|
5719
|
-
serializeHeaders(requestContext.headers),
|
|
5720
|
-
requestContext.base64Body.isEmpty() ? null : requestContext.base64Body,
|
|
5721
|
-
null,
|
|
5722
|
-
null,
|
|
5723
|
-
null,
|
|
5724
|
-
dialogId
|
|
5725
|
-
);
|
|
5833
|
+
if (outboundRule != null && outboundRule.getAction() == NativeProxyRule.Action.DELEGATE_TO_JS) {
|
|
5834
|
+
String proxyId = UUID.randomUUID().toString();
|
|
5835
|
+
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
5836
|
+
proxiedRequest.requestContext = requestContext;
|
|
5837
|
+
addProxiedRequest(proxyId, proxiedRequest);
|
|
5838
|
+
|
|
5839
|
+
String dialogId = instanceId != null ? instanceId : "";
|
|
5840
|
+
_options
|
|
5841
|
+
.getCallbacks()
|
|
5842
|
+
.proxyRequestEvent(
|
|
5843
|
+
proxyId,
|
|
5844
|
+
"outbound",
|
|
5845
|
+
requestContext.url,
|
|
5846
|
+
requestContext.method,
|
|
5847
|
+
serializeHeaders(requestContext.headers),
|
|
5848
|
+
requestContext.base64Body.isEmpty() ? null : requestContext.base64Body,
|
|
5849
|
+
null,
|
|
5850
|
+
null,
|
|
5851
|
+
null,
|
|
5852
|
+
dialogId
|
|
5853
|
+
);
|
|
5726
5854
|
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5855
|
+
try {
|
|
5856
|
+
if (proxiedRequest.semaphore.tryAcquire(1, 10, TimeUnit.SECONDS)) {
|
|
5857
|
+
if (proxiedRequest.canceled) {
|
|
5858
|
+
return createCanceledResponse();
|
|
5859
|
+
}
|
|
5860
|
+
if (proxiedRequest.response != null) {
|
|
5861
|
+
return proxiedRequest.response;
|
|
5862
|
+
}
|
|
5863
|
+
if (proxiedRequest.nativeResponse != null) {
|
|
5864
|
+
directResponseData = proxiedRequest.nativeResponse;
|
|
5865
|
+
} else {
|
|
5866
|
+
requestContext =
|
|
5867
|
+
proxiedRequest.requestContext != null ? proxiedRequest.requestContext : requestContext;
|
|
5868
|
+
}
|
|
5737
5869
|
} else {
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5870
|
+
synchronized (proxiedRequest) {
|
|
5871
|
+
proxiedRequest.timedOut = true;
|
|
5872
|
+
}
|
|
5873
|
+
removeProxiedRequest(proxyId);
|
|
5874
|
+
Log.w("InAppBrowserProxy", "Proxy timeout, falling back to native replay for: " + requestContext.url);
|
|
5743
5875
|
}
|
|
5876
|
+
} catch (InterruptedException error) {
|
|
5744
5877
|
removeProxiedRequest(proxyId);
|
|
5745
|
-
|
|
5878
|
+
Thread.currentThread().interrupt();
|
|
5879
|
+
Log.e("InAppBrowserProxy", "Semaphore wait error", error);
|
|
5880
|
+
return bridgeBackedRequest ? createCanceledResponse() : null;
|
|
5746
5881
|
}
|
|
5747
|
-
} catch (InterruptedException error) {
|
|
5748
|
-
removeProxiedRequest(proxyId);
|
|
5749
|
-
Thread.currentThread().interrupt();
|
|
5750
|
-
Log.e("InAppBrowserProxy", "Semaphore wait error", error);
|
|
5751
|
-
return bridgeBackedRequest ? createCanceledResponse() : null;
|
|
5752
5882
|
}
|
|
5753
|
-
}
|
|
5754
5883
|
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5884
|
+
NativeResponseData nativeResponse = directResponseData;
|
|
5885
|
+
if (nativeResponse == null) {
|
|
5886
|
+
try {
|
|
5887
|
+
nativeResponse = performNativeRequest(requestContext);
|
|
5888
|
+
} catch (IOException error) {
|
|
5889
|
+
Log.e("InAppBrowserProxy", "Native request failed for: " + requestContext.url, error);
|
|
5890
|
+
return createProxiedNativeFailureResponse(requestContext.url, bridgeBackedRequest, error);
|
|
5891
|
+
}
|
|
5762
5892
|
}
|
|
5763
|
-
}
|
|
5764
5893
|
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5894
|
+
int redirectsFollowed = 0;
|
|
5895
|
+
while (true) {
|
|
5896
|
+
NativeProxyRule inboundRule = findMatchingRule(_options.getInboundProxyRules(), requestContext, nativeResponse);
|
|
5897
|
+
if (inboundRule == null || inboundRule.getAction() == NativeProxyRule.Action.CONTINUE) {
|
|
5898
|
+
RedirectReplayResult redirectReplay;
|
|
5899
|
+
try {
|
|
5900
|
+
redirectReplay = followRedirectForWebView(requestContext, nativeResponse, redirectsFollowed);
|
|
5901
|
+
} catch (IOException error) {
|
|
5902
|
+
Log.e("InAppBrowserProxy", "Native redirect replay failed for: " + requestContext.url, error);
|
|
5903
|
+
return createProxiedNativeFailureResponse(requestContext.url, bridgeBackedRequest, error);
|
|
5904
|
+
}
|
|
5905
|
+
if (redirectReplay != null) {
|
|
5906
|
+
requestContext = redirectReplay.requestContext;
|
|
5907
|
+
nativeResponse = redirectReplay.responseData;
|
|
5908
|
+
redirectsFollowed++;
|
|
5909
|
+
continue;
|
|
5910
|
+
}
|
|
5911
|
+
return createWebResourceResponseOrFallback(nativeResponse, bridgeBackedRequest, requestContext.url);
|
|
5912
|
+
}
|
|
5913
|
+
if (inboundRule.getAction() == NativeProxyRule.Action.CANCEL) {
|
|
5914
|
+
return createCanceledResponse();
|
|
5915
|
+
}
|
|
5916
|
+
|
|
5917
|
+
String proxyId = UUID.randomUUID().toString();
|
|
5918
|
+
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
5919
|
+
proxiedRequest.requestContext = requestContext;
|
|
5920
|
+
proxiedRequest.nativeResponse = nativeResponse;
|
|
5921
|
+
addProxiedRequest(proxyId, proxiedRequest);
|
|
5922
|
+
|
|
5923
|
+
String dialogId = instanceId != null ? instanceId : "";
|
|
5924
|
+
_options
|
|
5925
|
+
.getCallbacks()
|
|
5926
|
+
.proxyRequestEvent(
|
|
5927
|
+
proxyId,
|
|
5928
|
+
"inbound",
|
|
5929
|
+
requestContext.url,
|
|
5930
|
+
requestContext.method,
|
|
5931
|
+
serializeHeaders(requestContext.headers),
|
|
5932
|
+
requestContext.base64Body.isEmpty() ? null : requestContext.base64Body,
|
|
5933
|
+
nativeResponse.statusCode,
|
|
5934
|
+
serializeHeaders(nativeResponse.headers),
|
|
5935
|
+
Base64.encodeToString(nativeResponse.bodyBytes, Base64.NO_WRAP),
|
|
5936
|
+
dialogId
|
|
5937
|
+
);
|
|
5938
|
+
|
|
5939
|
+
try {
|
|
5940
|
+
if (proxiedRequest.semaphore.tryAcquire(1, 10, TimeUnit.SECONDS)) {
|
|
5941
|
+
if (proxiedRequest.canceled) {
|
|
5942
|
+
return createCanceledResponse();
|
|
5943
|
+
}
|
|
5944
|
+
if (proxiedRequest.response != null) {
|
|
5945
|
+
return proxiedRequest.response;
|
|
5946
|
+
}
|
|
5947
|
+
if (proxiedRequest.nativeResponse != null) {
|
|
5948
|
+
nativeResponse = proxiedRequest.nativeResponse;
|
|
5949
|
+
}
|
|
5950
|
+
} else {
|
|
5951
|
+
synchronized (proxiedRequest) {
|
|
5952
|
+
proxiedRequest.timedOut = true;
|
|
5953
|
+
}
|
|
5954
|
+
removeProxiedRequest(proxyId);
|
|
5955
|
+
}
|
|
5956
|
+
} catch (InterruptedException error) {
|
|
5957
|
+
Thread.currentThread().interrupt();
|
|
5958
|
+
Log.e("InAppBrowserProxy", "Semaphore wait error", error);
|
|
5959
|
+
}
|
|
5960
|
+
|
|
5769
5961
|
RedirectReplayResult redirectReplay;
|
|
5770
5962
|
try {
|
|
5771
5963
|
redirectReplay = followRedirectForWebView(requestContext, nativeResponse, redirectsFollowed);
|
|
@@ -5781,69 +5973,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
5781
5973
|
}
|
|
5782
5974
|
return createWebResourceResponseOrFallback(nativeResponse, bridgeBackedRequest, requestContext.url);
|
|
5783
5975
|
}
|
|
5784
|
-
if (inboundRule.getAction() == NativeProxyRule.Action.CANCEL) {
|
|
5785
|
-
return createCanceledResponse();
|
|
5786
|
-
}
|
|
5787
|
-
|
|
5788
|
-
String proxyId = UUID.randomUUID().toString();
|
|
5789
|
-
ProxiedRequest proxiedRequest = new ProxiedRequest();
|
|
5790
|
-
proxiedRequest.requestContext = requestContext;
|
|
5791
|
-
proxiedRequest.nativeResponse = nativeResponse;
|
|
5792
|
-
addProxiedRequest(proxyId, proxiedRequest);
|
|
5793
|
-
|
|
5794
|
-
String dialogId = instanceId != null ? instanceId : "";
|
|
5795
|
-
_options
|
|
5796
|
-
.getCallbacks()
|
|
5797
|
-
.proxyRequestEvent(
|
|
5798
|
-
proxyId,
|
|
5799
|
-
"inbound",
|
|
5800
|
-
requestContext.url,
|
|
5801
|
-
requestContext.method,
|
|
5802
|
-
serializeHeaders(requestContext.headers),
|
|
5803
|
-
requestContext.base64Body.isEmpty() ? null : requestContext.base64Body,
|
|
5804
|
-
nativeResponse.statusCode,
|
|
5805
|
-
serializeHeaders(nativeResponse.headers),
|
|
5806
|
-
Base64.encodeToString(nativeResponse.bodyBytes, Base64.NO_WRAP),
|
|
5807
|
-
dialogId
|
|
5808
|
-
);
|
|
5809
|
-
|
|
5810
|
-
try {
|
|
5811
|
-
if (proxiedRequest.semaphore.tryAcquire(1, 10, TimeUnit.SECONDS)) {
|
|
5812
|
-
if (proxiedRequest.canceled) {
|
|
5813
|
-
return createCanceledResponse();
|
|
5814
|
-
}
|
|
5815
|
-
if (proxiedRequest.response != null) {
|
|
5816
|
-
return proxiedRequest.response;
|
|
5817
|
-
}
|
|
5818
|
-
if (proxiedRequest.nativeResponse != null) {
|
|
5819
|
-
nativeResponse = proxiedRequest.nativeResponse;
|
|
5820
|
-
}
|
|
5821
|
-
} else {
|
|
5822
|
-
synchronized (proxiedRequest) {
|
|
5823
|
-
proxiedRequest.timedOut = true;
|
|
5824
|
-
}
|
|
5825
|
-
removeProxiedRequest(proxyId);
|
|
5826
|
-
}
|
|
5827
|
-
} catch (InterruptedException error) {
|
|
5828
|
-
Thread.currentThread().interrupt();
|
|
5829
|
-
Log.e("InAppBrowserProxy", "Semaphore wait error", error);
|
|
5830
|
-
}
|
|
5831
|
-
|
|
5832
|
-
RedirectReplayResult redirectReplay;
|
|
5833
|
-
try {
|
|
5834
|
-
redirectReplay = followRedirectForWebView(requestContext, nativeResponse, redirectsFollowed);
|
|
5835
|
-
} catch (IOException error) {
|
|
5836
|
-
Log.e("InAppBrowserProxy", "Native redirect replay failed for: " + requestContext.url, error);
|
|
5837
|
-
return createProxiedNativeFailureResponse(requestContext.url, bridgeBackedRequest, error);
|
|
5838
|
-
}
|
|
5839
|
-
if (redirectReplay != null) {
|
|
5840
|
-
requestContext = redirectReplay.requestContext;
|
|
5841
|
-
nativeResponse = redirectReplay.responseData;
|
|
5842
|
-
redirectsFollowed++;
|
|
5843
|
-
continue;
|
|
5844
|
-
}
|
|
5845
|
-
return createWebResourceResponseOrFallback(nativeResponse, bridgeBackedRequest, requestContext.url);
|
|
5846
5976
|
}
|
|
5977
|
+
|
|
5978
|
+
return interceptBundledAssetRequest(request);
|
|
5847
5979
|
}
|
|
5848
5980
|
|
|
5849
5981
|
@Override
|
|
@@ -6192,11 +6324,11 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
6192
6324
|
}
|
|
6193
6325
|
|
|
6194
6326
|
// Clear any pending callbacks to prevent memory leaks
|
|
6195
|
-
if (
|
|
6196
|
-
|
|
6197
|
-
|
|
6327
|
+
if (activeFileChooserRequest != null) {
|
|
6328
|
+
FileChooserRequestSupport.cancel(activeFileChooserRequest);
|
|
6329
|
+
activeFileChooserRequest = null;
|
|
6330
|
+
syncFileChooserPublicFields();
|
|
6198
6331
|
}
|
|
6199
|
-
tempCameraUri = null;
|
|
6200
6332
|
|
|
6201
6333
|
// Clear file inputs for security/privacy before destroying WebView
|
|
6202
6334
|
try {
|