Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xamarin.mac support #97

Closed
mphill opened this issue Jun 2, 2020 · 9 comments
Closed

Xamarin.mac support #97

mphill opened this issue Jun 2, 2020 · 9 comments

Comments

@mphill
Copy link
Contributor

mphill commented Jun 2, 2020

Running a Xamarin.mac app that uses NetSparkle crashes on instantiation of NetSparkle with version 2.0 with the exception: Attribute of type System.Reflection.AssemblyProductAttribute

Supporting NetSparkle on Xamarin.mac would be a great addition. I noticed the core package has some windows specific references like Microsoft.Win32.Registry. If that was moved from the core package and into the Windows specific UI implementation it would allow NetSparkle to be used on Linux, Mac, Windows and maybe even iOS/Android (In-app dialogs about new versions).

Thanks.

@mphill
Copy link
Contributor Author

mphill commented Jun 2, 2020

A quick update, this is working on master now.

However, iOS and MacOS apps are not supported.

                if (_configuration == null)
                {
#if NETSTANDARD
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        _configuration = new RegistryConfiguration(_appReferenceAssembly);
                    }
                    else
                    {
                        _configuration = new JSONConfiguration(_appReferenceAssembly);
                    }
#else
                    _configuration = new RegistryConfiguration(_appReferenceAssembly);
#endif
                }

Are you Ok if I do a pull request to add an InfoPlistConfiguration?

On iOS and MacOS Info.plist is the analog to AssemblyInfo in some respects.

        protected Configuration(string referenceAssembly, bool isReflectionBasedAssemblyAccessorUsed)
        {
            // set default values
            InitWithDefaultValues();

            // set the value
            UseReflectionBasedAssemblyAccessor = isReflectionBasedAssemblyAccessorUsed;
            // save the reference assembly
            ReferenceAssembly = referenceAssembly;

            try
            {
                // set some value from the binary
                AssemblyAccessor accessor = new AssemblyAccessor(referenceAssembly, UseReflectionBasedAssemblyAccessor);
                ApplicationName = accessor.AssemblyProduct;
                InstalledVersion = accessor.AssemblyVersion;
            }
            catch
            {
                CheckForUpdate = false;
            }

        }

This code would need to be refactored to abstract the AssemblyAccessor out.

@mphill mphill changed the title Crashes on Xamarin.mac with "Attribute of type System.Reflection.AssemblyProductAttribute" Xamarin.mac support Jun 2, 2020
@Deadpikle
Copy link
Member

Deadpikle commented Jun 2, 2020

Yes, you'd be welcome to open a PR. A few things, though:

  1. If you're on macOS, I highly recommend using Sparkle instead of this lib as it is a native library that has stood the test of time in terms of features and usage. (Also has delta updates.) I got it working on an Avalonia app, so I think it should work on Xamarin.Mac. See my directions for using Sparkle with Avalonia perhaps.
  2. A macOS/iOS-specific Configuration would have to be a mix of Info.plist use and JSONConfiguration use, since we won't be able to write to the Info.plist file. However, a better way to do this would be to implement a new IAssemblyAccessor implementation that reads from Info.plist, since the JSONConfiguration should work fine for everything else. We'd need some way to pass in the appropriate AssemblyAccessor to the Configuration subclass, which might take a little more work. (The configuration classes need read/write capabilities and store info on when updates were checked, etc. The assembly accessor classes just give info on the actual assembly and only need read permissions.)

If you're working on it, why don't you do an IAssemblyAccessor subclass that reads from Info.plist? I would need a little more time to see how to do the other work.

Edit: Also, believe it or not, Microsoft.Win32.Registry targets .NET Standard!

@mphill
Copy link
Contributor Author

mphill commented Jun 2, 2020

If you're on macOS, I highly recommend using Sparkle instead of this lib

Thanks for the recommendation, but maintaining native bindings has its own set of issues, and it can be very time consuming. I'd like to explore what supporting Xamarin (Mac, Android, iOS) apps might look like. Using sharpie to generate ApiDefintions is very tedious.

If you're working on it, why don't you do an IAssemblyAccessor subclass that reads from Info.plist?

I can do this, but in order to read the Info.plist at runtime, I would need to add Xamarin.Mac as a dependency in order to call NSBundle.MainBundle.ObjectForInfoDictionary
i.e.

        public string AssemblyVersion => GetInfoPlistValue("CFBundleShortVersionString");

        private string GetInfoPlistValue(string identifier)
        {
            return NSBundle.MainBundle.ObjectForInfoDictionary(identifier).ToString();
        }

I doubt you want Xamarin as a project dependency, is there a way to pass this in somehow. I didn't see anything obvious in code.

JSONConfiguration is not public so I can't access that in the main project - but also it reeds from the file system. In Xamarin apps you'd want to use app preferences or NSUserDefaults

Is there a way to allow a developer manually create something to pass in the constructor like an IConfiguration

@Deadpikle
Copy link
Member

Thanks for the recommendation, but maintaining native bindings has its own set of issues, and it can be very time consuming. I'd like to explore what supporting Xamarin (Mac, Android, iOS) apps might look like. Using sharpie to generate ApiDefintions is very tedious.

Understood.

Is there a way to allow a developer manually create something to pass in the constructor like an IConfiguration

You can set SparkleUpdater.Configuration = myConfig; (see here) or do something like

var sparkle = new SparkleUpdater(...)
{
    Configuration = new MyConfig()
};

Just don't call the default constructor in the subclass for now.

Hm...regarding Info.plist: I don't see yet why we couldn't just read that in as XML. We don't really need a lib for reading that file, do we?

Regarding NSUserDefaults -- I can see why we'd need a dependency for this one. I don't know of a way to do this without some sort of native code. I am not unopposed to adding a NetSparkleUpdater.XamarinMac project or similar that has the extra dependency in it along with special Configuration or other classes that are specific to Xamarin. That way it's not a dependency in the main project.

(I have to apologize, here: normally I'd do a bit more research on my end, but life is very busy right now, and I don't have a lot of time during the work week for extra things. I've not used Xamarin before, so I am depending on your experience here.)

@mphill
Copy link
Contributor Author

mphill commented Jun 3, 2020

Hm...regarding Info.plist: I don't see yet why we couldn't just read that in as XML. We don't really need a lib for reading that file, do we?

I think that would work. I thought in the past I saw binary data in the info.plist once compiled, but looking around I don't see it. I think parsing the info.plist as xml works, but if you add a new project it could all be done with native calls.

I would propose this, a new project named:

NetSparkleUpdater.Xamarin with NetSparkleUpdater as a reference.

It would hold OS specific implications for iOS and MacOS to start, with Android added a little later as I find time.

In the main project I think there would be compiler directive to do this:

#if __MACOS__ || __IOS__
using NetSparkleUpdater.Xamarin;
#endif

...

#if __MACOS__ || __IOS__
     _configuration = new PListInfoConfiguration(_appReferenceAssembly); // class located in NetSparkleUpdater.Xamarin
#endif

Thoughts?

@Deadpikle
Copy link
Member

NetSparkleUpdater.Xamarin sounds fine along with the ref. You don't need to touch the main project though since you can set the Configuration property on SparkleUpdater without SparkleUpdater needing to know about the extra refs.

@Deadpikle
Copy link
Member

Posted this in PR #98 too, but for historical reference regarding referencing Xamarin in VS:

I'll try to look at the Xamarin.Mac thing too. I do have a Mac on hand and can take a look, I think. Perhaps if the project were created on macOS then referenced from the SLN manually? I'm not opposed to having a separate SLN if we have to. I did a quick test, and a Xamarin library project can reference the latest previews of NetSparkle on macOS, so it should be possible...

@Deadpikle
Copy link
Member

Deadpikle commented Jun 7, 2020

I was able to add a Xamarin project to the solution from Visual Studio for macOS. Visual Studio on Windows is complaining on my end, but no big deal.

I had to run a manual dotnet restore from within src/NetSparkle before Visual Studio for macOS would build the Xamarin DLL project.

Once things are working, a new GitHub action can be set up to build and deploy that package to NuGet.

So, I would actually recommend a few things. Configuration classes, as they are right now, are more for saving and loading the info on last version seen, etc. The IAssemblyAccessor classes are used by Configuration subclasses to load things. So, I think the following needs to happen for Xamarin support:

  • PListInfoAccessor class -- implements IAssemblyAccessor and grabs data from the PList
  • NSUserDefaultsConfiguration class -- subclasses Configuration and saves/loads data from NSUserDefaults.
  • Refactor Configuration (and subclasses) to accept an IAssemblyAccessor so that the user can determine how product/company/version/etc. properties are loaded rather that Configuration thinking it knows all.
    • This way, Xamarin users have the option of using either the JSONConfiguration (store on disk as JSON) or the NSUserDefaultsConfiguration.
  • Update docs somewhere on the different options for configurations and assembly accessors and which to use.
  • Add GitHub action for building and deploying NetSparkleUpdater.Xamarin NuGet
  • Update README for NetSparkleUpdater.Xamarin package

Sorry, something went wrong.

@Deadpikle Deadpikle added this to the 2.1+ milestone Jun 8, 2020
@Deadpikle Deadpikle modified the milestones: 2.2+, Future Nov 18, 2022
@Deadpikle
Copy link
Member

Given that all Xamarin support is ending on May 1, 2024 (https://dotnet.microsoft.com/en-us/platform/support/policy/xamarin), and no one else has asked for this nor helped to contribute code to this, I don't see the point of adding this to the NetSparkle library at this time. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants