Skip to content

Commit 73320c4

Browse files
committed
fix: Android In-App Browser Crash
1 parent 4e25e17 commit 73320c4

File tree

1 file changed

+82
-28
lines changed

1 file changed

+82
-28
lines changed

android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,14 @@ public void onProgressChanged(WebView webView, int newProgress) {
153153
@Override
154154
public void onPermissionRequest(final PermissionRequest request) {
155155

156+
// Reset state to handle new request
156157
grantedPermissions = new ArrayList<>();
158+
permissionRequest = null;
157159

158160
ArrayList<String> requestedAndroidPermissions = new ArrayList<>();
161+
ArrayList<String> permissionsNeedingDialog = new ArrayList<>();
162+
ArrayList<String> permissionLabels = new ArrayList<>();
163+
159164
for (String requestedResource : request.getResources()) {
160165
String androidPermission = null;
161166
String requestPermissionIdentifier = null;
@@ -179,37 +184,83 @@ public void onPermissionRequest(final PermissionRequest request) {
179184
*/
180185
androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID;
181186
} }
182-
Uri originUri = request.getOrigin();
183-
String host = originUri.getHost();
184-
// TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID.
185-
String alertMessage = String.format("Allow " + host + " to use your " + requestPermissionIdentifier + "?");
187+
186188
if (androidPermission != null) {
187189
if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), androidPermission) == PackageManager.PERMISSION_GRANTED) {
188-
AlertDialog.Builder builder = new AlertDialog.Builder(this.mWebView.getContext());
189-
builder.setMessage(alertMessage);
190-
builder.setCancelable(false);
191-
String finalAndroidPermission = androidPermission;
192-
builder.setPositiveButton("Allow", (dialog, which) -> {
193-
permissionRequest = request;
194-
grantedPermissions.add(finalAndroidPermission);
195-
requestPermissions(grantedPermissions);
196-
});
197-
builder.setNegativeButton("Don't allow", (dialog, which) -> {
198-
request.deny();
199-
});
200-
AlertDialog alertDialog = builder.create();
201-
alertDialog.show();
202-
//Delay making `allow` clickable for 500ms to avoid unwanted presses.
203-
Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
204-
posButton.setEnabled(false);
205-
this.runDelayed(() -> posButton.setEnabled(true), 500);
190+
// Permission already granted at OS level, but still need user confirmation
191+
permissionsNeedingDialog.add(androidPermission);
192+
permissionLabels.add(requestPermissionIdentifier);
206193
} else {
194+
// Permission not granted at OS level, need to request it
207195
requestedAndroidPermissions.add(androidPermission);
208196
}
209197
}
210198
}
211199

212-
// If all the permissions are already granted, send the response to the WebView synchronously
200+
// Show a SINGLE dialog for all permissions that are already granted at OS level
201+
if (!permissionsNeedingDialog.isEmpty()) {
202+
Uri originUri = request.getOrigin();
203+
String host = originUri.getHost();
204+
205+
// Build message for all requested permissions
206+
String permissionList = String.join(" and ", permissionLabels);
207+
String alertMessage = String.format("Allow %s to use your %s?", host, permissionList);
208+
209+
AlertDialog.Builder builder = new AlertDialog.Builder(this.mWebView.getContext());
210+
builder.setMessage(alertMessage);
211+
builder.setCancelable(false);
212+
213+
builder.setPositiveButton("Allow", (dialog, which) -> {
214+
// Add all permissions to granted list
215+
for (String permission : permissionsNeedingDialog) {
216+
if (permission.equals(Manifest.permission.CAMERA)) {
217+
grantedPermissions.add(PermissionRequest.RESOURCE_VIDEO_CAPTURE);
218+
} else if (permission.equals(Manifest.permission.RECORD_AUDIO)) {
219+
grantedPermissions.add(PermissionRequest.RESOURCE_AUDIO_CAPTURE);
220+
} else if (permission.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
221+
grantedPermissions.add(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID);
222+
}
223+
}
224+
225+
// If no additional system permissions needed, grant immediately
226+
if (requestedAndroidPermissions.isEmpty()) {
227+
if (!grantedPermissions.isEmpty()) {
228+
try {
229+
request.grant(grantedPermissions.toArray(new String[0]));
230+
} catch (IllegalStateException e) {
231+
// Request was already granted or denied, ignore
232+
} finally {
233+
grantedPermissions = null;
234+
permissionRequest = null;
235+
}
236+
}
237+
// DO NOT set permissionRequest since we're handling it entirely here
238+
} else {
239+
// Still need to request system permissions - set permissionRequest for listener callback
240+
permissionRequest = request;
241+
requestPermissions(requestedAndroidPermissions);
242+
}
243+
});
244+
245+
builder.setNegativeButton("Don't allow", (dialog, which) -> {
246+
request.deny();
247+
// Clean up state
248+
grantedPermissions = null;
249+
permissionRequest = null;
250+
});
251+
252+
AlertDialog alertDialog = builder.create();
253+
alertDialog.show();
254+
255+
//Delay making `allow` clickable for 500ms to avoid unwanted presses.
256+
Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
257+
posButton.setEnabled(false);
258+
this.runDelayed(() -> posButton.setEnabled(true), 500);
259+
260+
return;
261+
}
262+
263+
// If all the permissions are already granted (no dialog needed), send the response to the WebView synchronously
213264
if (requestedAndroidPermissions.isEmpty()) {
214265
if (!grantedPermissions.isEmpty()) {
215266
request.grant(grantedPermissions.toArray(new String[0]));
@@ -219,9 +270,7 @@ public void onPermissionRequest(final PermissionRequest request) {
219270
}
220271

221272
// Otherwise, ask to Android System for native permissions asynchronously
222-
223273
this.permissionRequest = request;
224-
225274
requestPermissions(requestedAndroidPermissions);
226275
}
227276

@@ -356,9 +405,14 @@ private synchronized void requestPermissions(List<String> permissions) {
356405
if (shouldAnswerToPermissionRequest
357406
&& permissionRequest != null
358407
&& grantedPermissions != null) {
359-
permissionRequest.grant(grantedPermissions.toArray(new String[0]));
360-
permissionRequest = null;
361-
grantedPermissions = null;
408+
try {
409+
permissionRequest.grant(grantedPermissions.toArray(new String[0]));
410+
} catch (IllegalStateException e) {
411+
// Request was already granted or denied, ignore
412+
} finally {
413+
permissionRequest = null;
414+
grantedPermissions = null;
415+
}
362416
}
363417

364418
if (!pendingPermissions.isEmpty()) {

0 commit comments

Comments
 (0)