@capgo/inappbrowser 7.6.3 → 7.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -22
- package/android/src/main/AndroidManifest.xml +12 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +113 -78
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +527 -38
- package/android/src/main/res/xml/file_paths.xml +14 -0
- package/dist/docs.json +33 -61
- package/dist/esm/definitions.d.ts +2 -12
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Plugin/InAppBrowserPlugin.swift +38 -22
- package/ios/Plugin/WKWebViewController.swift +4 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ With this plugin you can send events from the main app to the inappbrowser and v
|
|
|
75
75
|
|
|
76
76
|
> The data is sent as a JSON object, so no functions or other non-JSON-serializable types are allowed.
|
|
77
77
|
|
|
78
|
-
#### Main app to inappbrowser
|
|
78
|
+
#### Main app to inappbrowser, detail object is mendatory
|
|
79
79
|
|
|
80
80
|
```js
|
|
81
81
|
InAppBrowser.postMessage({ detail: { message: "myMessage" } });
|
|
@@ -89,7 +89,7 @@ window.addEventListener("messageFromNative", (event) => {
|
|
|
89
89
|
});
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
#### Send event from inappbrowser to main app
|
|
92
|
+
#### Send event from inappbrowser to main app, detail object is mendatory
|
|
93
93
|
|
|
94
94
|
```js
|
|
95
95
|
window.mobileApp.postMessage({ detail: { message: "myMessage" } });
|
|
@@ -147,7 +147,7 @@ window.mobileApp.close();
|
|
|
147
147
|
open(options: OpenOptions) => Promise<any>
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
Open url in a new window fullscreen
|
|
150
|
+
Open url in a new window fullscreen, on android it use chrome custom tabs, on ios it use SFSafariViewController
|
|
151
151
|
|
|
152
152
|
| Param | Type |
|
|
153
153
|
| ------------- | --------------------------------------------------- |
|
|
@@ -250,7 +250,7 @@ Open url in a new webview with toolbars, and enhanced capabilities, like camera
|
|
|
250
250
|
JavaScript Interface:
|
|
251
251
|
When you open a webview with this method, a JavaScript interface is automatically injected that provides:
|
|
252
252
|
- `window.mobileApp.close()`: Closes the webview from JavaScript
|
|
253
|
-
- `window.mobileApp.postMessage(
|
|
253
|
+
- `window.mobileApp.postMessage({detail: {message: 'myMessage'}})`: Sends a message from the webview to the app, detail object is the data you want to send to the webview
|
|
254
254
|
|
|
255
255
|
| Param | Type |
|
|
256
256
|
| ------------- | ----------------------------------------------------------------- |
|
|
@@ -479,24 +479,11 @@ Reload the current web page.
|
|
|
479
479
|
|
|
480
480
|
#### OpenOptions
|
|
481
481
|
|
|
482
|
-
| Prop | Type
|
|
483
|
-
| ---------------------------- |
|
|
484
|
-
| **`url`** | <code>string</code>
|
|
485
|
-
| **`
|
|
486
|
-
| **`
|
|
487
|
-
| **`isPresentAfterPageLoad`** | <code>boolean</code> | if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | 0.1.0 |
|
|
488
|
-
| **`preventDeeplink`** | <code>boolean</code> | if true the deeplink will not be opened, if false the deeplink will be opened when clicked on the link | 0.1.0 |
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
#### Headers
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
#### Credentials
|
|
495
|
-
|
|
496
|
-
| Prop | Type |
|
|
497
|
-
| -------------- | ------------------- |
|
|
498
|
-
| **`username`** | <code>string</code> |
|
|
499
|
-
| **`password`** | <code>string</code> |
|
|
482
|
+
| Prop | Type | Description | Since |
|
|
483
|
+
| ---------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
484
|
+
| **`url`** | <code>string</code> | Target URL to load. | 0.1.0 |
|
|
485
|
+
| **`isPresentAfterPageLoad`** | <code>boolean</code> | if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | 0.1.0 |
|
|
486
|
+
| **`preventDeeplink`** | <code>boolean</code> | if true the deeplink will not be opened, if false the deeplink will be opened when clicked on the link | 0.1.0 |
|
|
500
487
|
|
|
501
488
|
|
|
502
489
|
#### ClearCookieOptions
|
|
@@ -559,6 +546,17 @@ Reload the current web page.
|
|
|
559
546
|
| **`textZoom`** | <code>number</code> | textZoom: sets the text zoom of the page in percent. Allows users to increase or decrease the text size for better readability. | <code>100</code> | 7.6.0 |
|
|
560
547
|
|
|
561
548
|
|
|
549
|
+
#### Headers
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
#### Credentials
|
|
553
|
+
|
|
554
|
+
| Prop | Type |
|
|
555
|
+
| -------------- | ------------------- |
|
|
556
|
+
| **`username`** | <code>string</code> |
|
|
557
|
+
| **`password`** | <code>string</code> |
|
|
558
|
+
|
|
559
|
+
|
|
562
560
|
#### DisclaimerOptions
|
|
563
561
|
|
|
564
562
|
| Prop | Type | Description | Default |
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
2
|
<queries>
|
|
4
3
|
<intent>
|
|
@@ -8,4 +7,16 @@
|
|
|
8
7
|
</intent>
|
|
9
8
|
</queries>
|
|
10
9
|
<uses-permission android:name="android.permission.CAMERA"/>
|
|
10
|
+
|
|
11
|
+
<application>
|
|
12
|
+
<provider
|
|
13
|
+
android:name="androidx.core.content.FileProvider"
|
|
14
|
+
android:authorities="${applicationId}.fileprovider"
|
|
15
|
+
android:exported="false"
|
|
16
|
+
android:grantUriPermissions="true">
|
|
17
|
+
<meta-data
|
|
18
|
+
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
19
|
+
android:resource="@xml/file_paths" />
|
|
20
|
+
</provider>
|
|
21
|
+
</application>
|
|
11
22
|
</manifest>
|
|
@@ -12,6 +12,9 @@ import android.text.TextUtils;
|
|
|
12
12
|
import android.util.Log;
|
|
13
13
|
import android.webkit.CookieManager;
|
|
14
14
|
import android.webkit.PermissionRequest;
|
|
15
|
+
import androidx.activity.result.ActivityResult;
|
|
16
|
+
import androidx.activity.result.ActivityResultLauncher;
|
|
17
|
+
import androidx.activity.result.contract.ActivityResultContracts;
|
|
15
18
|
import androidx.annotation.NonNull;
|
|
16
19
|
import androidx.browser.customtabs.CustomTabsCallback;
|
|
17
20
|
import androidx.browser.customtabs.CustomTabsClient;
|
|
@@ -29,7 +32,6 @@ import com.getcapacitor.annotation.PermissionCallback;
|
|
|
29
32
|
import java.lang.reflect.Field;
|
|
30
33
|
import java.util.ArrayList;
|
|
31
34
|
import java.util.Iterator;
|
|
32
|
-
import java.util.Objects;
|
|
33
35
|
import java.util.regex.Pattern;
|
|
34
36
|
import java.util.regex.PatternSyntaxException;
|
|
35
37
|
import org.json.JSONException;
|
|
@@ -62,6 +64,54 @@ public class InAppBrowserPlugin
|
|
|
62
64
|
|
|
63
65
|
private PermissionRequest currentPermissionRequest;
|
|
64
66
|
|
|
67
|
+
private ActivityResultLauncher<Intent> fileChooserLauncher;
|
|
68
|
+
|
|
69
|
+
@Override
|
|
70
|
+
public void load() {
|
|
71
|
+
super.load();
|
|
72
|
+
fileChooserLauncher = getActivity()
|
|
73
|
+
.registerForActivityResult(
|
|
74
|
+
new ActivityResultContracts.StartActivityForResult(),
|
|
75
|
+
this::handleFileChooserResult
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private void handleFileChooserResult(ActivityResult result) {
|
|
80
|
+
if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
|
|
81
|
+
Uri[] results = null;
|
|
82
|
+
Intent data = result.getData();
|
|
83
|
+
|
|
84
|
+
if (result.getResultCode() == Activity.RESULT_OK) {
|
|
85
|
+
// Handle camera capture result
|
|
86
|
+
if (
|
|
87
|
+
webViewDialog.tempCameraUri != null &&
|
|
88
|
+
(data == null || data.getData() == null)
|
|
89
|
+
) {
|
|
90
|
+
results = new Uri[] { webViewDialog.tempCameraUri };
|
|
91
|
+
}
|
|
92
|
+
// Handle regular file picker result
|
|
93
|
+
else if (data != null) {
|
|
94
|
+
if (data.getClipData() != null) {
|
|
95
|
+
// Handle multiple files
|
|
96
|
+
int count = data.getClipData().getItemCount();
|
|
97
|
+
results = new Uri[count];
|
|
98
|
+
for (int i = 0; i < count; i++) {
|
|
99
|
+
results[i] = data.getClipData().getItemAt(i).getUri();
|
|
100
|
+
}
|
|
101
|
+
} else if (data.getData() != null) {
|
|
102
|
+
// Handle single file
|
|
103
|
+
results = new Uri[] { data.getData() };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Send the result to WebView and clean up
|
|
109
|
+
webViewDialog.mFilePathCallback.onReceiveValue(results);
|
|
110
|
+
webViewDialog.mFilePathCallback = null;
|
|
111
|
+
webViewDialog.tempCameraUri = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
65
115
|
public void handleMicrophonePermissionRequest(PermissionRequest request) {
|
|
66
116
|
this.currentPermissionRequest = request;
|
|
67
117
|
if (getPermissionState("microphone") != PermissionState.GRANTED) {
|
|
@@ -126,57 +176,6 @@ public class InAppBrowserPlugin
|
|
|
126
176
|
}
|
|
127
177
|
}
|
|
128
178
|
|
|
129
|
-
@Override
|
|
130
|
-
public void handleOnActivityResult(
|
|
131
|
-
int requestCode,
|
|
132
|
-
int resultCode,
|
|
133
|
-
Intent data
|
|
134
|
-
) {
|
|
135
|
-
super.handleOnActivityResult(requestCode, resultCode, data);
|
|
136
|
-
|
|
137
|
-
// Handle file chooser result
|
|
138
|
-
if (requestCode == WebViewDialog.FILE_CHOOSER_REQUEST_CODE) {
|
|
139
|
-
if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
|
|
140
|
-
Uri[] results = null;
|
|
141
|
-
|
|
142
|
-
// Check if response is valid
|
|
143
|
-
if (resultCode == Activity.RESULT_OK) {
|
|
144
|
-
if (data != null) {
|
|
145
|
-
// Get the data
|
|
146
|
-
if (data.getClipData() != null) {
|
|
147
|
-
// Handle multiple files
|
|
148
|
-
int count = data.getClipData().getItemCount();
|
|
149
|
-
results = new Uri[count];
|
|
150
|
-
for (int i = 0; i < count; i++) {
|
|
151
|
-
results[i] = data.getClipData().getItemAt(i).getUri();
|
|
152
|
-
}
|
|
153
|
-
} else if (data.getData() != null) {
|
|
154
|
-
// Handle single file
|
|
155
|
-
results = new Uri[] { data.getData() };
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Send the result to WebView
|
|
161
|
-
webViewDialog.mFilePathCallback.onReceiveValue(results);
|
|
162
|
-
webViewDialog.mFilePathCallback = null;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@PermissionCallback
|
|
168
|
-
private void cameraPermissionCallback() {
|
|
169
|
-
if (getPermissionState("camera") == PermissionState.GRANTED) {
|
|
170
|
-
grantCameraPermission();
|
|
171
|
-
} else {
|
|
172
|
-
if (currentPermissionRequest != null) {
|
|
173
|
-
currentPermissionRequest.deny();
|
|
174
|
-
currentPermissionRequest = null;
|
|
175
|
-
}
|
|
176
|
-
// Handle the case where permission was not granted
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
179
|
@PermissionCallback
|
|
181
180
|
private void cameraPermissionCallback(PluginCall call) {
|
|
182
181
|
if (getPermissionState("camera") == PermissionState.GRANTED) {
|
|
@@ -194,7 +193,23 @@ public class InAppBrowserPlugin
|
|
|
194
193
|
currentPermissionRequest.deny();
|
|
195
194
|
currentPermissionRequest = null;
|
|
196
195
|
}
|
|
197
|
-
|
|
196
|
+
|
|
197
|
+
// Reject only if there's a call - could be null for WebViewDialog flow
|
|
198
|
+
if (call != null) {
|
|
199
|
+
call.reject("Camera permission is required");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@PermissionCallback
|
|
205
|
+
private void cameraPermissionCallback() {
|
|
206
|
+
if (getPermissionState("camera") == PermissionState.GRANTED) {
|
|
207
|
+
grantCameraPermission();
|
|
208
|
+
} else {
|
|
209
|
+
if (currentPermissionRequest != null) {
|
|
210
|
+
currentPermissionRequest.deny();
|
|
211
|
+
currentPermissionRequest = null;
|
|
212
|
+
}
|
|
198
213
|
}
|
|
199
214
|
}
|
|
200
215
|
|
|
@@ -210,15 +225,16 @@ public class InAppBrowserPlugin
|
|
|
210
225
|
CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
|
|
211
226
|
@Override
|
|
212
227
|
public void onCustomTabsServiceConnected(
|
|
213
|
-
|
|
228
|
+
ComponentName name,
|
|
214
229
|
CustomTabsClient client
|
|
215
230
|
) {
|
|
216
231
|
customTabsClient = client;
|
|
217
|
-
client.warmup(0);
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
@Override
|
|
221
|
-
public void onServiceDisconnected(ComponentName name) {
|
|
235
|
+
public void onServiceDisconnected(ComponentName name) {
|
|
236
|
+
customTabsClient = null;
|
|
237
|
+
}
|
|
222
238
|
};
|
|
223
239
|
|
|
224
240
|
@PluginMethod
|
|
@@ -252,9 +268,17 @@ public class InAppBrowserPlugin
|
|
|
252
268
|
@PluginMethod
|
|
253
269
|
public void open(PluginCall call) {
|
|
254
270
|
String url = call.getString("url");
|
|
271
|
+
if (url == null) {
|
|
272
|
+
call.reject("URL is required");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
255
275
|
|
|
256
276
|
// get the deeplink prevention, if provided
|
|
257
277
|
Boolean preventDeeplink = call.getBoolean("preventDeeplink", null);
|
|
278
|
+
Boolean isPresentAfterPageLoad = call.getBoolean(
|
|
279
|
+
"isPresentAfterPageLoad",
|
|
280
|
+
false
|
|
281
|
+
);
|
|
258
282
|
|
|
259
283
|
if (url == null || TextUtils.isEmpty(url)) {
|
|
260
284
|
call.reject("Invalid URL");
|
|
@@ -294,6 +318,10 @@ public class InAppBrowserPlugin
|
|
|
294
318
|
}
|
|
295
319
|
}
|
|
296
320
|
|
|
321
|
+
if (isPresentAfterPageLoad) {
|
|
322
|
+
tabsIntent.intent.putExtra("isPresentAfterPageLoad", true);
|
|
323
|
+
}
|
|
324
|
+
|
|
297
325
|
tabsIntent.launchUrl(getContext(), Uri.parse(url));
|
|
298
326
|
|
|
299
327
|
call.resolve();
|
|
@@ -473,21 +501,7 @@ public class InAppBrowserPlugin
|
|
|
473
501
|
Log.e("InAppBrowser", "Vector resource not found: " + icon);
|
|
474
502
|
// List available drawable resources to help debugging
|
|
475
503
|
try {
|
|
476
|
-
|
|
477
|
-
StringBuilder availableResources = new StringBuilder(
|
|
478
|
-
"Available resources: "
|
|
479
|
-
);
|
|
480
|
-
for (int i = 0; i < Math.min(10, drawables.length); i++) {
|
|
481
|
-
availableResources
|
|
482
|
-
.append(drawables[i].getName())
|
|
483
|
-
.append(", ");
|
|
484
|
-
}
|
|
485
|
-
if (drawables.length > 10) {
|
|
486
|
-
availableResources
|
|
487
|
-
.append("... (")
|
|
488
|
-
.append(drawables.length - 10)
|
|
489
|
-
.append(" more)");
|
|
490
|
-
}
|
|
504
|
+
final StringBuilder availableResources = getStringBuilder();
|
|
491
505
|
Log.d("InAppBrowser", availableResources.toString());
|
|
492
506
|
} catch (Exception e) {
|
|
493
507
|
Log.e(
|
|
@@ -534,7 +548,7 @@ public class InAppBrowserPlugin
|
|
|
534
548
|
|
|
535
549
|
// Validate preShowScript requires isPresentAfterPageLoad
|
|
536
550
|
if (
|
|
537
|
-
call.
|
|
551
|
+
call.getData().has("preShowScript") &&
|
|
538
552
|
!Boolean.TRUE.equals(call.getBoolean("isPresentAfterPageLoad", false))
|
|
539
553
|
) {
|
|
540
554
|
call.reject("preShowScript requires isPresentAfterPageLoad to be true");
|
|
@@ -553,10 +567,10 @@ public class InAppBrowserPlugin
|
|
|
553
567
|
} else {
|
|
554
568
|
// Reject if closeModal is false but closeModal options are provided
|
|
555
569
|
if (
|
|
556
|
-
call.
|
|
557
|
-
call.
|
|
558
|
-
call.
|
|
559
|
-
call.
|
|
570
|
+
call.getData().has("closeModalTitle") ||
|
|
571
|
+
call.getData().has("closeModalDescription") ||
|
|
572
|
+
call.getData().has("closeModalOk") ||
|
|
573
|
+
call.getData().has("closeModalCancel")
|
|
560
574
|
) {
|
|
561
575
|
call.reject("closeModal options require closeModal to be true");
|
|
562
576
|
return;
|
|
@@ -565,13 +579,16 @@ public class InAppBrowserPlugin
|
|
|
565
579
|
}
|
|
566
580
|
|
|
567
581
|
// Validate shareDisclaimer requires shareSubject
|
|
568
|
-
if (
|
|
582
|
+
if (
|
|
583
|
+
call.getData().has("shareDisclaimer") &&
|
|
584
|
+
!call.getData().has("shareSubject")
|
|
585
|
+
) {
|
|
569
586
|
call.reject("shareDisclaimer requires shareSubject to be provided");
|
|
570
587
|
return;
|
|
571
588
|
}
|
|
572
589
|
|
|
573
590
|
// Validate buttonNearDone compatibility with toolbar type
|
|
574
|
-
if (call.
|
|
591
|
+
if (call.getData().has("buttonNearDone")) {
|
|
575
592
|
String toolbarType = options.getToolbarType();
|
|
576
593
|
if (
|
|
577
594
|
TextUtils.equals(toolbarType, "activity") ||
|
|
@@ -695,6 +712,24 @@ public class InAppBrowserPlugin
|
|
|
695
712
|
);
|
|
696
713
|
}
|
|
697
714
|
|
|
715
|
+
@NonNull
|
|
716
|
+
private static StringBuilder getStringBuilder() {
|
|
717
|
+
Field[] drawables = R.drawable.class.getFields();
|
|
718
|
+
StringBuilder availableResources = new StringBuilder(
|
|
719
|
+
"Available resources: "
|
|
720
|
+
);
|
|
721
|
+
for (int i = 0; i < Math.min(10, drawables.length); i++) {
|
|
722
|
+
availableResources.append(drawables[i].getName()).append(", ");
|
|
723
|
+
}
|
|
724
|
+
if (drawables.length > 10) {
|
|
725
|
+
availableResources
|
|
726
|
+
.append("... (")
|
|
727
|
+
.append(drawables.length - 10)
|
|
728
|
+
.append(" more)");
|
|
729
|
+
}
|
|
730
|
+
return availableResources;
|
|
731
|
+
}
|
|
732
|
+
|
|
698
733
|
@PluginMethod
|
|
699
734
|
public void postMessage(PluginCall call) {
|
|
700
735
|
if (webViewDialog == null) {
|