I have Xamarin.Android app which has a webview and asks permissions for camera and microphone. In my public override void OnPermissionRequest(PermissionRequest request), I want to check what is the permission requesting and show the relavant alert. But I don't know how to check whether its Camera permission or microphone. How can I check it?
Thanks!
Check the following code , PermissionRequest contains the request which the webview want to apply.
public override void OnPermissionRequest(PermissionRequest request)
{
base.OnPermissionRequest(request);
var resources = request.GetResources();
foreach ( var permission in resources)
{
if(permission == PermissionRequest.ResourceVideoCapture)
{
// apply camera permission
}
if(permission==PermissionRequest.ResourceAudioCapture)
{
// apply microphone permission
}
}
}
Related
I am having a Xamarin.Forms Prism application. It is using a WKWebView in ios Project to display a web page. In that page, other than the permission from the iOS, a permission popup from browser is also being displayed. Can anybody please help me with this? This is happening only in iOS.
https://learn.microsoft.com/en-us/answers/questions/1167987/how-to-fix-double-permission-popup-in-xamarin-ios
This thread helped me to solve this problem. Implement a class which is inherited from WKUIDelegate.
public class CustomWebViewDelegate : WKUIDelegate
{
[Export("webView:decideMediaCapturePermissionsForOrigin:initiatedByFrame:type:decisionHandler:")]
public override void RequestMediaCapturePermission(WKWebView webView, WKSecurityOrigin origin, WKFrameInfo frame, WKMediaCaptureType type, Action decisionHandler)
{
try
{
decisionHandler(WKPermissionDecision.Grant);
base.RequestMediaCapturePermission(webView, origin, frame, type, decisionHandler);
}
catch (Exception e)
{ }
}
}
Add this statement in the Renderer class.
webView.UIDelegate = new CustomWebViewDelegate();
Whenever I am opening my app I need to check the GPS is on or off. If the GPS is off, I need to redirect the user to the location settings page. I have done the android part using the dependency service like below.
ILocSettings
public interface ILocSettings
{
void OpenSettings();
bool isGpsAvailable();
}
Android implementation
[assembly: Dependency(typeof(LocationShare))]
namespace Projectname.Droid.Services
{
public class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
bool value = false;
Android.Locations.LocationManager manager = (Android.Locations.LocationManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.LocationService);
if (!manager.IsProviderEnabled(Android.Locations.LocationManager.GpsProvider))
{
//gps disable
value = false;
}
else
{
//Gps enable
value = true;
}
return value;
}
public void OpenSettings()
{
Intent intent = new Android.Content.Intent(Android.Provider.Settings.ActionLocationSourceSettings);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
}
Finally from the shared project called like below:
//For checking the GPS Status
bool gpsStatus = DependencyService.Get<ILocSettings>().isGpsAvailable();
//For opening the location settings
DependencyService.Get<ILocSettings>().OpenSettings();
For ios how I can I do the same features? I tried like below:
[assembly: Dependency(typeof(LocationShare))]
namespace Projectname.iOS.Serivces
{
class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
//how to check the GPS is on or off here
}
public void OpenSettings()
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));
}
}
}
Location settings page opening on ios simulators, but don't know how to check the GPS status.
Update1
I have tried the CLLocationManager code and it is not working as expected. It returns true always even if the location is off or on.
OpenSettings() function code (UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));) is also not working as expected, it is redirecting to some other page, I need to open the location settings page if the GPS is off.
Also, I am requesting location permission like below:
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
In android, location permission is asking, but in ios, no permissions are asking.
Update2
I have tried the new codes and getting false value always as GPS status. I have added all the location permission on the info.plist like below:
But location permission is not asking when running the app (not even a single time). I have tried Permissions.LocationWhenInUse instead of Permissions.LocationAlways, but no luck.
Update 3
Following is my complete flow for checking location permission, checking GPS status, and open settings. The permission status value is always Disabled.
//Requesting permission like below:
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
if (status == PermissionStatus.Granted)
{
//Then checking the GPS state like below
bool gpsStatus = DependencyService.Get<ILocSettings>().isGpsAvailable();
if (!gpsStatus)
{
//show a message to user here for sharing the GPS
//If user granted GPS Sharing, opening the location settings page like below:
DependencyService.Get<ILocSettings>().OpenSettings();
}
}
I have tried the below 2 codes for requesting or checking permission. In both cases, the status value is Disabled. If I uninstall the app and reinstall it again, getting the same status and not showing any permission pop-up window.
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
Unlike the Android system, iOS can set the GPS switch separately, and can only get the status of whether the location service is turned on. The rest of the specific positioning method will be left to the iOS system to choose.
At the beginning, we need to have a look at the status of location in iOS:
CLAuthorizationStatus Enum
UIApplicationOpenSettingsURLString: Used to create a URL that you can pass to the openURL: method. When you open the URL built from this string, the system launches the Settings app and displays the app’s custom settings, if it has any.
From now, iOS only support this way to displays the app’s custom settings. There are two helpful discussion, you could have a look. How to jump to system setting's location service on iOS10? and Open Location Settings Not working in ios 11 Objective c?.
If it is redirecting to some other page as follows:
That means your app not do any settings about the location service after installing the app . Therefore, you not need to open the setting page, because it will not show the location service bellow the setting page of your app. Now the CLAuthorizationStatus should be NotDetermined. You could use CLLocationManager.RequestWhenInUseAuthorization to request the permission, the
popup window of location service will show for customer to choose inside the app.
If customer select Don't Allow first time, that means next time opening the app to check the location service that will show Denied status. Now you will need to use UIApplicationOpenSettingsURLString to open the settings page and will see the location service inside the app’s custom settings list.
At last, the final code of LocationShare is as follows:
public class LocationShare : ILocSettings
{
public bool isGpsAvailable()
{
bool value = false;
if ( CLLocationManager.LocationServicesEnabled )
{
if(CLLocationManager.Status == CLAuthorizationStatus.Authorized || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse)
{//enable
value = true;
}
else if (CLLocationManager.Status == CLAuthorizationStatus.Denied)
{
value = false;
OpenSettings();
}
else{
value = false;
RequestRuntime();
}
}
else
{
//location service false
value = false;
//ask user to open system setting page to turn on it manually.
}
return value;
}
public void RequestRuntime()
{
CLLocationManager cLLocationManager = new CLLocationManager();
cLLocationManager.RequestWhenInUseAuthorization();
}
public void OpenSettings()
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString));
}
}
Similarly, if CLAuthorizationStatus is Denied (the same as status == PermissionStatus.Unknown in Forms), the following code will not work in Forms.
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
It only works when CLAuthorizationStatus is NotDetermined. And you'd better request Permissions.LocationWhenInUse instead of Permissions.LocationAlways, this should be the better recommanded option.
============================Update #2================================
I have modified the above code, and you will see that if CLLocationManager.LocationServicesEnabled is false, we only can ask user to redirect to the system setting page to turn on the service manually. Because from iOS 10, iOS not supports to navigate to system setting page from non-system app.
============================Update #3======================================
If location service is enabled, when using UIApplication.SharedApplication.OpenUrl(new NSUrl(UIApplication.OpenSettingsUrlString)); method you will see the similar screenshot as follows:
The Loaction option will show in the list.
I'm trying to display James Montemagno's Media Picker immediately when a user navigates to one of my tabbed pages. I found a function called OnAppearing() that I tried overriding to create this result. Although it technically shows the camera immediately when I switch tabs, after I close out of the media picker I get an error saying "only one operation can be active at a time".
Here is how I'm trying to implement this feature:
protected override async void OnAppearing()
{
TakePhotoButton_Clicked();
}
async void TakePhotoButton_Clicked()
{
//Allows users to take pictures in the app
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
DisplayAlert("No Camera", "Camera is not available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
//Sets the properties of the photo file
SaveToAlbum = true,
PhotoSize = PhotoSize.MaxWidthHeight,
DefaultCamera = CameraDevice.Rear
});
if (file == null)
return;
}
I'm pretty new to all of this and I feel as if I'm making a technical error. I read this post https://damian.fyi/2016/07/06/only-one-operation-can-be-active-at-at-time/ about someone getting the same error. They claimed, "I finally realized that after taking the photo it was re-displaying the form, causing the appearing event to be fired again, and thus causing a new photo to be taken while the old one was being taken. Hence the crash."
However, I'm not catching how my code is causing this. Any guidance would be appreciated.
use a bool variable to check if you have already taken a picture
bool first = true;
protected override async void OnAppearing()
{
if (first) TakePhotoButton_Clicked();
}
async void TakePhotoButton_Clicked()
{
first = false;
...
}
My application collects location data when the user presses on a certain button, but if the user turns gps option off then turns it back the location no more works even if the gps is enabled.How to handle such a thing in flutter??
As per example in this link https://pub.dartlang.org/packages/location you should put add below code in button's click event.
var location = new Location();
// Platform messages may fail, so we use a try/catch PlatformException.
try {
currentLocation = await location.getLocation;
} on PlatformException {
currentLocation = null;
}
What is the right way to access the the front or back camera.
Currently I'm only able to access the "user" camera ( front ).
I can't switch to back camera using any constraints.
Using a specific device id is also not working:
var constraints = {
video: {
facingMode: "environment",
deviceId: "E858F78F6026428D45DD669617B4A881409AA4DA"
}
};
navigator.mediaDevices.getUserMedia(constraints).
Cany somebody please help me?
It is always accessing the front camera.
Following your question I think you already have successfully called getUserMedia() to get the user's permission to access the camera (otherwise you won't have get the front camera to work). This is needed because the label values in the following JSON will only be filled when the user has already granted access.
On iOS you now have to call navigator.mediaDevices.enumerateDevices() and will get a "response JSON" like that:
[
{
"deviceId":"<firstID>",
"kind":"audioinput",
"label":"iPhone Microphone",
"groupId":""
},
{
"deviceId":"<secondID>",
"kind":"videoinput",
"label":"Back Camera",
"groupId":""
},
{
"deviceId":"<thirdID>",
"kind":"videoinput",
"label":"Front Camera",
"groupId":""
}
]
using the deviceId of the device you want or let the user choose it using a basic UI will give you access to the back camera.
Caution: The deviceId values will change on each invocation of enumerateDevices()!
You can also pass this in as an argument when you are calling getUserMedia.
video: {
facingMode: {
exact: 'environment'
}
}
This will return the back camera's video:
navigator.mediaDevices.getUserMedia({
video: {
facingMode: {
exact: 'environment'
}
}
})