xamarin / AndroidSupportComponents

Xamarin bindings for Android Support libraries - For AndroidX see https://github.com/xamarin/AndroidX
MIT License
146 stars 56 forks source link

How to override the browser to use for custom tabs? #123

Closed lorenh closed 5 years ago

lorenh commented 5 years ago

Xamarin.Android Version:

8.1

Operating System & Version:

Windows 7, Visual Studio 2017

Support Libraries Version (eg: 23.3.0):

Xamarin.Android.Support.CustomTabs version 27.0.2.1

Describe your Issue:

I would like an example of how to override the package to use to display custom tabs. On a phone that has Microsoft Edge for Android installed and set as the default browser app, custom tabs do not work properly, so we would like to detect this and change back to "com.android.chrome". However I am not seeing an example of how to do this. I tried passing "com.android.chrome" to BindService on the custom tabs activity manager, but Edge still was used, so I'm clearly doing something wrong.

(You can ignore most of this code, it's a work in progress, an early attempt at making this sample more robust in cases where Edge is installed, or where no browser is installed that supports custom tabs https://github.com/IdentityModel/IdentityModel.OidcClient.Samples/blob/master/AndroidClientChromeCustomTabs/AndroidClientChromeCustomTabs/ChromeCustomTabsWebView.cs )


using Android.Content;
using Android.Graphics;
using Android.Support.CustomTabs;
using IdentityModel.OidcClient.Browser;
using System;
using System.Threading.Tasks;

namespace Auth0.OidcClient
{
    public class ChromeCustomTabsWebView : IBrowser
    {
        private readonly Activity context;
        private CustomTabsActivityManager customTabsManager;

        public ChromeCustomTabsWebView(Activity context)
        {
            this.context = context;
        }

        public Task<BrowserResult> InvokeAsync(BrowserOptions options)
        {
            if (string.IsNullOrWhiteSpace(options.StartUrl))
            {
                throw new ArgumentException("Missing StartUrl", nameof(options));
            }

            if (string.IsNullOrWhiteSpace(options.EndUrl))
            {
                throw new ArgumentException("Missing EndUrl", nameof(options));
            }

            // must be able to wait for the intent to be finished to continue
            // with setting the task result
            var tcs = new TaskCompletionSource<BrowserResult>();

            // create & open chrome custom tab
            this.customTabsManager = new CustomTabsActivityManager(this.context);

            var packageToUse = CustomTabsHelper.GetPackageNameToUse(this.context);

            // If Microsoft Edge for Android is installed and set as default browser app,
            // use Chrome instead since Edge seems to currently have some bugs in their
            // custom tab implementation
            if ("com.microsoft.emmx".Equals(packageToUse, StringComparison.OrdinalIgnoreCase))
            {
                packageToUse = "com.android.chrome";
            }

            if (!this.customTabsManager.BindService(packageToUse))  <===== Edge was still used
            {
                // Cannot use custom tabs, launch URL another way
                var uri = Android.Net.Uri.Parse(options.StartUrl);

                var intent = new Intent(Intent.ActionView, uri);

                intent.AddFlags(ActivityFlags.NoHistory)
                    .AddFlags(ActivityFlags.NewTask);

                Application.Context.StartActivity(intent);
            }
            else
            {
                // build custom tab
                var builder = new CustomTabsIntent.Builder(this.customTabsManager.Session)
                   .SetToolbarColor(Color.Argb(255, 52, 152, 219))
                   .SetShowTitle(true)
                   .EnableUrlBarHiding();

                var customTabsIntent = builder.Build();

                // ensures the intent is not kept in the history stack, which makes
                // sure navigating away from it will close it
                customTabsIntent.Intent.AddFlags(ActivityFlags.NoHistory);

                void callback(string response)
                {
                    // remove handler
                    ActivityMediator.Instance.ActivityMessageReceived -= callback;

                    // set result
                    if (response == "UserCancel")
                    {
                        tcs.SetResult(new BrowserResult()
                        {
                            ResultType = BrowserResultType.UserCancel
                        });
                    }
                    else
                    {
                        tcs.SetResult(new BrowserResult()
                        {
                            Response = response,
                            ResultType = BrowserResultType.Success
                        });
                    }
                }

                // attach handler
                ActivityMediator.Instance.ActivityMessageReceived += callback;

                // launch
                customTabsIntent.LaunchUrl(this.context, Android.Net.Uri.Parse(options.StartUrl));
            }

            return tcs.Task;
        }
    }
}
lorenh commented 5 years ago

Solved the issue. I just needed a night to sleep on it (plus a little help from stack overflow)

I was missing a single line to SetPackage()


                :
                var customTabsIntent = builder.Build();

                // ensures the intent is not kept in the history stack, which makes
                // sure navigating away from it will close it
                customTabsIntent.Intent.AddFlags(ActivityFlags.NoHistory);

                customTabsIntent.Intent.SetPackage(packageToUse); <===== SetPackage does the trick
                :