I'm trying to show WebRTC chat in WebView.
According to this documentation, WebView v36 supports WebRTC. For my test I'm using a device with Chrome/39.0.0.0 and I have added permissions to the AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<user-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
but when I enter into the chat, I see a Chromium error log (device doesn't show \ translate anything, only 'loading' progress bar):
W/AudioManagerAndroid: Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO
W/AudioManagerAndroid: No audio device will be available for recording
E/chromium: [ERROR:web_contents_delegate.cc(178)] WebContentsDelegate::CheckMediaAccessPermission: Not supported.
E/chromium: [ERROR:web_contents_delegate.cc(178)] WebContentsDelegate::CheckMediaAccessPermission: Not supported.
W/AudioManagerAndroid: Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO
W/AudioManagerAndroid: No audio device will be available for recording
D/ChromiumCameraInfo: Camera enumerated: front
Tested on a real device, Android 5.1.1.
additional request for permissions is needed
webView.setWebChromeClient(new WebChromeClient(){
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources());
}
});
update but it not working for audio capture
UPDATE found working google-sample code here
You need these permissions to access Camera and Microphone
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
// don't miss this one
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Next you need to grant permissions to your webview, check this link for more details:
webView.setWebChromeClient(new WebChromeClient(){
#Override
public void onPermissionRequest(PermissionRequest request) {
runOnUiThread(() -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String[] PERMISSIONS = {
PermissionRequest.RESOURCE_AUDIO_CAPTURE,
PermissionRequest.RESOURCE_VIDEO_CAPTURE
};
request.grant(PERMISSIONS);
}
});
}
});
If audio playback is not working, use this:
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
My experience with this in 2022:
CAMERA and RECORD_AUDIO permissions need to be declared in Manifest
setWebChromeClient.onPermissionRequest should check if those permissions have already been granted. If not, use registerForActivityResult(new RequestMultiplePermissions()) to ask the user to grant them.
its mostly error in webview reload becuase when we will request for audio , camera permission on webview , after accept permission , we need to refresh the webpage.
if (permission.equals("android.webkit.resource.AUDIO_CAPTURE")) {
demandForPermission(request.getOrigin().toString(), Manifest.permission.RECORD_AUDIO, MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
} else {
myRequest.grant(request.getResources());
}
I also stuck this problem for many days but after in below link code , 100% working code Android Webview
Related
I have been trying to use an react native ble librairie (react-native-ble-manager). In order to use this the user have to allow location permission (as explain in the documentation android.permission.ACCESS_COARSE_LOCATION and android.permission.ACCESS_FINE_LOCATION if android API >= 29.
I request the autorisation as their example with:
(PermissionsAndroid is from the react-native librairie) :
if (Platform.OS === 'android' && Platform.Version >= 23) {
PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("Permission is OK");
} else {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("User accept");
} else {
console.log("User refuse");
}
});
}
});
}
On my device the pop-up ask me for the autorisation with only two choices :
Only when the application is running
Refuse
But with their example I have 3 choices the two others and "always authorise"
And for some reason I'm not able to scan peripheral if I don't always approve (I have been able to change to always for my application by going in the settings of it).
Part of my android manifest (android/app/src/main) (as you can see I have background_location)
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
I'm sure I'm missing an obvious thing but I can't see what..
In advance thank you :)
For those having the same issue : my phone has android 11 so it can't be directly requested in the pop-up.
You have to indicate to your user how to change the permission
Source : https://developer.android.com/training/location/permissions
During the debugging process of React Native application on a physical device (Android) when I check for the location permission it's always blocked, even though I granted the permission in the settings. I have to note that I haven't been able to request the "ask for permission" window previously, so I couldn't block it in any way. Also, I tried to delete and let the app to be installed again.
Here's the code where I check for location permission (I tried others too). There I use react-native-permissions however, the behaviour is the same if I use PermissionsAndroid from react-native.
import {check, PERMISSIONS, request, RESULTS, openSettings} from "react-native-permissions";
async function checkPermissions() {
let response = await check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION); // <-- always blocked
let isPermissionsGranted = false;
if (response === RESULTS.GRANTED) {
isPermissionsGranted = true;
} else if (response === RESULTS.DENIED) {
response = request(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION, {
title: "FreeLine requires permission",
message: "FreeLine needs access to your location so you can see your position",
buttonPositive: "Ok",
buttonNegative: "Don't show my position",
});
if (response === RESULTS.GRANTED) {
isPermissionsGranted = true;
} else if (response === RESULTS.DENIED) {
await openSettings();
}
}
return isPermissionsGranted;
}
I haven't found any information that'd explain that. I thought that it's possible that during debugging I can't request for permission.
In the end, I found the root of the problem. The funniest thing it isn't connected with my code in any way. The problem was caused by the manifest, to be more precise by rules I included.
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-feature android:name="android.permission.BLUETOOTH" android:required="true"/>
<!-- Only foreground ble access -->
<uses-feature android:name="android.permission.ACCESS_FINE_LOCATION" android:required="true"/>
As you can see from the snippet above, I used use-feature. Here what the docs say about it:
Google Play uses the elements declared in your app manifest to filter your app from devices that do not meet its hardware and software feature requirements.
In addition to the rules above, I have to add uses-permission, like that:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I have been trying various ways to call on my location data ranging from IP location API's to Flutter plugin's but have not been able to get accurate location data for any of them. Through all I have settled onto Geolocator. But I kept getting
I/flutter ( 5206): null
I/flutter ( 5206): GeolocationStatus.unknown
When calling it in my Init state as follows:
void initState() {
super.initState();
fetchData();
}
fetchData() async {
setState(() {
isLoading = true; //Data is loading
});
GeolocationStatus geolocationStatus =
await Geolocator().checkGeolocationPermissionStatus();
position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
if (position != null) {
lastPosition = await Geolocator()
.getLastKnownPosition(desiredAccuracy: LocationAccuracy.high);
}
...
if (position != null)
print(position);
else
print(lastPosition);
print(geolocationStatus);
setState(() {
isLoading = false; //Data has loaded
});
}
After some research I decided to settle on permission_handler to try to check permissions. I declared PermissionStatus _status added the following lines to my fetchData() function:
PermissionHandler()
.checkPermissionStatus(PermissionGroup.location);
To which I get No permissions found in manifest for: 3
My manifest has the permissions to the best of my understanding. Manifest file: https://gist.github.com/Purukitto/640d1637c05bdb1b69cc4309947c45d5
From what I understand adding the permissions to the Manifest should add the permission option at least to the app, but after building and installing the app there are "No permissions" for my app(Screenshot attached).
What could be the problem. I have tried to mention all relevant things. Any insight will be really helpful.
This question is linked in the Flutter package permission_handler's ReadMe as an example of setting up the AndroidManifest.xml for asking permissions.
If you're having issues with the device asking the user for permissions, this may be your culprit.
To elaborate on rollcake's answer:
1. If you don't know what permissions you need yet, go to the Android Developer page to see the list and the syntax(es).
2. In your project, open: android/app/src/main/AndroidManifest.xml
3. Insert your permissions as shown in this example here:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.your.package">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name="io.flutter.app.FlutterApplication"
...<and so on>...
Just a side note: There are different AndroidManifest.xml files in your project (...src/debug, ...src/profile, and ...src/main). Adding the permissions to the main version described above should work but if you're noticing inconsistent behavior make sure you're putting all of your permissions in the same AndroidManifest file.
Check for targetSdkVersion is 23 if so then check for runtime permission you can use checkSelfPermission() and requestPermissions() for android 6 and above
open android project in flutterProject
click manifests file
insert permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
1. Add them in AndroidMenifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="30"></uses-permission>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"></uses-permission>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"></uses-permission>
2. Update permissions handler package :
Package link : https://pub.dev/packages/permission_handler
I was running into issues with the manual process behind requesting permissions (just kept falling into the 'denied' code), so I switched over to using Dexter to simplify. I implemented the following code in onCreate(), and I did a fresh install of the app:
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
#Override public void onPermissionGranted(PermissionGrantedResponse response) {
Log.d(TAG, "GRANTED!");
initCamera();
}
#Override public void onPermissionDenied(PermissionDeniedResponse response) {
Log.d(TAG, "DENIED!");
}
#Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
Log.d(TAG, "PERMISSION RATIONAL SHOULD BE SHOWN!");
}
}).check();
It immediately falls into the "DENIED!" log, and it never even prompts me. I tried this particular code to attempt multiple permissions (which is ultimately what I need to do):
Dexter.withActivity(activity)
.withPermissions(Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
Log.d(TAG, "Accepted: " + report.getGrantedPermissionResponses().size() + " | Denied: " + report.getDeniedPermissionResponses().get(0).getPermissionName());
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
Log.d(TAG, "continuing permissions request..");
token.continuePermissionRequest();
}
})
.check();
It prompts for permissions to Record Audio, then it asks about Access to photos/media/files on the device (it never asks about Camera). Then once that's done, it prints the log: "Accepted 3 | Denied: android.permission.CAMERA". It denies it without even prompting me again.
My Manifest is set properly to have CAMERA in the proper place (outside of the 'application' tag). See below for reference:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.my.app">
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
etc..
Odd thing is that when I go into Settings > Applications > MyApp, the Camera option is not even displayed in there.
I don't think it's an issue with Dexter, since it's doing basically the same thing when I set it up manually (and I confirmed that it's definitely setup properly in that case after looking at a few top S.O. posts).
Any thoughts on what the issue could be here? FYI - I'm using a Galaxy S6, OS 6.0.2. The other users experiencing this seem to be other devices with 6.0+ OS. Thanks in advance!
EDIT:
Testing various devices, it works on some and does not work on some:
Moto X (OS 5.0) - Broken
Nexus 5 (OS 7.0) - Works
Samsung S6 (OS 6.0.1) - Broken
Broken Moto X (OS 6.0) - Works
Doesn't seem to be a solid pattern.. Definitely strange. I also started a brand new project and ran the same code - worked fine and allowed access to my camera. So it doesn't appear to be fully device-specific..
The issue with this turned out to be a third-party library, which had this line in their Manifest, overriding our own permission:
<uses-permission android:name="android.permission.CAMERA" tools:node="remove" />
The solution was either to manually import their project as a module (rather than use gradle), and then comment out that line, OR more simple - you can add "tools:node="replace"" to the end of the main project's CAMERA permission line, and it works fine after that; no need to import the project with the latter approach.
What you need is native runtime permissions not dexter, Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.YOUR_PERMISSION);
then what you need is to request a certain permission if that check is false,
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.YOUR_PERMISSION},
MY_PERMISSION_CODE);
Bare in ind that you need to as well declare them also in the manifest, based on what you have shown still that was already done. For more information.
I developed a simple Android app that wrap a WebView to connect to apprtc.appspot.com. The WebRTC session is establish successfully, video streams are shown in both the app and the peer (a Chrome browser on a Mac,) the audio can be heard on the app, but the Mac does not receive any audio. chrome://webrtc-internals on the Mac's Chrome browser shows no error. WebRTCing from Chrome in the Android device to the Chrome in the Mac works fine with audio. I also wrote a test activity in the app to use MediaRecorder and MediaPlayer that successfully captured and played back audio.
My permission set up looks like
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.audio.low_latency" />
<uses-feature android:name="android.hardware.audio.pro" />
<uses-feature android:name="android.hardware.microphone" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.front" android:required="true" />
The app codes look like
int permission;
permission = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
if (permission != PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
// Show an expanation to the user *asynchronously* -- don't block
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_REQUEST_AUDIO);
}
}
// ... similar camera permission request ...
WebView webView = (WebView) findViewById(R.id.web_view);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
webView.setWebChromeClient(new WebChromeClient() {
#Override
public void onPermissionRequest(PermissionRequest request) {
request.grant(request.getResources());
}
});
webView.loadUrl("https://appr.tc/r/my-room");
What goes wrong?
Adding <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> in the permission solved the problem for me.
Add:
settings.setMediaPlaybackRequiresUserGesture(false);
For this problem you have to do these levels :
1)define a String :
private static final String DESKTOP_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36";
2)
myWebView.getSettings().setUserAgentString(DESKTOP_USER_AGENT);
3)
myWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);