Skip to content

Commit 1001d5c

Browse files
authored
Merge pull request #13 from CoolBitX-Technology/fix/android-permission-alert-issue
fix: 優化 Android 權限請求彈窗會非同步執行的問題
2 parents 33e61d5 + b543e21 commit 1001d5c

File tree

1 file changed

+73
-24
lines changed

1 file changed

+73
-24
lines changed

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

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,11 @@ public void onPermissionRequest(final PermissionRequest request) {
158158
ArrayList<String> requestedAndroidPermissions = new ArrayList<>();
159159
for (String requestedResource : request.getResources()) {
160160
String androidPermission = null;
161-
String requestPermissionIdentifier = null;
162161

163162
if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) {
164163
androidPermission = Manifest.permission.RECORD_AUDIO;
165-
requestPermissionIdentifier = "microphone";
166164
} else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
167165
androidPermission = Manifest.permission.CAMERA;
168-
requestPermissionIdentifier = "camera";
169166
} else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
170167
if (mAllowsProtectedMedia) {
171168
grantedPermissions.add(requestedResource);
@@ -180,36 +177,43 @@ public void onPermissionRequest(final PermissionRequest request) {
180177
androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID;
181178
}
182179
}
183-
Uri originUri = request.getOrigin();
184-
String host = originUri.getHost();
180+
185181
// TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID.
186-
String alertMessage = String.format("Allow " + host + " to use your " + requestPermissionIdentifier + "?");
187182
if (androidPermission != null) {
188183
if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), androidPermission) == PackageManager.PERMISSION_GRANTED) {
189-
AlertDialog.Builder builder = new AlertDialog.Builder(this.mWebView.getContext());
190-
builder.setMessage(alertMessage);
191-
builder.setCancelable(false);
192-
String finalAndroidPermission = androidPermission;
193-
builder.setPositiveButton("Allow", (dialog, which) -> {
194-
permissionRequest = request;
195-
grantedPermissions.add(finalAndroidPermission);
196-
requestPermissions(grantedPermissions);
197-
});
198-
builder.setNegativeButton("Don't allow", (dialog, which) -> {
199-
request.deny();
200-
});
201-
AlertDialog alertDialog = builder.create();
202-
alertDialog.show();
203-
//Delay making `allow` clickable for 500ms to avoid unwanted presses.
204-
Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
205-
posButton.setEnabled(false);
206-
this.runDelayed(() -> posButton.setEnabled(true), 500);
184+
grantedPermissions.add(requestedResource);
207185
} else {
208186
requestedAndroidPermissions.add(androidPermission);
209187
}
210188
}
211189
}
212190

191+
if (this.shouldShowRequestPermissionDialog(grantedPermissions)) {
192+
String alertMessage = this.getRequestPermissionAlertMessage(request, grantedPermissions);
193+
194+
this.showRequestPermissionDialog(
195+
alertMessage,
196+
(dialog, which) -> {
197+
this.grantOrRequestPermission(request, requestedAndroidPermissions);
198+
},
199+
(dialog, which) -> {
200+
request.deny();
201+
});
202+
} else {
203+
this.grantOrRequestPermission(request, requestedAndroidPermissions);
204+
}
205+
}
206+
207+
// CW-22083: 如果網頁要求麥克風或攝影機權限,就顯示權限請求對話框。
208+
// 參數只需要傳入已經被授權的權限即可。未授權的權限會由手機系統的權限請求對話框處理。
209+
private boolean shouldShowRequestPermissionDialog(List<String> grantedPermissions) {
210+
return grantedPermissions.contains(PermissionRequest.RESOURCE_AUDIO_CAPTURE) ||
211+
grantedPermissions.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE);
212+
}
213+
214+
// 如果 requestedAndroidPermissions 為空,表示手機系統已經給予所有權限給 app。app 可以直接 grant 權限給 webview。
215+
// 如果 requestedAndroidPermissions 不為空,表示 app 還需要向手機系統請求權限,後續會有 listener 會再 grant 權限給 webview。
216+
private void grantOrRequestPermission(PermissionRequest request, List<String> requestedAndroidPermissions) {
213217
// If all the permissions are already granted, send the response to the WebView synchronously
214218
if (requestedAndroidPermissions.isEmpty()) {
215219
if (!grantedPermissions.isEmpty()) {
@@ -226,6 +230,51 @@ public void onPermissionRequest(final PermissionRequest request) {
226230
requestPermissions(requestedAndroidPermissions);
227231
}
228232

233+
private String getDisplayHostName(PermissionRequest request) {
234+
try {
235+
Uri originUri = request.getOrigin();
236+
return originUri.getHost();
237+
} catch (Exception e) {
238+
return "";
239+
}
240+
}
241+
242+
private String getRequestPermissionAlertMessage(PermissionRequest request, List<String> permissions) {
243+
List<String> permissionNames = new ArrayList<>();
244+
for (String permission : permissions) {
245+
switch (permission) {
246+
case PermissionRequest.RESOURCE_AUDIO_CAPTURE:
247+
permissionNames.add("microphone");
248+
break;
249+
case PermissionRequest.RESOURCE_VIDEO_CAPTURE:
250+
permissionNames.add("camera");
251+
break;
252+
default:
253+
// Skip unknown permissions, just handle audio & video
254+
break;
255+
}
256+
}
257+
258+
String host = this.getDisplayHostName(request);
259+
String permissionNamesJoined = String.join(" and ", permissionNames);
260+
261+
return String.format("Allow " + host + " to use your " + permissionNamesJoined + "?");
262+
}
263+
264+
private void showRequestPermissionDialog(String alertMessage, DialogInterface.OnClickListener onAllow, DialogInterface.OnClickListener onDeny) {
265+
AlertDialog.Builder builder = new AlertDialog.Builder(this.mWebView.getContext());
266+
builder.setMessage(alertMessage);
267+
builder.setCancelable(false);
268+
builder.setPositiveButton("Allow", onAllow);
269+
builder.setNegativeButton("Don't allow", onDeny);
270+
AlertDialog alertDialog = builder.create();
271+
alertDialog.show();
272+
//Delay making `allow` clickable for 500ms to avoid unwanted presses.
273+
Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
274+
posButton.setEnabled(false);
275+
this.runDelayed(() -> posButton.setEnabled(true), 500);
276+
}
277+
229278
private void runDelayed(Runnable function, long delayMillis) {
230279
Handler handler = new Handler();
231280
handler.postDelayed(function, delayMillis);

0 commit comments

Comments
 (0)