Did someone know a trick to wait for user read/write storage permission on Xamarin ?
I've been looking for that but didn't found a good solution without using plugin.
My application doesn't wait for the user permissionn, it mean that when my code is working on the device directories. VS is returning an Exception...
My app is crashing when I am using this line of code :
string path = Android.OS.Environment.ExternalStorageDirectory.Path;
List<string> files1 = System.IO.Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
.Where(s => s.EndsWith(".pdf"))
.ToList();
I don't know if this thing happens only on emulator or also on real device.
Main activity :
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.WriteExternalStorage }, 0);
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage }, 0);
}
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
I know this lines are not usefull :
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.WriteExternalStorage }, 0);
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != (int)Permission.Granted)
{
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage }, 0);
}
Any advice pls ?
Before performing that operation, ask for user permission, and allow that only if permission granted, otherwise display a user alert.
You can use PermissionsPlugin for the same, Which allows you to ask for the permission and give status if permission granted or denied.
Please refer this for more detail: How to ask user for accessing permission in Xamarin.forms
Related
I want to do payment using google pay in xamarin.form.
Google pay always throw error: "Payment Failed. this transaction may be risky. for your safety it can't be completed at this time."
2 question: Do I have to do any configuration in google Pay API Console?
Below is my code for android application:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
int gpay_requestCode = 123;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
MessagingCenter.Subscribe<string>(this, "PayViaGooglePay", (value) =>
{
PayViaGooglePay();
});
}
private void PayViaGooglePay()
{
if (IsGooglePayInstalled())
{
string GOOGLE_PAY_PACKAGE_NAME = "com.google.android.apps.nbu.paisa.user";
int GOOGLE_PAY_REQUEST_CODE = 123;
Uri uri =
new Uri.Builder()
.Scheme("upi")
.Authority("pay")
.AppendQueryParameter("pa", "9725258448#okbizaxis")
.AppendQueryParameter("pn", "Gurukrupa")
.AppendQueryParameter("mc", "5812")
.AppendQueryParameter("tr", "123456789")
.AppendQueryParameter("tn", "test")
.AppendQueryParameter("am", "1")
.AppendQueryParameter("cu", "INR")
.Build();
Intent intent = new Intent(Intent.ActionView);
intent.SetData(uri);
intent.SetPackage(GOOGLE_PAY_PACKAGE_NAME);
StartActivityForResult(intent, GOOGLE_PAY_REQUEST_CODE);
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == gpay_requestCode)
{
if (data != null)
{
string response = data.GetStringExtra("response");
string[] resArray = response.Split("&");
string txnId = resArray[0].Split("=")[1].ToString();
string responseCode = resArray[1].Split("=")[1].ToString();
string status = resArray[2].Split("=")[1].ToString();
string txnRef = resArray[3].Split("=")[1].ToString();
if (status == "SUCCESS")
{
Toast.MakeText(this, "Payment Success", ToastLength.Long).Show();
}
else
{
Toast.MakeText(this, "Payment Failed", ToastLength.Long).Show();
}
}
else
{
Toast.MakeText(this, "Payment Failed", ToastLength.Long).Show();
}
}
}
private bool IsGooglePayInstalled()
{
PackageManager pm = this.PackageManager;
bool installed = false;
try
{
pm.GetPackageInfo("com.google.android.apps.nbu.paisa.user", PackageInfoFlags.Activities);
installed = true;
}
catch (PackageManager.NameNotFoundException e)
{
Toast.MakeText(this, "Google Pay Is Not Installed", ToastLength.Long).Show();
}
return installed;
}
This code will open google pay application, but when I do payment it throw error "Payment Failed. this transaction may be risky. for your safety it can't be completed at this time."
Please help me and share me your suggestion.
Thanks in advance.
I'm trying to use the Google Sign-In in Xamarin in order to create a YoutubeService instance. For now, i can get a GoogleSignInAccount with this function:
public void Login()
{
if(account != null)
{
CreateYoutube();
return;
}
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn)
.RequestServerAuthCode("112086459272-o965mju8hjqqr1fq333g3am9hqrm650e.apps.googleusercontent.com")
.RequestEmail()
.RequestScopes(new Scope(YouTubeService.Scope.Youtube))
.Build();
googleClient = new GoogleApiClient.Builder(this)
.EnableAutoManage(this, this)
.AddApi(Auth.GOOGLE_SIGN_IN_API, gso)
.Build();
OptionalPendingResult silentLog = Auth.GoogleSignInApi.SilentSignIn(googleClient);
if (silentLog.IsDone)
{
Console.WriteLine("&Casting silentlog to google account");
GoogleSignInResult result = (GoogleSignInResult)silentLog.Get();
if (result.IsSuccess)
{
account = result.SignInAccount;
CreateYoutube();
}
}
StartActivityForResult(Auth.GoogleSignInApi.GetSignInIntent(googleClient), 1598);
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == 1598)
{
GoogleSignInResult result = Auth.GoogleSignInApi.GetSignInResultFromIntent(data);
if (result.IsSuccess)
{
account = result.SignInAccount;
CreateYoutube();
}
}
}
It's working fine and i can get user's profile but the only way i've found to create a REST Api instance (like the youtube one) is by using the GoogleAccountCredential class (from the doc here: https://developers.google.com/android/guides/http-auth). Here is the code i want to use:
void CreateYoutube()
{
GoogleAccountCredential credential = GoogleAccountCredential.UsingOAuth2(
this /*Context*/,
YouTubeService.Scope.Youtube);
credential.SelectedAccount = account;
YouTubeService service = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
}
but i can't find the api who contain GoogleAccountCredential in Xamarin. Is there another way to create a YoutubeService using oauth or an api who cover the GoogleAccountCredential class ?
Do not hesitate to ask me if you don't understand something in my question.
Thanks for reading,
Tristan Roux
can't find the api who contain GoogleAccountCredential in Xamarin
You are looking the Nuget package: Xamarin.GooglePlayServices.Auth
Example Signin:
~~~
// mGoogleApiClient is a fully configured GoogleApiClient with the scopes your app need
var signInIntent = Auth.GoogleSignInApi.GetSignInIntent(mGoogleApiClient);
StartActivityForResult(signInIntent, 1010);
~~~
Now in your OnActivityResult you can retrieve the GoogleSignInAccount from the received intent:
Example OnActivityResult and the GoogleSignInAccount:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 1010)
{
var result = Auth.GoogleSignInApi.GetSignInResultFromIntent(data);
GoogleSignInAccount account = result.SignInAccount;
/// Do something with your "GoogleSignInAccount"
}
}
i have implemented code below scenarios
namespace Inspect.Droid
{
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
private DataBaseEncryption dbEncryption;
protected override async void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
MainAppActivity = this;
Forms.Init(this, bundle);
//to get the current device language code
var code = Locale.Default.GetDisplayLanguage(Locale.Default);
CommonInfo.Instance.DeviceCurrentLanguageCode = code.Substring(0, 2).ToUpper();
Console.WriteLine("Device lang code: " + CommonInfo.Instance.DeviceCurrentLanguageCode);
try
{
ConfigurationManager.Initialise(PCLAppConfig.FileSystemStream.PortableStream.Current);
}
catch (Exception ex)
{
//when application coming back from background throws exception, bcz PCLAppConfig is already initialized, so as there is no change no need to change here
Console.WriteLine(ex.Message);
}
GLOBAL_CONTEXT = Android.App.Application.Context;
ACTIVITY_CONTEXT = this;
FragmentMgr = FragmentManager;
dbEncryption = new DataBaseEncryption();
//await PrepareDb();
await dbEncryption.InitiateDecryption();
//AzureMobileServices Initialization for Android
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
SessionInfo.Instance.DeviceId = Utility.GenerateGuid().ToString();
//This will set the value for _skipCount variable in all respected helper classes.
SetSkipCount();
Inspect.ScreenSize = new Xamarin.Forms.Size(Resources.DisplayMetrics.WidthPixels / Resources.DisplayMetrics.Density,
Resources.DisplayMetrics.HeightPixels / Resources.DisplayMetrics.Density);
Inspect.AndroidDisplayMetricsDensity = Resources.DisplayMetrics.Density;
int statusBarResId = Resources.GetIdentifier("status_bar_height", "dimen", "android");
if (statusBarResId > 0)
{
Inspect.AndroidStatusBarHeight = Resources.GetDimensionPixelSize(statusBarResId);
}
Context context = this.ApplicationContext;
Acr.UserDialogs.UserDialogs.Init(this);
//allowing the device to change the screen orientation based on the rotation
MessagingCenter.Subscribe<InspectionAddNotesPage>(this, CommonConstants.AllowLandScape, sender =>
{
RequestedOrientation = ScreenOrientation.Unspecified;
});
//during page close setting back to portrait
MessagingCenter.Subscribe<InspectionAddNotesPage>(this, CommonConstants.PreventLandScape, sender =>
{
RequestedOrientation = ScreenOrientation.Portrait;
});
LoadApplication(new Inspect());
//Intializing the context for Media access
CrossCurrentActivity.Current.Activity = this;
PasscodeAuthDependency.Activity = this;
}
protected override void OnStop()
{
base.OnStop();
dbEncryption.InitiateEncryption(true);
}
protected override void OnRestart()
{
base.OnRestart();
dbEncryption.InitiateDecryption();
}
protected override void OnDestroy()
{
base.OnDestroy();
}
Please provide the solution.
Where exactly is your exception coming from? Did you manage to get the origin?
And in case you are talking about the exception from the ConfigurationManager.Initialize() method, try this.
if(Configurationmanager.AppSettings == null)
{
ConfigurationManager.Initialise(PCLAppConfig.FileSystemStream.PortableStream.Current);
}
Its just that the ConfigurationManager throws an exception if it already finds a NameValueCollection initialized.
I am attempting to read a QRCode in Xamarin.Forms. I have a shared project in XF. I have added the nuget packages for ZXing.Net. Everything works in the iOS project. I am getting an error in the Android project. The errors that I get via Android SDK Monitor, it indicates that there is a problem with the scanner being null and not being accessible. I am guessing that there is something that I have not set up correct on the Android side. Does anyone see anything improper in my code? Thanks for your time.
ScanPage class:
public class ScanPage : ContentPage
{
ZXing.Net.Mobile.Forms.ZXingScannerView zxing;
ZXingDefaultOverlay overlay;
bool isConnected = false;
string basicUrl = "golfeventscores.azurewebsites.net";
public ScanPage ()
{
zxing = new ZXing.Net.Mobile.Forms.ZXingScannerView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
AutomationId = "zxingScannerView",
};
zxing.OnScanResult += async (ZXing.Result result) => {
zxing.IsAnalyzing = false;
zxing.IsScanning = false;
var teamToken = result.Text;
//MessagingCenter.Send<string>(teamToken, "SelectTeamMembers");
isConnected = await Plugin.Connectivity.CrossConnectivity.Current.IsRemoteReachable(basicUrl);
if (isConnected)
{
await GetTeamData(teamToken);
}
else
{
await DisplayAlert("Connectivity", "There is a problem with internet connectivity. Please try and reload this screen.", "Ok");
}
};
overlay = new ZXingDefaultOverlay
{
TopText = "Hold your phone up to the barcode",
BottomText = "Scanning will happen automatically",
ShowFlashButton = zxing.HasTorch,
AutomationId = "zxingDefaultOverlay",
};
overlay.FlashButtonClicked += (sender, e) => {
zxing.IsTorchOn = !zxing.IsTorchOn;
};
var grid = new Grid
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
grid.Children.Add(zxing);
grid.Children.Add(overlay);
// The root page of your application
Content = grid;
}
protected override void OnAppearing()
{
base.OnAppearing();
zxing.IsScanning = true;
}
protected override void OnDisappearing()
{
zxing.IsScanning = false;
base.OnDisappearing();
}
async System.Threading.Tasks.Task GetTeamData(string Token)
{
try
{
var scanResult = await WebServices.ws.TokenLookup(Token);
if (scanResult.Result == true)
{
if (scanResult.IsScoreBoard == true)
{
var uri = new System.Uri(scanResult.ScoreboardUrl);
Device.BeginInvokeOnMainThread(() =>
{
Device.OpenUri(uri);
Navigation.PopToRootAsync();
});
}
if (scanResult.IsCharity == true)
{
if (scanResult.TeamPlayers.Count > 0)
{
var player = scanResult.TeamPlayers.First();
var playerId = player.PlayerTeamId;
var urlResult = await WebServices.ws.ServerUrl(Token, playerId);
if (urlResult.ValidRequest && (!String.IsNullOrEmpty(urlResult.Url)))
{
var uri = new System.Uri(urlResult.Url);
Device.OpenUri(uri);
await Navigation.PopToRootAsync();
}
}
else{
await DisplayAlert("Scanning", "There was a problem downloading the Charity Team Info.", "OK");
}
}
else
{
if (scanResult.IsLargeGame != true)
{
var select = new Pages.SelectTeamMembers(Token);
await Navigation.PushAsync(select);
}
else
{
await DisplayAlert("Large Game", "Don't have the large team game setup with scanning.", "Ok");
}
}
}
else
{
await DisplayAlert("Server Problem", "There was some type of server error. Please try again or call Wally.", "Ok");
}
}
catch(System.Exception sysExc)
{
//nothing seems to be caught
}
}
}
MainActivity.cs contents:
[Activity (Label = "TD Scan", Icon = "#drawable/icon", Theme="#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
ZXing.Net.Mobile.Forms.Android.Platform.Init();
LoadApplication (new GolfGameScanApp.App ());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Have you defined all in Android Project?
Xamarin Forms
For Xamarin Forms there is a bit more setup needed. You will need to initialize the library on each platform in your platform specific app project.
Android
On Android, in your main Activity's OnCreate (..) implementation, call:
ZXing.Net.Mobile.Forms.Android.Platform.Init();
ZXing.Net.Mobile for Xamarin.Forms also handles the new Android permission request model for you, but you will need to add the following override implementation to your main Activity as well:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
global::ZXing.Net.Mobile.Forms.Android.PermissionsHandler.OnRequestPermissionsResult (requestCode, permissions, grantResults);
}
The Camera permission should be automatically included for you in the AndroidManifest.xml however if you would like to use the Torch API's you will still need to add the Flashlight permission yourself. You can do this by using the following assembly level attribute:
[assembly: UsesPermission (Android.Manifest.Permission.Flashlight)]
I am developing an application with MVVM Cross, Mvvm Cross Forms, Xamarin Forms and Grail KIT. In IOS it works perfectly. But when I start it on Android I get an error without trace and I do not know how to solve it.
After the OnStart method is executed. This exception occurs:
The step-by-step execution of the debugger does not allow me to go beyond this method.
This is the code of the MvxFormsApplication.
public partial class App : MvxFormsApplication
{
private void ConfigLocale()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android )
{
Debug.WriteLine("Get Culture Info ...");
var ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
Debug.WriteLine(ci.ToString());
AppResources.Culture = ci; // set the RESX for resource localization
DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}
}
public App()
{
ConfigLocale();
InitializeComponent();
}
void OnAuthenticatedUserMessage(AuthenticatedUserMessage authenticatedUserMessage)
{
Debug.WriteLine("OnAuthenticatedUserMessage ...");
var deviceGroupsService = Mvx.Resolve<IDeviceGroupsService>();
// save token
deviceGroupsService.saveDevice(CrossDeviceInfo.Current.Id, Settings.FcmToken).Subscribe(device => {
Debug.WriteLine(String.Format("Device Saved: {0}", device.ToString()));
});
}
void OnExceptionOcurredMessage(ExceptionOcurredMessage exceptionOcurredMessage)
{
Debug.WriteLine("OnExceptionOcurredMessage ...");
var userDialogs = Mvx.Resolve<IUserDialogs>();
userDialogs.ShowError(AppResources.Global_ErrorOcurred);
if (exceptionOcurredMessage.Ex != null)
exceptionOcurredMessage.Ex.Track();
}
protected override void OnStart()
{
Debug.WriteLine("Forms App OnStart ...");
var messenger = Mvx.Resolve<IMvxMessenger>();
// subscribe to Authenticated User Message
messenger.Subscribe<AuthenticatedUserMessage>(OnAuthenticatedUserMessage);
// subscribe to Exception Ocurred Message
messenger.Subscribe<ExceptionOcurredMessage>(OnExceptionOcurredMessage);
//Handling FCM Token
CrossFirebasePushNotification.Current.OnTokenRefresh += (s, p) =>
{
Debug.WriteLine($"TOKEN REC: {p.Token}");
Settings.FcmToken = p.Token;
};
Debug.WriteLine($"TOKEN: {CrossFirebasePushNotification.Current.Token}");
Settings.FcmToken = CrossFirebasePushNotification.Current.Token;
}
}
}
The application starts with a SplashScreen that I expose below:
using System;
using Android.App;
using Android.Content.PM;
using MvvmCross.Droid.Views;
using MvvmCross.Forms.Droid;
using Xamarin.Forms;
namespace Bullytect.Droid
{
[Activity(
Name = "com.usal.bisite.bulltect.SplashScreen",
Label = "Bulltect"
, MainLauncher = true
, Icon = "#mipmap/ic_launcher"
, Theme = "#style/Theme.Splash"
, NoHistory = true
, ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashScreen : MvxSplashScreenActivity
{
public override void InitializationComplete()
{
StartActivity(typeof(MvxFormsApplicationActivity));
}
protected override void OnCreate(Android.OS.Bundle bundle)
{
Forms.Init(this, bundle);
// Leverage controls' StyleId attrib. to Xamarin.UITest
Forms.ViewInitialized += (object sender, ViewInitializedEventArgs e) => {
if (!string.IsNullOrWhiteSpace(e.View.StyleId))
{
e.NativeView.ContentDescription = e.View.StyleId;
}
};
base.OnCreate(bundle);
}
}
}
The Activity MvxFormsApplicationActivity is then executed by the Application Application
namespace Bullytect.Droid
{
[Activity(
Name = "com.usal.bisite.bulltect.MvxFormsApplicationActivity",
Label = "bulltect",
Icon = "#mipmap/ic_launcher",
Theme = "#style/AppTheme",
MainLauncher = false,
LaunchMode = LaunchMode.SingleTask,
ScreenOrientation = ScreenOrientation.Portrait
)]
public class MvxFormsApplicationActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
try
{
ToolbarResource = Resource.Layout.Toolbar;
TabLayoutResource = Resource.Layout.Tabs;
base.OnCreate(bundle);
Forms.Init(this, bundle);
PullToRefreshLayoutRenderer.Init();
XFGloss.Droid.Library.Init(this, bundle);
//Initializing FFImageLoading
CachedImageRenderer.Init();
UserDialogs.Init(this);
GrialKit.Init(this, "Bullytect.Droid.GrialLicense");
FormsHelper.ForceLoadingAssemblyContainingType(typeof(UXDivers.Effects.Effects));
var formsPresenter = (MvxFormsPagePresenter)Mvx.Resolve<IMvxAndroidViewPresenter>();
LoadApplication(formsPresenter.FormsApplication);
//FirebasePushNotificationManager.ProcessIntent(Intent);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("**BullTect LAUNCH EXCEPTION**\n\n" + e);
}
}
public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
DeviceOrientationLocator.NotifyOrientationChanged();
}
}
}
These are all the packages I have installed:
Hope someone can help me.