Bug 51629 - ShouldInteractWithUrl not getting called on iOS 10.
Summary: ShouldInteractWithUrl not getting called on iOS 10.
Status: CONFIRMED
Alias: None
Product: iOS
Classification: Xamarin
Component: General (show other bugs)
Version: XI 10.4 (C9)
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-01-18 23:36 UTC by ye_he
Modified: 2017-07-17 23:12 UTC (History)
9 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
A few changes to the blank Xamarin forms App template. (540.78 KB, application/x-rar)
2017-01-18 23:36 UTC, ye_he
Details
Modified TestApp (276.41 KB, application/x-zip-compressed)
2017-07-17 23:12 UTC, Ammar Mheir
Details

Description ye_he 2017-01-18 23:36:55 UTC
Created attachment 19393 [details]
A few changes to the blank Xamarin forms App template.

I've created a blank Xamarin Forms app on Visual Studio 2016. And I added only a few things to test the 'ShouldInteractWithUrl' delegate.

1. A custom label class with empty content in the forms project.

    public class AutoHyperLinkLabel : Label
    {
    }

2. Reference this custom label in the MainPage.

    <local:AutoHyperLinkLabel Text="Welcome to Xamarin Forms! http://www.google.com"
                              VerticalOptions="Center"
                              HorizontalOptions="Center" />
3. Custom iOS view renderer.

    public class AutoHyperLinkRenderer : ViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            var view = (AutoHyperLinkLabel) Element;
            if (view == null) return;

            UITextView uiTextView = new UITextView(new CGRect(0, 0, view.Width, view.Height))
            {
                Editable = false,
                ScrollEnabled = false,
                Selectable = true,
                UserInteractionEnabled = true,
                Text = view.Text,
                BackgroundColor = UIColor.Clear,
                DataDetectorTypes = UIDataDetectorType.All,
            };

            uiTextView.TextContainer.LineFragmentPadding = 0;
            uiTextView.TextContainerInset = new UIEdgeInsets(0, 0, 0, 0);

            uiTextView.ShouldInteractWithUrl = (arg1, url, arg3) =>
            {
                // breakpoint gets hit on iOS 9 but not on iOS 10.
                return false;
            };
            
            SetNativeControl(uiTextView);
        }
    }

The issue is the anonymous method set to ShouldInteractWithUrl not called on iOS 10.
The result is that I cannot intercept URL clicks on the UITextView on iOS 10.

It's kind of urgent, anyone has any idea?

Above behaviours are noticed on real devices:
iPhone 5S (iOS 9)
iPhone SE (iOS 10)

The project fils is in the attachment.
Comment 1 adrianknight89 2017-02-13 00:05:44 UTC
I can confirm this issue. Have you tried creating a custom View with a bindable TextProperty? You're using a Label but converting it into a UITextView on the iOS side. Now, I don't think that's the problem since you said it works for iOS 9, but if you are looking for solutions, it's one thing to check.

Also, using a named method instead of a lambda doesn't seem to fix the issue.
Comment 2 ye_he 2017-02-13 00:34:30 UTC
The workaround of this issue is to set the Delegate manually.

In the initialisation of UITextView:

Delegate = new MyTextViewDelegate(this)

Create a separate class:

        private class MyTextViewDelegate : UITextViewDelegate
        {
            private AutoHyperLinkRenderer _renderer;

            public MyTextViewDelegate(AutoHyperLinkRenderer renderer)
            {
                _renderer = renderer;
            }

            public override bool ShouldInteractWithUrl(UITextView textView, NSUrl URL, NSRange characterRange)
            {
                return _renderer.ShouldInteractWithUrl(textView, URL, characterRange);
            }
        }

Works on iOS 9 and 10.

I guess these things are doing exactly the same jobs as what `ShouldInteractWithUrl` claims to do.
Comment 3 Paul DiPietro [MSFT] 2017-02-15 19:35:47 UTC
I'm rather sure that this is a Xamarin.iOS issue. It appears to do the same thing in a Xamarin.iOS project where clicking the link will open the browser on iOS 10, but not on iOS 9.
Comment 4 Onur Hazar 2017-03-29 12:27:36 UTC
Yes, I am having the same issue on Xamarin iOS project (with the latest version of Xamarin) 

I did the workaround below;

TxtView.WeakDelegate = new MyTextViewDelegate(Owner);

public class MyTextViewDelegate : UITextViewDelegate
	{
		public UIViewController Owner { get; set; }

		public MyTextViewDelegate(UIViewController owner)
		{
			Owner = owner;
		}

		public override bool ShouldInteractWithUrl(UITextView textView, Foundation.NSUrl URL, Foundation.NSRange characterRange)
		{
			//DO SOMETHING HERE WITH URL
                        return true;
		}
	}

Downgrading to xamarin cycle 8 also works.
Comment 5 Ezra 2017-04-19 16:12:46 UTC
@yehe01@gmail.com 

Do you mind sharing your Renderer class please?  

Delegate = new MyTextViewDelegate(this) does not seem to work for me. Am I missing something in my renderer class below?

I am using Xamarin.iOS 10.8. 

public class MarkdownViewRenderer : ViewRenderer<MarkdownView, UITextView>
	{
		protected override void OnElementChanged(ElementChangedEventArgs<MarkdownView> e)
		{
			if (Control == null) {
				UITextView uiView = new UITextView()
				{
					TextAlignment = UITextAlignment.Left,
					Editable = false,
					SelectedRange = new NSRange(0, 0),
					Selectable = true,
					DataDetectorTypes = UIDataDetectorType.All,
					ScrollEnabled = false,
					Delegate = new MyTextViewDelegate(this)
				};
				uiView.Text = Element.Markdown; //this is a string of html

				SetNativeControl(uiView);

			}
		}

                bool ShouldInteractWithUrl(UITextView arg1, NSUrl arg2, NSRange arg3)
		{
	            string clickedUrl = arg2.ToString().ToLower(); //does not get called?		
                    System.Diagnostics.Debug.WriteLine("clicked url: " + clickedUrl );
			return false;
                }

private class MyTextViewDelegate : UITextViewDelegate
		{
			private MarkdownViewRenderer _renderer;

			public MyTextViewDelegate(MarkdownViewRenderer renderer)
			{
				_renderer = renderer;
			}

			public override bool ShouldInteractWithUrl(UITextView textView, NSUrl URL, NSRange characterRange)
			{
				
				return _renderer.ShouldInteractWithUrl(textView, URL, characterRange);
			}
		}
Comment 6 Andy 2017-06-23 15:07:44 UTC
It's broken Xamarin team. You need to fix it.
Comment 7 Ammar Mheir 2017-07-17 23:12:37 UTC
Created attachment 23613 [details]
Modified TestApp

Was able to replicate this issue on my end using the attached sample project in Comment 1


#Replication steps

1. Downloaded sample project attached in Comment 1
2. Set breakpoint within the ShouldInteractWithUrl
3. Ran on iOS Simulator 10.3
4. Clicked on link to google.com
5. Breakpoint not hit, ShouldInteractWithUrl not being called


#Current Workaround

As indicated in Comment 2, it seems that the current workaround is to create the delegate for the UITextView manually. I attached the sample replication project from the original comment containing the workaround, I made the modification to the TestApp.iOS/AutoHyperLinkLabel.Renderer.cs file.


#Version Information

Microsoft Visual Studio Enterprise 2015
Version 14.0.25431.01 Update 3
Microsoft .NET Framework
Version 4.7.02046
Installed Version: Enterprise

Xamarin   4.5.0.486 (fec6f88)
Xamarin.iOS   10.10.0.37 (ad35de4)


#Additional Information

Although I am not specifically sure if this might be of relevance, or if the appropriate use of ShouldInteractWithUrl would need a manually created delegate: https://stackoverflow.com/a/38170861/5957162

Note You need to log in before you can comment on or make changes to this bug.