Xamarin IOS Facebook SDK LoginButton - ios

Im new to Xamarin and IOS development and dont understand why I get this following error:
But first some Information:
Im using this SDK:
https://components.xamarin.com/view/facebookios
and creating my LoginButtin in my ViewController in ViewDidLoad like this:
loginButton = new LoginButton(new CGRect(48, 0, 218, 46))
{
LoginBehavior = LoginBehavior.Native,
ReadPermissions = readPermissions.ToArray()
};
View.AddSubview(button);
But in my Storyboard I get this error message:
Edit: my ViewController.cs
using System;
using System.Collections.Generic;
using UIKit;
namespace FacebookLogin
{
public partial class ViewController : UIViewController
{
List<string> readPermissions = new List<string> { "public_profile" };
LoginButton loginButton;
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
loginButton = new LoginButton(new CGRect(48, 0, 218, 46))
{
LoginBehavior = LoginBehavior.Native,
ReadPermissions = readPermissions.ToArray()
};
View.AddSubview(button);
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}

Make sure to follow the instructions found on the getting started page. I see an empty component in your solution explorer but just in case, make sure that you installed Xamarin.Facebook.iOS 4.27.1 with nugget. Of course, you also need to set up your facebook app, login, and configure the iOS portion (like setting the BundleID).
Don't create the button in the controller. What you can do is use the storyBoard designer to drop in a regular button. Then, in the properties window click on Class and it should open a dropdown menu. In the selection you should see FBSDKLoginButton, select that class. Give it a name like btnFacebook.
In the codebehind for your controller it will look like this:
string[] readPermissions = { "public_profile" };
public override void ViewDidLoad()
{
base.ViewDidLoad();
btn.LoginBehavior = LoginBehavior.Native;
btnFacebook.ReadPermissions = readPermissions;
// Handle actions once the user is logged in
btnFacebook.Completed += LoginView_Completed;
// Handle actions once the user is logged out
btnFacebook.LoggedOut += LoginView_LoggedOut;
}
private void LoginView_Completed(object sender, LoginButtonCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
if (e.Result.IsCancelled)
{
return;
}
}
private void LoginView_LoggedOut(object sender, EventArgs e)
{
}
For good measure, clean solution and recompile. The login button won't appear as a facebook login button in your designer but on runtime it will.
As for your error, I don't see anything in your designer so it's curious that it's giving you an error like that. Open the Document Outline (View -> Other Windows -> Document Outline) and see if there's any invisible garbage (elements that aren't being rendered) that has to be deleted.

First Of All! You're on the right Way To solve your issue
and Secondly, I would Suggest you that you have created a controller in the above image you need to create a View Controller File and then add a Login Screen Like a Username named Textbox Then a Password named Textbox and A login Button and then View Controller will automatically created once you save the view And Then Finally, You Save the view Controller By Adding the Following Code
partial void login_TouchUpInside(UIButton sender)
{
var auth = new OAuth2Authenticator(clientId: "YOUR_CLIENT_ID", scope: "", authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"), redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html"));
auth.Completed += Auth_Completed;
var ui = auth.GetUI();
PresentViewController(ui, true, null);
}
private async void Auth_Completed(object sender, AuthenticatorCompletedEventArgs e)
{
if (e.IsAuthenticated)
{
var request = new OAuth2Request("POST", new Uri("YOUR Location Where You want to reach After Login"), null, e.Account);
//fb://profile/<id> For opening in Facebook App.
}
DismissViewController(true, null);
}
You See the Above Code And If you Want to Open the Facebook Link In Facebook Application Just Replace URL with
fb://profile/<id>

Related

ICloudStorage.GetChildren() never return

I'm trying to access Google Drive with CloudRail using the following codes.
// Actual string value removed.
private const string GDRIVE_CLIENT_ID = "client_id";
private const string ANDROID_PACKAGE_NAME = "package_name";
private const string CLOUDRAIL_APP_KEY = "app_key";
private readonly string REDIRECT_URL = $"{ANDROID_PACKAGE_NAME}:/oauth2redirect";
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set CloudRail application key.
CloudRail.AppKey = CLOUDRAIL_APP_KEY;
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
try
{
var googleDrive = new GoogleDrive(this, GDRIVE_CLIENT_ID, "", REDIRECT_URL, "state");
googleDrive.UseAdvancedAuthentication();
m_Service = googleDrive;
Action act = () =>
{
var list = m_Service.GetChildren(#"/");
// The function call never return.
};
var thread = new Thread(new ThreadStart(act));
thread.Start();
}
catch (Exception ex)
{
}
}
After calling into ICloudStorage.GetChildren(), my apps get redirected to login into Google account. After user has logged in to Google account and granted consent to the application, the function call never return. No exception is caught either.
What could have go wrong?
I got a reply from CloudRail support team and manage to solved the issue with their help.
You need to include the IntentFilter and LaunchMode to SingleTask on top of your activity.
Also you need to put OnNewIntent method as shown below:
[Activity(Label = "Awesome.Android", LaunchMode = Android.Content.PM.LaunchMode.SingleTask)]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataScheme = "Android_Package_Name")]
public class MainActivity : Activity
{
protected override void OnNewIntent(Intent intent)
{
CloudRail.AuthenticationResponse = intent;
base.OnNewIntent(Intent);
}
}
The key is that the corresponding Activity class (in my case, MainActivity) has to be decorated with IntentFilter. Also, OnNewItent has to be overridden and passing the response back to CloudRail.AuthenticationResponse in the override.
I also found that android package name must be in full lower case, otherwise it won't work either.
Edit [2018.07.19]
Android package name must contain at least one period character (.), otherwise, you may encounter invalid_request - missing authority error.

Warning: View is not in Window Hierarchy in Xamarin.Forms

I am doing a Xamarin project, Forms and I have integrated Xam.Plugins.Messaging to send SMS from my app. For this I have created a custom renderer in my iOS project with below code:
AppDelegate smsObj = new AppDelegate();
bool a= smsObj.ShowAndSendSMS(new string[] { "123" }, "Hi there");
And in my AppDelegate, I have the code as below:
public bool ShowAndSendSMS(string[] recipients, string body)
{
UIViewController sms = new UIViewController();
if (MFMessageComposeViewController.CanSendText)
{
MFMessageComposeViewController message = new MFMessageComposeViewController();
message.Finished += (sender, e) => {
message.DismissViewController(true, null);
};
message.Body = body;
message.Recipients = recipients;
sms.PresentModalViewController(message, false);
}
return true;
}
The problem I am facing is on my first-time app launch, the functionality to share SMS doesn't work and the debug log gives me warning like "Attempt to present on whose view is not in the window hierarchy!"
However, if I restart the app, the same functionality works like a charm. Any ideas from where i have made mistake?
I think the problem is with the fact that you're newing up an AppDelegate and calling the ShowAndSendSMS from there. iOS is going to new up that AppDelegate for you upon app startup, and you should always use that, as opposed to creating a new instance of AppDelegate (at least I've never seen a situation that called for a multi-AppDelegate-instance pattern). So, try this:
Create a helper class in your project like this (I don't really like the word "helper", but that's beside the point; name it something fitting for your project):
using Foundation;
using UIKit;
public class SmsHelper
{
public bool ShowAndSendSMS(string[] recipients, string body)
{
if (MFMessageComposeViewController.CanSendText)
{
UIViewController sms = new UIViewController();
MFMessageComposeViewController message = new MFMessageComposeViewController();
message.Finished += (sender, e) => {
message.DismissViewController(true, null);
};
message.Body = body;
message.Recipients = recipients;
sms.PresentModalViewController(message, false);
}
return true;
}
}
And then change your page renderer to consume it like this:
public class SMS_Ios: PageRenderer
{
private readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
SmsHelper smsObj = new SmsHelper();
bool a = smsObj.ShowAndSendSMS(new string[] {"123"}, "Hi there");
}
}
And finally, remove ShowAndSendSMS from your AppDelegate.cs, since you'll be using your SMS helper going forward.
Let me know if that works for you.
If you have already installed the Xam.Plugins.Messaging package in the PCL and your platforms. You can just use the API from it in PCL to implement that without any special codes in your iOS platform.
You can just use the APIs of Xam.Plugins.Messaging in the PCL, like this:
// Send Sms
var smsMessenger = CrossMessaging.Current.SmsMessenger;
if (smsMessenger.CanSendSms)
smsMessenger.SendSms("+27213894839493", "Well hello there from Xam.Messaging.Plugin");
Reference: Messaging Plugin for Xamarin and Windows.

Xamarin iOS: Pass credentials over http

I am trying to pass credentials over http on my xamarin iOS project but its not working.
public partial class WebView : UIViewController
{
protected override void ViewDidLoad()
{
webView.LoadRequest(new NSUrlRequest(new NSUrl("https:example.com")));
webView.AllowsBackForwardNavigationGestures = true;
webView.NavigationDelegate = new WebViewDelegate(this);
}
}
public class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate
{
public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
//base.DidReceiveAuthenticationChallenge(webView, challenge, completionHandler);
completionHandler(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, new NSUrlCredential("username", "password", NSUrlCredentialPersistence.ForSession));
Console.WriteLine("We are authenticated");
return;
}
}
can anyone advise how to resolve this issue ?
Update:
DidReceiveAuthenticationChallenge is being called and is being called continuously in a loop. Instead of getting the expected page , I am getting a blank page and it just says "Authenticate"
From Apple's doc on PerformDefaultHandling:
Use the default handling for the challenge as though this delegate method were not implemented. The provided credential parameter is ignored.
Try UseCredential instead:
var crendential = new NSUrlCredential("user", "pass", NSUrlCredentialPersistence.ForSession);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, crendential);

using config.groovy in gwt for user preference

I have a gwt and grails legacy app that I'm upgrading and modifying.. Its a reservation calendar basically with different "views".. the problem I'm having is I want the user to be able to choose a default view for themselves upon logging in..I've done this with a grails only application before but gwt is much different..how can I pass something from config.groovy to the gwt part that select which view to show..and this view isn't a view like a grails view..think of it like restaurants..and a user may only want to see the reservations for a particular restaurant instead of the default of all restaurants
Maybe not a direct answer to your question but you can just make a ordinary GWT remote service UserPreferencesService which will store user preferences
public interface UserPreferencesService extends RemoteService {
List<Restaurant> getRestaurants(Account user);
void setRestaurants(Account user, List<Restaurant> restaurants);
}
In your entry point you can then make a decision on what kind of view you'll show to user
public final class Application implements EntryPoint {
private AuthServiceAsync authService =
GWT.create(AuthService.class);
private UserPreferencesAsync preferencesService =
GWT.create(UserPreferencesService.class);
#Override
public void onModuleLoad() {
// handle login
authService.getAccount(new Callback<Account>() {
#Override
public void onSuccess(final Account account) {
// check if user have a preferred restourants
preferencesService.getRestaurants(account,
new Callback<Account>() {
#Override
public void onSuccess(final List<Restaurant> restaurants) {
// user did not select any restaurants yet.
// Show a selection widget
if (restaurants.isEmpty) {
RestaurantSelectorWidget widget =
new RestaurantSelectorWidget();
// your custom handler here
widget.addHandler(new Handler() {
#Override
public void onSelected(/*...*/) {
// save user preferences
// and switch to normal view
}
})
RootPanel.get("container")
.add(widget);
} else {
// show normal view
}
}
}
}
}
}
}
}
Also you may take look to this plugin which is adds GWT support to grails.

MvvmCross Android Dialog bind programmatically

I want to use the Android.Dialog (Cross.UI) in my MvvmCross project. My first approach was to use AutoViews. As this feature is still fairly young, the alternative was to implement the dialog in touch and Droid platforms.
For now i'm just doing this for Droid and I need to programmatically bind the properties of the ViewModel to the elements of the Dialog.
My View and ViewModel code is the following:
View
public class DialogConfigurationView : MvxBindingDialogActivityView<DialogConfigurationViewModel>
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
DroidResources.Initialise(typeof(Resource.Layout));
Root = new RootElement()
{
new Section("Private Configuration")
{
new EntryElement("Name:"),
new EntryElement("Description:"),
new BooleanElement("Active?")
}
};
}
}
ViewModel
public class DialogConfigurationViewModel : MvxViewModel
{
public ConfigurationSet Configuration
{
get { return _configuration; }
set
{
if (_configuration != value)
{
_configuration = value;
RaisePropertyChanged(() => Configuration);
}
}
}
private ConfigurationSet _configuration;
}
My goal is to have a twoway bind the EntryElement("Name:") with the property ViewModel.Configuration.Name.
Can anyone help me with this? Can this be done?
I don't know if there are any monodroid.dialog mvvmcross samples floating around which don't use autoviews!
However.... the basic syntac for binding should be the same as MonoTouch.Dialog - e.g. something like:
new Section("Contact Info")
{
new StringElement("ID", ViewModel.Customer.ID ?? string.Empty),
new EntryElement("Name", "Name").Bind(this, "{'Value':{'Path':'Customer.Name'}}"),
new EntryElement("Website", "Website").Bind(this, "{'Value':{'Path':'Customer.Website'}}"),
new EntryElement("Primary Phone", "Phone").Bind(this, "{'Value':{'Path':'Customer.PrimaryPhone'}}"),
},
new Section("Primary Address")
{
new EntryElement("Address").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Street1'}}"),
new EntryElement("Address2").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Street2'}}"),
new EntryElement("City").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.City'}}"),
new EntryElement("State").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.State'}}"),
new EntryElement("Zip").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Zip'}}"),
},
from https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20CustomerManagement/CustomerManagement/CustomerManagement.Touch/Views/BaseCustomerEditView.cs
Note that in MvvmCross bindings for MonoTouch and MonoDroid, the default binding for things like text edit boxes is generally TwoWay by default.
If you do get a sample running, then please feel free to post it to a gist or to a repo - or to blog about it - looks like we could do with some samples to work from!

Resources