Search This Blog

Sunday 29 September 2019

Login with google in Xamarin(Android/iOS)




Install Xamarin.Auth library in your project.

Right-click on your Project Solution and select Manage Nuget for the solution.
Search for the Xamarin.Auth library and install it in all the project (Android, iOS, Xamarin Project).



Note: Another required libraries are Newtonsoft.Json and System.Net.Http

Initialize the Xamarin.Auth library in Android & iOS Project

Xamarin.Android  Project
Initialize the Xamarin.Auth library in MainActivity.cs class.

MainActivity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
    TabLayoutResource = Resource.Layout.Tabbar;
    ToolbarResource = Resource.Layout.Toolbar;
    base.OnCreate(savedInstanceState);
 
    global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
    global::Xamarin.Auth.Presenters.XamarinAndroid.AuthenticationConfiguration.Init(this, savedInstanceState); // for login with google
 
    // User-Agent tweaks for Embedded WebViews
    global::Xamarin.Auth.WebViewConfiguration.Android.UserAgent = "Mozilla/5.0 (Linux; Android 4.4.4; One Build/KTU84L.H4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Mobile Safari/537.36";
 
    #region Other Xamarin.Auth intialization properties
 
    // Xamarin.Auth CustomTabs Initialization/Customisation
 
    //global::Xamarin.Auth.CustomTabsConfiguration.ActionLabel = null;
    //global::Xamarin.Auth.CustomTabsConfiguration.MenuItemTitle = null;
    //global::Xamarin.Auth.CustomTabsConfiguration.AreAnimationsUsed = true;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsShowTitleUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsUrlBarHidingUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsCloseButtonIconUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsActionButtonUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsActionBarToolbarIconUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsDefaultShareMenuItemUsed = false;
    //global::Xamarin.Auth.CustomTabsConfiguration.ToolbarColor = Android.Graphics.Color.LightBlue;
 
    //// ActivityFlags for tweaking closing of CustomTabs
    //// please report findings!
    //global::Xamarin.Auth.CustomTabsConfiguration.
    //   ActivityFlags =
    //        global::Android.Content.ActivityFlags.NoHistory
    //        |
    //        global::Android.Content.ActivityFlags.SingleTop
    //        |
    //        global::Android.Content.ActivityFlags.NewTask;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsWarmUpUsed = true;
    //global::Xamarin.Auth.CustomTabsConfiguration.IsPrefetchUsed = true;
    #endregion
 
       LoadApplication(new App());
}

Xamarin.iOS Project
Initialize the Xamarin.Auth library in AppDelegate.cs class.

AppDelegate.cs
using System;
using System.Collections.Generic;
using System.Linq;
 
using Foundation;
using UIKit;
 
namespace Mechat.iOS
{
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();
            return base.FinishedLaunching(app, options);
        }
    }
}
 

Xamarin.Form Project
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"          
             mc:Ignorable="d"
             x:Class="Mechat.MainPage">
    <StackLayout Margin="10">
        <Button Text="Click here to login with google" Clicked="Button_Clicked"/>
    </StackLayout>
 
</ContentPage>
 
MainPage.cs
using Mechat.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Auth;
using Xamarin.Forms;
 
namespace Mechat
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void Button_Clicked(object sender, EventArgs e)
        {
            var authenticator = new OAuth2Authenticator
                         (
                           "Google client ID",
                           "email profile",
                            new System.Uri( "https://accounts.google.com/o/oauth2/auth"),
                            new System.Uri("https://www.google.com")
                          );
 
            authenticator.AllowCancel = true;
 
            var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
            presenter.Login(authenticator);
 
            authenticator.Completed += async (senders, obj) =>
            {
                if (obj.IsAuthenticated)
                {
                    var clientData = new HttpClient();
 
                    //call google api to fetch logged in user profile info 
                    var resData = await clientData.GetAsync("https://www.googleapis.com/oauth2/v3/userinfo?access_token=" + obj.Account.Properties["access_token"]);
                    var jsonData = await resData.Content.ReadAsStringAsync();
 
                    // deserlize the jsondata and intilize in GoogleAuthClass
                    GoogleAuthClass googleObject = JsonConvert.DeserializeObject<GoogleAuthClass>(jsonData);
 
                    //you can access following property after login
                    string email = googleObject.email;
                    string photo = googleObject.picture;
                    string name = googleObject.name;
                }
                else
                {
                    //Authentication fail
                    // write the code to handle when auth failed
                }
            };
            authenticator.Error += onAuthError;
        }
 
        private void onAuthError(object sender, AuthenticatorErrorEventArgs e)
        {
            DisplayAlert("Google Authentication Error", e.Message, "OK");
        }
    }
 
}

Note: You will get google client id from the google developer console. there you need to create a project.

GoogleAuthClass.cs
using System;
using System.Collections.Generic;
using System.Text;
 
namespace Mechat.Model
{
   public class GoogleAuthClass
    {
        public string email { get; set; }
        public bool email_verified { get; set; }
        public string name { get; set; }
        public string picture { get; set; }
    }
 
}


Monday 23 September 2019

Convert a string to Title Case in Xamarin.Forms

Create the ToTitle method with the following code.

public static string ToTitle(string data)
{
    if (!string.IsNullOrEmpty(data))
    {
        TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
        return string.Format(textInfo.ToTitleCase(data.ToLower()));
    }

    return data;
}

Now use this method on any page to convert any string into Title case.

string msg = "title test string";
Console.WriteLine(msg.ToTitle());


Wednesday 18 September 2019

Reduce & Resize image without rotation in C#


private void ReduceImageSize(double scaleFactor, Stream sourcePath, string targetPath)
        {
            const int OrientationKey = 0x112;
            const int NotSpecified = 0;
            const int NormalOrientation = 1;
            const int MirrorHorizontal = 2;
            const int UpsideDown = 3;
            const int MirrorVertical = 4;
            const int MirrorHorizontalAndRotateRight = 5;
            const int RotateLeft = 6;
            const int MirorHorizontalAndRotateLeft = 7;
            const int RotateRight = 8;

            using (var image = System.Drawing.Image.FromStream(sourcePath))
            {
                var newWidth = System.Convert.ToInt32((image.Width * scaleFactor));
                var newHeight = System.Convert.ToInt32((image.Height * scaleFactor));

                if (image.Height > 3000)
                {
                    newHeight = System.Convert.ToInt32((image.Height * 0.25));
                    newWidth = System.Convert.ToInt32((image.Width * 0.25));
                }
                if (image.Height <= 600)
                {
                    newHeight = System.Convert.ToInt32((image.Height * 1));
                    newWidth = System.Convert.ToInt32((image.Width * 1));
                }
                var thumbnailImg = new Bitmap(newWidth, newHeight);
                var thumbGraph = Graphics.FromImage(thumbnailImg);
                if (image.Height > 3000)
                {
                    thumbGraph.CompositingQuality = CompositingQuality.HighSpeed;
                    thumbGraph.SmoothingMode = SmoothingMode.HighSpeed;
                }
                else if (image.Height <= 600)
                {
                    thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
                    thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
                }
                else
                {
                    thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
                    thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
                }


                thumbGraph.InterpolationMode = InterpolationMode.High;
                var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
                thumbGraph.DrawImage(image, imageRectangle);
                if (image.PropertyIdList.Contains(OrientationKey))
                {
                    var orientation = System.Convert.ToInt32(image.GetPropertyItem(OrientationKey).Value[0]);

                    switch (orientation)
                    {
                        case NotSpecified: // Assume it is good.
                        case NormalOrientation:
                            // No rotation required.
                            break;
                        case MirrorHorizontal:
                            thumbnailImg.RotateFlip(RotateFlipType.RotateNoneFlipX);
                            break;
                        case UpsideDown:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
                            break;
                        case MirrorVertical:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate180FlipX);
                            break;
                        case MirrorHorizontalAndRotateRight:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate90FlipX);
                            break;
                        case RotateLeft:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
                            break;
                        case MirorHorizontalAndRotateLeft:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate270FlipX);
                            break;
                        case RotateRight:
                            thumbnailImg.RotateFlip(RotateFlipType.Rotate270FlipNone);
                            break;
                        default:
                            throw new NotImplementedException("An orientation of " + orientation + " isn't implemented.");
                    }
                }
                thumbnailImg.Save(targetPath, image.RawFormat);
            }
        }

Tuesday 17 September 2019

Custom Renderer for displaying html text into Label



In Xamarin Form project create ExtendedHtmlLabel Class that Inherit the Label Class.

ExtendedHtmlLabel.cs
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace Mechat.Renderer
{
    public class ExtendedHtmlLabel :Label
    {

    }

}


Xamarin.Android
Then in Android Project Create the Class ExtendedHtmlLabelRenderer.cs that Inherit the Label Renderer.

ExtendedHtmlLabelRenderer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.Text;
using Android.Text;
using Android.Views;
using Android.Widget;
using Mechat.Droid.Renderer;
using Mechat.Renderer;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly:ExportRenderer(typeof(ExtendedHtmlLabel),typeof(ExtendedHtmlLabelRenderer))]
namespace Mechat.Droid.Renderer
{
    public class ExtendedHtmlLabelRenderer : LabelRenderer
    {

        public ExtendedHtmlLabelRenderer(Context context) : base(context)
        {

        }
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.TextFormatted = Build.VERSION.SdkInt >= BuildVersionCodes.N
? Html.FromHtml(Element.Text, FromHtmlOptions.ModeCompact)
: Html.FromHtml(Element.Text);
                Control.MovementMethod = new Android.Text.Method.LinkMovementMethod();
            }
        }
    }
}


Xamarin.iOS

Then in iOS Project Create the Class ExtendedHtmlLabelRenderer.cs that Inherit the Label Renderer.

ExtendedHtmlLabelRenderer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Foundation;
using Mechat.iOS.Renderer;
using Mechat.Renderer;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ExtendedHtmlLabel), typeof(ExtendedHtmlLabelRenderer))]
namespace Mechat.iOS.Renderer
{
    public class ExtendedHtmlLabelRenderer :LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (Control != null && Element != null && !string.IsNullOrWhiteSpace(Element.Text))
            {
                var attr = new NSAttributedStringDocumentAttributes();
                var nsError = new NSError();
                attr.DocumentType = NSDocumentType.HTML;

                var myHtmlData = NSData.FromString(Element.Text, NSStringEncoding.Unicode);
                Control.Lines = 0;
                Control.AttributedText = new NSAttributedString(myHtmlData, attr, ref nsError);
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == Label.TextProperty.PropertyName)
            {
                if (Control != null && Element != null && !string.IsNullOrWhiteSpace(Element.Text))
                {
                    var attr = new NSAttributedStringDocumentAttributes();
                    var nsError = new NSError();
                    attr.DocumentType = NSDocumentType.HTML;

                    var myHtmlData = NSData.FromString(Element.Text, NSStringEncoding.Unicode);
                    Control.Lines = 0;
                    Control.AttributedText = new NSAttributedString(myHtmlData, attr, ref nsError);
                }
            }
        }
    }
}

Now implement this Renderer on Xamairn Page.

MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:extendControl="clr-namespace:Mechat.Renderer"
             mc:Ignorable="d"
             x:Class="Mechat.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <extendControl:ExtendedHtmlLabel 
           HorizontalOptions="Center" x:Name="txtLabel"
           VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace Mechat
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            txtLabel.Text = "<html><body ><h1 ><i>Hello</i></h1><br/><b>Demo Test</b><br> <b>H<sub>2</sub>O</b><br/><font color='red'>This is some text!</font></body></html>";
        }
    }
}


Get image path from Content-URI in Android (Xamarin)

MainActivity.cs
Add this method in MainActivity.cs
//Here pass the URI of image and it will return full image path.
       private string GetPathToImage(global::Android.Net.Uri uri)
        {
            String[] projection = { MediaStore.Images.Media.InterfaceConsts.Data };
            var cursor = this.ContentResolver.Query(uri, projection, null, null, null);
            cursor.MoveToFirst();
            int columnIndex = cursor.GetColumnIndex(projection[0]);
            String picturePath = cursor.GetString(columnIndex); // returns null
            if (string.IsNullOrEmpty(picturePath))
            {
                string wholeID = DocumentsContract.GetDocumentId(uri);
                string id = wholeID.Split(':')[1];
                String sel = MediaStore.Images.Media.InterfaceConsts.Id + "=?";
                var externalCursor = this.ContentResolver.Query(MediaStore.Images.Media.ExternalContentUri, projection, sel, new string[] { id }, null);
                int columnIndex1 = externalCursor.GetColumnIndex(projection[0]);
                if (externalCursor.MoveToFirst())
                {
                    picturePath = externalCursor.GetString(columnIndex1);
                }
            }
            //string doc_id = "";
            //using (var c1 = ContentResolver.Query(uri, null, null, null, null))
            //{
            //    c1.MoveToFirst();
            //    String document_id = c1.GetString(0);
            //    doc_id = document_id.Substring(document_id.LastIndexOf(":") + 1);
            //}
            //string path = null;

            //// The projection contains the columns we want to return in our query.
            //string selection = MediaStore.Images.Media.InterfaceConsts.Id + " =? ";
            //Context CurrentContext = CrossCurrentActivity.Current.Activity;

            //using (var cursor = this.ContentResolver.Query(MediaStore.Images.Media.ExternalContentUri, null, selection, new string[] { doc_id }, null))
            //{

            //    if (cursor == null) return path;
            //    var columnIndex = cursor.GetColumnIndexOrThrow(MediaStore.Images.Media.InterfaceConsts.Data);
            //    cursor.MoveToFirst();
            //    try
            //    {
            //        path = cursor.GetString(columnIndex);

            //    }
            //    catch(Exception ex)
            //    {

            //            path = uri.LastPathSegment;
            //    }

            //}
            return picturePath;
        }

Monday 16 September 2019

Fix ClearText Traffic Error in Android 9 Pie

In AndroidManifest.xml file add android:usesCleartextTraffic="true" this.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.mechat">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
  <uses-permission android:name="android.permission.INTERNET" />
   <application android:label="Mechat.Android" android:usesCleartextTraffic="true">
    </application>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

Popular Posts