I am creating a Xamarin Form PCL project for Android and IOS.
Is this possible to display multiple permission at once on the screen? My App is using Location, Storage and Camera permission. From my current code, this is displaying permission popup one by one on the different page like before use of camera i display camera permission popup. As I know three permission required for my App so i want to display a single popup for all three permission.
Below is my code for storage permission.
public static async Task<dynamic> CheckStoragePermission()
{
var result = "";
try
{
var Storagestatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
if (Storagestatus != PermissionStatus.Granted)
{
await Utils.CheckPermissions(Plugin.Permissions.Abstractions.Permission.Storage);
}
}
catch (Exception ex)
{
error(ex.Message, Convert.ToString(ex.InnerException), ex.Source, ex.StackTrace);
}
return result;
}
Hope someone did this before in xamarin forms, I will thank for your help for this.
You could try using the following code to request multiple permissions at one time:
private async void Button_Clicked(object sender, EventArgs e)
{
await GetPermissions();
}
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.LocationAlways,
Permission.LocationWhenInUse,
Permission.Storage,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}
Related
I am creating an application for myself, and I need my service to work when the device is rebooted. I did it here is my code.
namespace Corporate_messenger.Droid.Broadcast
{
[BroadcastReceiver(Name = "com.companyname.corporate_messenger.BootReceiver", Enabled = true, Exported = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
public class BootReceiver : BroadcastReceiver
{
private void Start1(Context context)
{
Intent mycallIntent = new Intent(context, typeof(MainActivity));
mycallIntent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(mycallIntent);
}
public override void OnReceive(Context context, Intent intent)
{
try
{
var intentService = new Intent(context, typeof(NotoficationService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
SpecialData.RestartResponse = true;
context.StartForegroundService(intentService);
}
else
{
context.StartService(intentService);
// Flag_On_Off_Service = true;
}
}
catch(Exception ex)
{
Log.Error("MyLog", ex.Message);
}
} // OnReceive
}
}
I also requested permissions to work with folders and microphone.
My cod - Permission
public async Task Permission()
{
var PermissionsStrorage_Write = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
var PermissionsInternet = await Permissions.CheckStatusAsync<Permissions.NetworkState>();
var PermissionsStrorage_Read = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
var PermissionsRecord = await Permissions.CheckStatusAsync<Permissions.Microphone>();
if (PermissionsInternet != PermissionStatus.Granted)
{
PermissionsInternet = await Permissions.RequestAsync<Permissions.NetworkState>();
}
if (PermissionsRecord != PermissionStatus.Granted)
{
PermissionsRecord = await Permissions.RequestAsync<Permissions.Microphone>();
}
if (PermissionsStrorage_Write != PermissionStatus.Granted && PermissionsStrorage_Read != PermissionStatus.Granted)
{
PermissionsStrorage_Write = await Permissions.RequestAsync<Permissions.StorageWrite>();
PermissionsStrorage_Read = await Permissions.RequestAsync<Permissions.StorageRead>();
}
if (PermissionsStrorage_Write != PermissionStatus.Granted && PermissionsStrorage_Read != PermissionStatus.Granted)
{
return;
}
}
Result code:
But I ran into a problem, which is that for my service to work correctly on some devices, two checkboxes are required. Here's a picture
Now I don't understand how to ask the user about these permissions so that he doesn't have to go into the settings himself. Perhaps the application could open this page on its own.Basically , this problem occurs on xiaomi phone. At the moment I am writing an application for android. But xamarin allows you to write code for iOS, so in the future I will also add such functions there.
here is the answer to this question
private void SetSetting()
{
// Manufacturer (Samsung)
var manufacturer = DeviceInfo.Manufacturer.ToLower();
switch (manufacturer)
{
case "xiaomi":
SetPermission("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity");
break;
case "huawei":
SetPermission("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity");
break;
case "samsung":
if(Battery.EnergySaverStatus == EnergySaverStatus.On)
SetPermission("com.samsung.android.lool", "com.samsung.android.sm.battery.ui.BatteryActivity");
break;
}
}
private void SetPermission(string param1,string param2)
{
try
{
Intent intent = new Intent();
intent.SetComponent(new ComponentName(param1, param2));
// intent.SetComponent(new ComponentName("com.miui.securitycenter", "com.miui.appmanager.ApplicationsDetailsActivity"));
intent.PutExtra("package_name", PackageName);
StartActivity(intent);
}
catch (Exception anfe)
{
}
}
How to get into settings on other devices
How to start Power Manager of all android manufactures to enable background and push notification?
Only I just don't understand how to find out the status of the flag
I'm using Two await function in my program, and first one is working flawlessly but on encountering second await, my program comes out of function without executing that awaitable function and any line after that.
Not giving error and not even crashing.
Tried "wait()", "Running on main thread", "Task Run", "Threading Sleep"..
here a snippet of the code along
private async void Btn_Clicked(object sender, EventArgs e)
{
//this statement works perfectly fine
var status = await CrossPermissions.Current.RequestPermissionAsync<LocationPermission>();
//on debugging i found out it return out of function at this point without executing
var check = await CrossPermissions.Current.RequestPermissionAsync<CameraPermission>();
//None of the code is executed
Console.WriteLine("Granted");
Console.WriteLine("Granted");
}
You try to use the below method :
private async void Btn_Clicked(object sender, EventArgs e)
{
await GetPermissions();
}
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.Camera,
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = Plugin.Permissions.Abstractions.PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted || status == Plugin.Permissions.Abstractions.PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}
Hi guy's i'm trying to figure out a way to display a DisplayAlert Popup when Someone entered the Wrong details into the Login Process.
Issue is, The login's a little "Weird" I'm not comparing against a Database i'm comparing against a List of Customers I get from a APi So I have to loop threw to then find if the detail's are correct.
I have a login Phase 1() which Checks against the Wordpress API but I want to have this be able to notify on Phase 1 and 2, Phase 1 is a Username = Username Password = Password Where phase 2 is just a Username = Username , I know it's not secure The Login is more of a Formality then anything.
public async void Login_Phase1()
{
try
{
#region Login Phase 1
var client = new WordPressClient("http://XXX.co.za/wp-json/");
client.AuthMethod = AuthMethod.JWT;
try
{
await client.RequestJWToken(Usernamelabel.Text, Password.Text);
}
catch (Exception e)
{
await App.Current.MainPage.DisplayAlert("Something Went wrong", e.ToString(), "OK");
}
var x = client;
var isValidToken = await client.IsValidJWToken();
WpApiCredentials.token = client.GetToken();
if (isValidToken)
{
Login_Phase2();
}
else
{
await App.Current.MainPage.DisplayAlert("Detail's are Incorect", "Token not Found", "OK");
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
public void Login_Phase2()
{
try
{
#region login Phase 2
var list = FetchCustomers.customers.ToList();
foreach (var user in list)
{
if (user.username == Usernamelabel.Text)
{
Preferences.Set("CId", user.id.ToString());
Preferences.Set("Token", WpApiCredentials.token);
Preferences.Set("CUsername", user.username);
Preferences.Set("CEmail", user.email);
Users.Loggedin = true;
Application.Current.SavePropertiesAsync();
App.Current.MainPage.DisplayAlert("Complete", "Login Process Complete, Enjoy", "OK");
App.Current.MainPage = new Home("Mica Market");
}
//Want to add a Display popup Here to say the information is entered incorrectly, but
not have it repeat 200 Time's
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
Fetching all the Customers to check against
private async void ExtractWooData(List<Customer> x)
{
try
{
#region FetchC
RestAPI rest = new RestAPI("http://xxxxxx/wp-json/wc/v3/", "ck_a25xxxxxxxxxxx0", "cs_8xxxxxxxx8xxxx");
WCObject wc = new WCObject(rest);
int pageNum = 1;
var isNull = false;
List<Customer> oldlist;
while (!isNull)
{
var page = pageNum.ToString();
x = await wc.Customer.GetAll(new Dictionary<string, string>() {
{
"page", page
}, {
"per_page", "100"
}
});
oldlist = FetchCustomers.customers ?? new List<Customer>();
if (x.Count == 0)
{
break;
}
else
{
//1st loop customers needs to = 100
//2nd loop oldist needs to = 40+
//If count = 0 then => Combine Customers + Oldist
pageNum++;
FetchCustomers.customers = oldlist.Union(x).ToList();
}
}
}
catch (Exception ex)
{
Crashes.TrackError(ex);
}
#endregion
}
Any Advice?
you can replace the foreach with a LINQ query
// find the first match
var found = list.Where(user => user.username == Usernamelabel.Text).FirstOrDefault();
if (found != null)
{
// set preferences and navigation
}
else
{
// DisplayAlert
}
This is killing me. I'm new to android/Xamarin. I can't find anything on the web that explains what is going on here.
I'm using xamarin forms for my application. I have a page that synchronizes the device with a web service.
The method simply retrieves 100 records at a time from the web service and updates a sqlite table on the device. I randomly get this error. I'm running 5000 records for my test sample.
Here is the button click:
public async void OnSyncCachedData_Clicked(object sender, EventArgs e)
{
activityIndicatorAll.IsRunning = true;
try
{
actIndSyncItems.IsRunning = true;
SyncAllFinished += SynchAllFinishedProcessing;
await Task.Run(async () => await App.ItemsRepo.LoadCacheDataFromCacheAsync(DbPath).ConfigureAwait(false));
}
catch (BAL.Exceptions.NetworkException nex)
{
await DisplayAlert(Messages.TitleError, nex.Message, Messages.MsgOk);
}
catch (Exception ex)
{
await DisplayAlert(Messages.TitleError, string.Format(Messages.MsgAreYouConnectedParm1, ex.Message), Messages.MsgOk);
}
finally
{
EventHandler handler = SyncAllFinished;
if (handler != null)
{
handler(this, new EventArgs());
}
SyncAllFinished -= SynchAllFinishedProcessing;
}
}
the main worker method:
public async Task<bool> LoadCacheDataFromCacheAsync(string dbPath)
{
WebSvcManagers.ItemsManager itemsWebServiceManager = new WebSvcManagers.ItemsManager();
List<Models.WebServiceItems> consumedRecords = new List<Models.WebServiceItems>() { };
int bufferSize = 100;
Log.Debug(TAG, "LoadCacheDataFromCacheAsync starting");
try
{
{
int lastID = 0;
IEnumerable<Models.WebServiceItems> remoteRecords = await BAL.DataAccessHelper.GetItemsFromGPCacheAsync(App.Login, lastID, bufferSize, itemsWebServiceManager).ConfigureAwait(false);
while (remoteRecords.Count() != 0)
{
foreach (Models.WebServiceItems remoteItem in remoteRecords)
{
// DbActionTypes dbAction = (DbActionTypes)remoteItem.DbAction;
Models.Items itemRecord = new Models.Items() { ItemNumber = remoteItem.ItemNumber.ToUpper().Trim(), Description = remoteItem.Description.Trim() };
Log.Debug(TAG, "Processing {0}", remoteItem.ItemNumber.Trim());
bool success = await AddRecordAsync(itemRecord).ConfigureAwait(false);
if (success)
consumedRecords.Add(remoteItem);
}
lastID = remoteRecords.Max(r => r.RecordID) + 1;
remoteRecords = await BAL.DataAccessHelper.GetItemsFromGPCacheAsync(App.Login, lastID, bufferSize, itemsWebServiceManager).ConfigureAwait(false);
}
}
// await UpdateConsumedRecords(consumedRecords).ConfigureAwait(false);
return true;
}
catch (Exception ex)
{
this.StatusMessage = ex.Message;
Log.Debug(TAG, "Error Catch: {0}", StatusMessage);
return false;
}
finally
{
itemsWebServiceManager = null;
HandleSyncFinished(this, new EventArgs());
SyncAllFinished -= HandleSyncFinished;
}
}
My simple webservice manager:
public static async Task<IEnumerable<Models.WebServiceItems>> GetItemsFromGPCacheAsync(Models.Login login, int offset, int bufferCount, WebSvcManagers.ItemsManager manager)
{
try
{
return await manager.GetCacheRecordsAsync(login, offset, bufferCount).ConfigureAwait(false);
}
catch (Exception)
{
throw;
}
}
And the code for the interaction with the web service:
const int bufferSize = 100;
public async Task<IEnumerable<Models.WebServiceItems>> GetCacheRecordsAsync(Models.Login login, int offSet, int bufferCount)
{
string deviceID = App.ConfigSettings.DeviceID.ToString("D");
try
{
///* Testing start */
//return await DataStore(bufferCount, offSet).ConfigureAwait(false);
///* Testing end */
if (!App.IsConnected)
throw new BAL.Exceptions.NetworkException(Messages.ExceptionNetworkConnection);
string user = login.UserName;
string password = login.Password;
HttpClient client = HttpClientExtensions.CreateHttpClient(user, password);
try
{
List<Models.WebServiceItems> items = new List<Models.WebServiceItems>() { };
int lastID = offSet;
int i = 0;
string uri = string.Format("{0}", string.Format(Messages.WebRequestItemsCacheParms3, deviceID, lastID, Math.Min(bufferCount, bufferSize)));
Log.Debug(TAG, string.Format("Webservice {0}", uri));
string response = await client.GetStringAsync(uri).ConfigureAwait(false);
while (i < bufferCount && response != null && response != "[]")
{
while (response != null && response != "[]")
{
dynamic array = JsonConvert.DeserializeObject(response);
foreach (var item in array)
{
i++;
items.Add(new Models.WebServiceItems()
{
ItemNumber = item["ITEMNMBR"].Value.Trim(),
Description = item["ITEMDESC"].Value.Trim(),
DbAction = (int)(item["DbAction"].Value),
RecordID = (int)(item["DEX_ROW_ID"].Value),
});
lastID = (int)(item["DEX_ROW_ID"].Value);
Log.Debug(TAG, string.Format("Webservice {0}", item["ITEMNMBR"].Value.Trim()));
}
if (i < Math.Min(bufferCount, bufferSize))
{
uri = string.Format("{0}", string.Format(Messages.WebRequestItemsCacheParms3, deviceID, lastID + 1, Math.Min(bufferCount, bufferSize)));
Log.Debug(TAG, string.Format("Webservice {0}", uri));
response = await client.GetStringAsync(uri).ConfigureAwait(false);
}
else
break;
}
}
Log.Debug(TAG, string.Format("Webservice return {0} items", items.Count()));
return items;
}
catch (Exception ex)
{
Log.Debug(TAG, "Error Catch: {0}", ex.Message);
throw ex;
}
}
catch (System.Net.Http.HttpRequestException nex)
{
throw new Exception(string.Format(Messages.ExceptionWebServiceLoginParm1, nex.Message));
}
catch (Exception)
{
throw;
}
}
I've had assistance from a Xamarin instructor and we thought we got it, (because this is random), but it clearly is not swatted. I've been hitting my head up against a wall for over 3 weeks on this. It smells like a memory leak, but I have no idea how to find it with such a generic error message that doesn't appear on web searches.
Somebody out there with some major brains, Please help!
Error:
08-03 12:41:11.281 D/X:ItemsRepositiory(16980): UpdateRecordAsync 65702-40710
08-03 12:41:11.306 D/X:ItemsManager(16980): Webservice DeleteCacheRecordAsync 20497
08-03 12:41:11.406 D/X:ItemsManager(16980): Webservice api/InventoryItems?DeviceID=7c5bb45d-2ea0-45b9-ae50-92f2e25a2983&OffSet=20498&Max=100&cached=true
Thread finished: <Thread Pool> #7 08-03 12:41:11.521 E/art (16980): Nested signal detected - original signal being reported The thread 'Unknown' (0x7) has exited with code 0 (0x0).
This might be a problem with the VS Android Emulator. As we have shown in tests, this is not reproducible on the Google Android Emulators, nor on Xamarin Android Player, nor on a physical Android device.
I want to make my WinForms-App to use the SingleSign-On (SSO) feature with Microsoft Accounts.
I created a LiveApp and I'm able to Login to my App with the LiveSDK 5.4.
But everytime I click on my Login-Button the permissions list appears and I need to accept it again.
This is my code:
private const string ClientID = "{MY_CLIENT_ID}";
private LiveAuthClient liveAuthClient;
private LiveConnectClient liveConnectClient;
string[] scopes = new string[] { "wl.offline_access", "wl.emails", "wl.signin" };
private void buttonLogin_Click(object sender, EventArgs e)
{
liveAuthClient = new LiveAuthClient(ClientID);
webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}
private async void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
if (this.webBrowser1.Url.AbsoluteUri.StartsWith("https://login.live.com/oauth20_desktop.srf"))
{
AuthResult authResult = new AuthResult(this.webBrowser1.Url);
if (authResult.AuthorizeCode != null)
{
try
{
LiveConnectSession session = await liveAuthClient.ExchangeAuthCodeAsync(authResult.AuthorizeCode);
this.liveConnectClient = new LiveConnectClient(session);
LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
dynamic meData = meRs.Result;
if(string.Equals(meData.emails.account, MyAppUser.EmailAddress))
MessageBox.Show("Successful login: " + meData.name);
}
catch (LiveAuthException aex)
{
MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
}
catch (LiveConnectException cex)
{
MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
}
}
else
{
MessageBox.Show(string.Format("Error received. Error: {0} Detail: {1}", authResult.ErrorCode, authResult.ErrorDescription));
}
}
}
What I need to change? I don't want the User to accept the permissions on each login.
You can use IRefreshTokenHandler to save token as following example:
public class RefreshTokenHandler : IRefreshTokenHandler
{
private string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\oneDrive\\RefreshTokenHandler\\RefreshTokenInfo.RefreshToken-me";
public Task<RefreshTokenInfo> RetrieveRefreshTokenAsync()
{
return Task.Factory.StartNew<RefreshTokenInfo>(() =>
{
if (File.Exists(path))
{
return new RefreshTokenInfo(File.ReadAllText(path));
}
return null;
});
}
public Task SaveRefreshTokenAsync(RefreshTokenInfo tokenInfo)
{
// Note:
// 1) In order to receive refresh token, wl.offline_access scope is needed.
// 2) Alternatively, we can persist the refresh token.
return Task.Factory.StartNew(() =>
{
if (File.Exists(path)) File.Delete(path);
if (!Directory.Exists(Path.GetDirectoryName(path))) Directory.CreateDirectory(Path.GetDirectoryName(path));
File.AppendAllText(path, tokenInfo.RefreshToken);
});
}
}
after that you get session as following:
RefreshTokenHandler handler = new RefreshTokenHandler();
liveAuthClient = new LiveAuthClient(ClientID, handler);
var Session = liveAuthClient.InitializeAsync(scopes).Result.Session;
if (Session == null)
{
webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}
else
{
try
{
this.liveConnectClient = new LiveConnectClient(Session);
LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
dynamic meData = meRs.Result;
if (string.Equals(meData.emails.account, MyAppUser.EmailAddress))
MessageBox.Show("Successful login: " + meData.name);
}
catch (LiveAuthException aex)
{
MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
}
catch (LiveConnectException cex)
{
MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
}
}
I've only used this API in Objective C, but I had to follow two steps.
Use the wl.offline_access scope. (Which you're already doing)
You only show the login screen if the sessions object is null. If your session object is already populated, you can proceed as you would if the sign in was successful.