2

Right now, I have to have my linker set to "Link All" in order to submit to the App Store because of the deprecated UIWebView. While doing this, I had to add [Preserve(AllMembers = true)] to my DataStores to make them work this way, but then I ran into this issue.

The following line will return null:

var dp = DependencyService.Get<ITextMeter>();

After looking into the solution, it seemed the best answer would be to add the following line into the AppDelegate:

DependencyService.Register<ITextMeter, TextMeterImplementation>();

Once I did that, I started receiving this exception:

DependencyService: System.MissingMethodException: Default constructor not found for [Interface] https://forums.xamarin.com/discussion/71072/dependencyservice-system-missingmethodexception-default-constructor-not-found-for-interface

I just want to find a working solution that will allow everything to work with the linker set to "Link All". Thanks in advance.

ITextMeter:

using System;
using Xamarin.Forms.Internals;

namespace RedSwipe.Services
{
    public interface ITextMeter
    {
        double MeasureTextSize(string text, double width, double fontSize, string fontName = null);
    }
}

TextMeterImplementation:

using System.Drawing;
using Foundation;
using RedSwipe.iOS.Services;
using RedSwipe.Services;
using UIKit;

[assembly: Xamarin.Forms.Dependency(typeof(TextMeterImplementation))]
namespace RedSwipe.iOS.Services
{
    public class TextMeterImplementation : ITextMeter
    {

        public double MeasureTextSize(string text, double width, double fontSize, string fontName = null)
        {
            var nsText = new NSString(text);
            var boundSize = new SizeF((float)width, float.MaxValue);
            var options = NSStringDrawingOptions.UsesFontLeading | NSStringDrawingOptions.UsesLineFragmentOrigin;

            if (fontName == null)
            {
                fontName = "HelveticaNeue";
            }

            var attributes = new UIStringAttributes
            {
                Font = UIFont.FromName(fontName, (float)fontSize)
            };

            var sizeF = nsText.GetBoundingRect(boundSize, options, attributes, null).Size;

            //return new Xamarin.Forms.Size((double)sizeF.Width, (double)sizeF.Height);
            return (double)sizeF.Height;
        }

    }
}
Federico Navarrete
  • 3,069
  • 5
  • 41
  • 76
Sethmr
  • 3,046
  • 1
  • 24
  • 42
  • 1
    have you tried the official fix for the UIWebView issue? https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/webview?tabs=windows#uiwebview-deprecation-and-app-store-rejection-itms-90809 – ottermatic May 12 '20 at 17:34
  • No, I have not. I have been looking for that for days though. Thank you so much! – Sethmr May 12 '20 at 18:05
  • @ottermatic I was mistaken. I have used that solution. That fixes the UIWebView issue, but leaves me with my DependencyService not working. – Sethmr May 12 '20 at 18:47
  • @Sethmr Hi , whether have a try with **SDK Only** to check that ? – Junior Jiang May 13 '20 at 02:35
  • @JuniorJiang-MSFT I had the same issue and fixed with **SDK Only** but **Link All** should give me smaller size and I am interesting to try it. Any suggestion for this? – cahyo May 13 '20 at 06:07
  • 1
    @cahyo If using **Link All** , Have a try with [Skipping Assemblies](https://learn.microsoft.com/en-us/xamarin/ios/deploy-test/linker?tabs=macos#skipping-assemblies) to skip the assembly which will occur error in project . – Junior Jiang May 13 '20 at 06:25
  • I ended up getting it working with SDK Only, but it didn't just work with all my configurations that way. It felt magic when it started working, because at that point I was working on something else and all the sudden I both has SDK Only on and the DependencyService started working. It was after I had removed all the extra stuff I had added to make things work like the Preserve stuff and extra Register calls that it began working again. – Sethmr May 13 '20 at 14:31
  • @Sethmr Glad solved that ! It's a magical setting :-) – Junior Jiang May 14 '20 at 03:11
  • @Sethmr What exactly worked for you? Which assembly did you set to skipping the assemblies parameter? I am facing exactly the same issue. – PlusInfosys May 16 '20 at 12:16
  • Set it to SDK Only and leave it alone. Then remove any code you added to get it working. This fixed the dependency services..... I don't know if I had to clean any caches before it took effect. – Sethmr May 19 '20 at 11:41

1 Answers1

1

Add this [Preserve (AllMembers = true)] in your TextMeterImplementation before class implementation.

Your code would be like:

using System.Drawing;
using Foundation;
using RedSwipe.iOS.Services;
using RedSwipe.Services;
using UIKit;
using Xamarin.Forms.Internals; // Add This import

[assembly: Xamarin.Forms.Dependency(typeof(TextMeterImplementation))]
namespace RedSwipe.iOS.Services
{
    [Preserve (AllMembers = true)]
    public class TextMeterImplementation : ITextMeter
    {

        public double MeasureTextSize(string text, double width, double fontSize, string fontName = null)
        {
            var nsText = new NSString(text);
            var boundSize = new SizeF((float)width, float.MaxValue);
            var options = NSStringDrawingOptions.UsesFontLeading | NSStringDrawingOptions.UsesLineFragmentOrigin;

            if (fontName == null)
            {
                fontName = "HelveticaNeue";
            }

            var attributes = new UIStringAttributes
            {
                Font = UIFont.FromName(fontName, (float)fontSize)
            };

            var sizeF = nsText.GetBoundingRect(boundSize, options, attributes, null).Size;

            //return new Xamarin.Forms.Size((double)sizeF.Width, (double)sizeF.Height);
            return (double)sizeF.Height;
        }

    }
}