Question

I'm assuming that the answer is simply no, but just in case... Is there any way of executing platform-specific code in a PCL?

My specific example lends itself nicely to a PCL. The vast majority of code is fully supported using profile104 (WP7/Windows Store/Net40). The only bit which is platform specific is the ability to launch a deep-link:

my-custom-protocol://some/url

The non-shared code is:

On WP7, it would be:
        WebBrowserTask web = new WebBrowserTask();
        web.Uri = BuildUrl();
        web.Show();

On WP8 and Windows Store it would be:
        Windows.System.Launcher.LaunchUriAsync(BuildUrl());

On Net40, I guess you would host a web-browser control.

So the common library provides custom "Task" objects which provide the implementation of "BuildUrl()". The issue is that on a supported device, you want to launch "my-custom-protocol://some/url", but on any other device you want to go to a web fallback http://mysite.com/some/url. This is all wrapped up in:

        new CustomTask(data).Show()
  • Option 1 (Current implementation): Don't use a PCL, and use #ifdefs in the CustomTaskBase class to contain the platform specifics. However, I really don't want to have to maintain platform-specific project files with cs files added as links :-(

  • Option 2: Just put the launchers in platform specific assemblies, with all the other code in a PCL. Again, I don't like this, as it seems maintenance-heavy, and doesn't reduce our project count. It also means that clients need to reference two assemblies, rather that one, which seems overkill for a few custom tasks.

  • Option 3: Inject an abstracted IPlatformSpecificLauncher into the constructor of the Launcher, which then becomes a URLBuilder. This moves the launch-code into the client, which would be copy-paste (although minimal). It does however complicate the API and makes it less readable.

        new CustomTask(new WP8Launcher(), data).Show()
    
  • Option 4: Change the API so that the CustomTask simply returns the URL to launch (and again have the launching code in-client). But then how would you implement the web-fallback on devices which don't support the custom protocol? You cant say if(platform == WP7) in the PCL, can you?

Thank you in advance of any hints and tips!

Was it helpful?

Solution

For platform-dependent functionality in a PCL the obvious answer (other than giving up) is dependency injection of some sort, or using a service locator. Your example seems to me to be a good use of DI in general, even ignoring the actual limitations of PCLs - you really are plugging in different behaviour.

"Platform enlightenment" ala RX is another approach (good overview of all these approaches here), where the PCL loads additional assemblies via reflection.

In either case you'll increase your project count. I think there's an argument that putting as much into a PCL as possible and separating out platform-specific functionality into separate small chunks is cleaner than a big shared library which is linked from multiple projects, where the distinction between shared and #if-conditional code is less obvious.

As to the question "can you say if (platform == WP7)", your PCL can't contain platform-conditional code, though a PCL could target a subset of platforms all of which contain the required functionality.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top