How to send OnActivityResult To a specific page in xamarin forms - events

I am using a custom button renderer for google sign In in xamarin forms page its working fine I get the signin resultin MainActivity Now i want to send this data from MainActivity and AppDelegate to the Particular page in Xamarin Forms.
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 9001)
{
Utilities.Configuration.UpdateConfigValue(Utilities.Constants.loggedInflag,string.Empty);
GoogleSignInResult result = Android.Gms.Auth.Api.Auth.GoogleSignInApi.GetSignInResultFromIntent(data);
if (result.IsSuccess)
{
GoogleSignInAccount acct = result.SignInAccount;
var token = acct.IdToken;
//I wan to send the 'accnt' to a Page in xamarin forms
}
else
{
//Signin Failure send response to Page in xamarin forms
}
}
}

Xamarin.Forms runs only in one Activity on Android. So if your url request comes out in a different Activity, you have to switch back to the MainActivity before you can use the normal XF navigation.
I do this when a user opens a file associated with my app.
[Activity(Label = "LaunchFileActivity")]
public class LaunchFileActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
if (Intent.Data != null)
{
var uri = Intent.Data;
if (uri != null)
{
Intent i = new Intent(this, typeof(MainActivity));
i.AddFlags(ActivityFlags.ReorderToFront);
i.PutExtra("fileName", uri.Path);
this.StartActivity(i);
}
}
this.FinishActivity(0);
}
}
And in MainActivity:
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
Intent = intent;
}
protected override void OnPostResume()
{
base.OnPostResume();
if (Intent.Extras != null)
{
string fileName = Intent.Extras.GetString("fileName");
if (!string.IsNullOrEmpty(fileName))
{
// do something with fileName
}
Intent.RemoveExtra("fileName");
}
}

Xamarin forms runs on one activity, which is most like your main activity.
There are two sample projects that show you how to communicate between native and form parts of the code, which can be found here
https://github.com/xamarin/xamarin-forms-samples/tree/master/Forms2Native
https://github.com/xamarin/xamarin-forms-samples/tree/master/Native2Forms
However, to answer your question, you would do something like the following
private const int MyRequestCode = 101;
//Start activity for result
var contactPickerIntent = new Intent(Intent.ActionPick, Android.Provider.ContactsContract.Contacts.ContentUri);
context.StartActivityForResult(contactPickerIntent, MyRequestCode);
and then in your main activity (the activity that initializes your xamarin forms application (using global::Xamarin.Forms.Forms.Init(this, bundle);)
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == MyRequestCode && resultCode == Result.Ok)
{
}
}

Related

How to make a call via dialer programmatically in android Pie and above

I use this code to show the number and when pressing it to make a dial.It is working for android versions before Android Pie.
final Button but= findViewById(R.id.buttond);
but.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String PhNumber = "6998474783";////example number
final CharSequence[] phones = PhNumber.split(" - ");
AlertDialog.Builder builder = new AlertDialog.Builder(CTX);
builder.setTitle("Επιλογή Τηλεφώνου");
builder.setItems(phones, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
// Do something with the selection
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phones[item].toString()));
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return; }
startActivity(intent);
}
});
AlertDialog alert = builder.create();
alert.show();
}
});
What I have to change to work with Pie and above?
It shows the phone number but when I press it nothing happens
Solved using ACTION_DIAL without any checkSelfPermission.
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phones[item].toString()));
startActivity(intent);
If is there any other way, maybe with telecom-Manager please post it.

How do I enable WebGL in Xamarin.Forms WebView on UWP?

I’m new to Xamarin.Forms and tried using WebView on my Windows 10 x64 v1803 machine with UWP but I can’t see how to get it to work with WebGL.
Sites which use WebGL either display a message that “Your video card does not support WebGL or just don’t display and graphical content at all.
Is this a limitation of UWP or WebView itself?
Is it a WebView configuration issue?
WebGL works in all other browsers on this machine.
UWP WebView control is support WebGL. There is similar issue case in msdn you could refer. Please try to use SeparateProcess mode WebView to replace the default one.
public MainPage()
{
this.InitializeComponent();
var MyWebView = new WebView(WebViewExecutionMode.SeparateProcess);
MyWebView.Source = new Uri("http://cycleblob.com/");
this.RootGrid.Children.Add(MyWebView);
}
I had the same problem, but with the newer Xamarin Forms it took a little more poking around to get this took work right. However, I do like that they moved the native WebView resolver back to the responsibility of the UWP/iOS/Android project (as a native XAML object) instead of using code branching with compiler directives in the Shared project.
Start by creating a HybridWebView class in the shared project to use as your WebForm view object:
public class HybridWebView : Xamarin.Forms.WebView
{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void Cleanup()
{
action = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
}
Then in the UWP project, create a custom renderer, which will construct the native WebView and relay the events back to the WebForms object in the Shared project:
Put this at the top of the namespace, to link the HybridWebView with the Custom Renderer:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(WebViewRenderer2))]
Then create the renderer class (for the IOS and android projects, if you leave this class out, it defaults to the standard native controls which seem to work fine for me):
public class WebViewRenderer2 : ViewRenderer<Xamarin.Forms.WebView, Windows.UI.Xaml.Controls.WebView>, IWebViewDelegate
{
Windows.UI.Xaml.Controls.WebView _control;
public void LoadHtml(string html, string baseUrl)
{
}
public void LoadUrl(string url)
{
}
protected override void Dispose(bool disposing)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
if (_control == null) {
_control = new Windows.UI.Xaml.Controls.WebView(WebViewExecutionMode.SeparateProcess);
SetNativeControl(_control);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var xamWebView = sender as HybridWebView;
switch(e.PropertyName.ToLower())
{
case "source":
var urlSource = xamWebView.Source as Xamarin.Forms.UrlWebViewSource;
_control.Source = new Uri(urlSource.Url);
break;
case "width":
_control.Width = xamWebView.Width;
break;
case "height":
_control.Height = xamWebView.Height;
break;
case "isfocused":
var focused = xamWebView.IsFocused;
if (focused)
_control.Focus(FocusState.Programmatic);
else
_control.Focus(FocusState.Unfocused);
break;
}
}
}
You can also use the Custom Renderer to inject scripts, and you can use it to communicate from the native webview back to the Xamarin App, as seen here: HybridWebView Communication

OneSignal Xamarin.Forms HandleNotificationOpened redirect to notification specific page

in my Xamarin.Forms project I use OneSignal for notifications. In iOS Xamarin.Forms.Application.Current.MainPage = new NavigationPage(new NotificationPage()); worked but in Android this not work. I tried to use messaging center to communicate with PCL project. It worked when app is background but not working when app is closed. How can I redirect notification specific page when notification received in Android? Thanks
Note : Code edited and issue solved, I used shared preferences to control if app launched from notification or not. Then I Load xamarin.Forms application.
You can use below method before LoadApplication() method is called.
if (Intent.Extras != null)
{
foreach (var key in Intent.Extras.KeySet())
{
if (key != null)
{
var value = Intent.Extras.GetString(key);
Log.Debug(TAG, "Key: {0} Value: {1}", key, value);
}
}
}
LoadApplication(new App());
You have to set intent.putExtra() method in OnMessageReceivedMethod().
intent.PutExtra("Key", "value");
Then you can use redirection in App.xaml.cs file based on this key value. Because in android when notification is open while app is reinitialized.
I think you don't need to put below condition.
if (extrasList[0] == "true")
{
LoadApplication(new App(true));
}
else
{
LoadApplication(new App(false));
}
First Store your value global level so you can use it in App.cs file. Just use below code to handle page navigation in App() class like.
if (Device.RuntimePlatform == Device.Android)
{
if (YourKey == "true")
{
//handle that page navigation
}
else
{
//Default Page of App
}
}
Note : Code edited and issue solved, I used shared preferences to control if app launched from notification or not. Then I Load xamarin.Forms application
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);
InitializeUI();
global::Xamarin.Forms.Forms.Init(this, bundle);
global::Xamarin.FormsMaps.Init(this, bundle);
ImageCircleRenderer.Init();
tV = new TextView(this);
resources = this.Resources;
OneSignal.Current.StartInit("***APP ID***")
.InFocusDisplaying(OSInFocusDisplayOption.Notification)
.HandleNotificationReceived(HandleNotificationReceived)
.HandleNotificationOpened(HandleNotificationOpened)
.EndInit();
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var LaunchFromNotification = prefs.GetString("is_notification_received", "false");
if (LaunchFromNotification == "true")
{
LoadApplication(new App(true));
}
else
{
LoadApplication(new App(false));
}
OneSignal.Current.IdsAvailable(IdsAvailable); //Lets you retrieve the OneSignal player id and push token.
}
}
private static void HandleNotificationOpened(OSNotificationOpenedResult result)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(Android.App.Application.Context);
ISharedPreferencesEditor editor = prefs.Edit();
editor.PutString("is_notification_received", "true");
editor.Apply();
}
protected override void OnResume()
{
base.OnResume();
ISharedPreferences prefs =
PreferenceManager.GetDefaultSharedPreferences(this);
ISharedPreferencesEditor editor = prefs.Edit();
editor.Remove("is_notification_received");
editor.PutString("is_notification_received", "false");
editor.Apply();
}

Sharing targeted xamarin forms

I use the following command to share a link, but with this command opens a box with apps for me to share. I want when I share it already go straight to facebook, without going through this box
void OnTapped4(object sender, EventArgs args)
{
CrossShare.Current.ShareLink(link, "teste", titulo);
}
Need to do direct shares to facebook, whatsapp, twitter and email
I have this command plus it works only on xamarin android, in xamarin forms it would no work
Intent sendIntent = new Intent();
sendIntent.SetAction(Intent.ActionSend);
sendIntent.PutExtra(Intent.ExtraText,"titulo");
sendIntent.SetType("text/plain");
sendIntent.SetPackage("com.facebook.orca");
StartActivity(sendIntent);
I found the following example where I did on android and it worked, now I want to do this in IOS how can I get it to go to whatsapp
Android
public class ShareService : IShareService
{
public void SharePageLink(string url)
{
var context = Forms.Context;
Activity activity = context as Activity;
Intent share = new Intent(Intent.ActionSend);
share.SetType("text/plain");
share.AddFlags(ActivityFlags.ClearWhenTaskReset);
share.PutExtra(Intent.ExtraSubject, "Brusselslife");
share.SetPackage("com.whatsapp");
share.PutExtra(Intent.ExtraText, url);
activity.StartActivity(Intent.CreateChooser(share, "Share link!"));
}
}
In IOS where to put this 'com.whatsapp'
public class ShareService : IShareService
{
public void SharePageLink(string url)
{
var window = UIApplication.SharedApplication.KeyWindow;
var rootViewController = window.RootViewController;
//SetPackage
var activityViewController = new UIActivityViewController(new NSString[] { new NSString(url) }, null);
activityViewController.ExcludedActivityTypes = new NSString[] {
UIActivityType.AirDrop,
UIActivityType.Print,
UIActivityType.Message,
UIActivityType.AssignToContact,
UIActivityType.SaveToCameraRoll,
UIActivityType.AddToReadingList,
UIActivityType.PostToFlickr,
UIActivityType.PostToVimeo,
UIActivityType.PostToTencentWeibo,
UIActivityType.PostToWeibo
};
rootViewController.PresentViewController(activityViewController, true, null);
}
}

Google Drive API implementation Xamarin Android

Our application should have the functionality to save Application files to Google Drive. Of course, using the local configured account.
From Android API i tried to figure out some clue. But android API with Xamarin implementation seems very tough for me.
I have installed Google Play Services- Drive from Xamarin Components but there are no examples listed from which we can refer the flow and functionality.
The basic steps (see the link below for full details):
Create GoogleApiClient with the Drive API and Scope
Try to connect (login) the GoogleApiClient
The first time you try to connect it will fail as the user has not selected a Google Account that should be used
Use StartResolutionForResult to handle this condition
When GoogleApiClient is connected
Request a Drive content (DriveContentsResult) to write the file contents to.
When the result is obtained, write data into the Drive content.
Set the metadata for the file
Create the Drive-based file with the Drive content
Note: This example assumes that you have Google Drive installed on your device/emulator and you have registered your app in Google's Developer API Console with the Google Drive API Enabled.
C# Example:
[Activity(Label = "DriveOpen", MainLauncher = true, Icon = "#mipmap/icon")]
public class MainActivity : Activity, GoogleApiClient.IConnectionCallbacks, IResultCallback, IDriveApiDriveContentsResult
{
const string TAG = "GDriveExample";
const int REQUEST_CODE_RESOLUTION = 3;
GoogleApiClient _googleApiClient;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate
{
if (_googleApiClient == null)
{
_googleApiClient = new GoogleApiClient.Builder(this)
.AddApi(DriveClass.API)
.AddScope(DriveClass.ScopeFile)
.AddConnectionCallbacks(this)
.AddOnConnectionFailedListener(onConnectionFailed)
.Build();
}
if (!_googleApiClient.IsConnected)
_googleApiClient.Connect();
};
}
protected void onConnectionFailed(ConnectionResult result)
{
Log.Info(TAG, "GoogleApiClient connection failed: " + result);
if (!result.HasResolution)
{
GoogleApiAvailability.Instance.GetErrorDialog(this, result.ErrorCode, 0).Show();
return;
}
try
{
result.StartResolutionForResult(this, REQUEST_CODE_RESOLUTION);
}
catch (IntentSender.SendIntentException e)
{
Log.Error(TAG, "Exception while starting resolution activity", e);
}
}
public void OnConnected(Bundle connectionHint)
{
Log.Info(TAG, "Client connected.");
DriveClass.DriveApi.NewDriveContents(_googleApiClient).SetResultCallback(this);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLUTION)
{
switch (resultCode)
{
case Result.Ok:
_googleApiClient.Connect();
break;
case Result.Canceled:
Log.Error(TAG, "Unable to sign in, is app registered for Drive access in Google Dev Console?");
break;
case Result.FirstUser:
Log.Error(TAG, "Unable to sign in: RESULT_FIRST_USER");
break;
default:
Log.Error(TAG, "Should never be here: " + resultCode);
return;
}
}
}
void IResultCallback.OnResult(Java.Lang.Object result)
{
var contentResults = (result).JavaCast<IDriveApiDriveContentsResult>();
if (!contentResults.Status.IsSuccess) // handle the error
return;
Task.Run(() =>
{
var writer = new OutputStreamWriter(contentResults.DriveContents.OutputStream);
writer.Write("Stack Overflow");
writer.Close();
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.SetTitle("New Text File")
.SetMimeType("text/plain")
.Build();
DriveClass.DriveApi
.GetRootFolder(_googleApiClient)
.CreateFile(_googleApiClient, changeSet, contentResults.DriveContents);
});
}
public void OnConnectionSuspended(int cause)
{
throw new NotImplementedException();
}
public IDriveContents DriveContents
{
get
{
throw new NotImplementedException();
}
}
public Statuses Status
{
get
{
throw new NotImplementedException();
}
}
}
Ref: https://developers.google.com/drive/android/create-file

Resources