How to Share Code Across Xamarin Projects

Good programmers are lazy. They never write the same code twice and they steal from others as much as possible. Or, to say it another way, they leverage good design principles to maximize code reuse and facilitate the integration of 3rd party components.

A cross-platform development framework like Xamarin is all about code reuse: “write once, run everywhere all the places you care about”. In this tutorial, I’ll walk you through setting up a new Xamarin project with the configuration I recommend for most applications.

For this tutorial, I’m be using Visual Studio 2017 with the Xamarin tools installed. The Community [free] Edition of Visual Studio has everything you need: https://www.visualstudio.com/vs/mobile-app-development/#downloadvs

New Project

When you create a new cross-platform project in Visual Studio, you are immediately asked to make two important decisions…

New Project

  1. Will you be building a separate native user interface for each platform or will you be using the Xamarin.Forms cross-platform UI framework?
  2. What will be your “code sharing strategy”? The options you are given are “Shared Project” or “Portable Class Library (PCL)”.

A good discussion about this decision of Xamarin.Forms vs. native UIs is available on the Xamarin forms here: https://forums.xamarin.com/discussion/53829/difference-between-xamarin-forms-and-native-apps-in-mobleapps-tab.

The answer to the first question will have a dramatic effect on how your application is structured; you should try to get that one right. So, what is the right answer? Unfortunately, there isn’t a single choice that’s always the right one. For one application, a single UI built with Xamarin.Forms can work very well and save you a lot of development time. For another application, building a custom native UI for each platform might be the right answer.

For this tutorial, it’s the answer to the second question that we’re more interested in. If you click the question mark icon next to “Code Sharing Strategy” in the new project dialog, you will be taken to a page (https://developer.xamarin.com/guides/cross-platform/application_fundamentals/code-sharing/) that provides a very good overview of the options. I highly recommend that you review that information before continuing (I’ll wait).

Solution Structure

Now that we have some information about the options, let’s make some choices. In the new project dialog, we’ll choose Native as our UI technology and select “Shared Project” as our code sharing strategy (we’re not actually going to use either code sharing option but we must pick something here). This will give us a solution that looks like this in Solution Explorer (you may also have a UWP project for Windows-based devices):

Instead of using a shared project for our common code, we would like to build a library that is as reusable as possible. For example, we would like the option to add our shared library to our ASP.NET Core-based web version of our application.

Portable Class Libraries (PCLs)

Portable class libraries (PCLs) were developed as a way for developers to write libraries that could be used across different implementations of .NET (full framework, Mono, Silverlight, etc.). PCLs accomplished this by defining a set of profiles – each profile was an intersection of the APIs available in two or more .NET implementations. So, for example, if you wanted to develop a library that could be used by Xamarin developers as well as Silverlight developers, you would have your library target the PCL profile that included both of those platforms. When writing your library, you would only be able to use the APIs that are available for all the platforms in the selected profile.

.NET Standard

With .NET Standard, Microsoft is working to create a better solution for the problem that PCLs were designed to solve. Think of .NET Standard as just a list of APIs that an implementation of .NET can support. As a library developer, if you target .NET Standard 1.2, your library can be used with any implementation of .NET that supports all the APIs defined for .NET Standard 1.2. Since PCLs will eventually be completely replaced by .NET Standard, it’s a good idea to get on that train!

See this page, https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard, for a more in-depth introduction to .NET Standard.

For our common (non-UI) code, we’ll add a new .NET Standard library to our Xamarin project.

The version of .NET Standard we are targeting is available as part of the project’s properties.

The native platform projects can now reference and use this library like a typical .NET class library project but we can also use this library in any application that is running on top of an implementation of .NET Standard 1.4. Xbox version of MyApp coming soon!

There are some known issues with using a .NET Standard library project within a Xamarin.Forms-based solution. Until these are resolved, you should take a look at (https://bugzilla.xamarin.com/show_bug.cgi?id=53474) and (https://bugzilla.xamarin.com/show_bug.cgi?id=53060) if you are planning to use Xamarin.Forms and .NET Standard together.

Dependency Injection

For code that is purely platform neutral, our new .NET Standard library will work well. However, sometimes, the implementation of an operation requires some platform-specific code. For example, if our file I/O code needs to obtain the path of the directory to write to, how to obtain that path will differ between iOS and Android (and Xbox). Dependency injection can provide a clean way to solve this problem.

First, we’ll define an interface (in the library) for the functionality that our .NET Standard library requires:

     public interface IStoragePathProvider
     {
       string GetPath();
     }

Each platform-specific project can then provide an implementation of the interface.

     public class StoragePathProvider : IStoragePathProvider
  { public string GetPath() { ... }   }

Finally, whenever our .NET Standard library needs the functionality provided by a native implementation, it can ask our dependency injection framework for an instance.

     var pathProvider = DependencyService.Get<IStoragePathProvider>(); 

This architecture means…

  1. We can trigger platform-specific functionality within our common library without taking a dependency on any platform-specific code.
  2. We avoid artifacts that are common in other cross-platform code sharing approaches (compiler directives, partial classes, etc.).
  3. If we use the library in a new type of project (e.g. Xbox), it will not require any modifications to the library itself (just an implementation of IStoragePathProvider in the new platform-specific project). This sounds like a software design principle. Gold star awarded if you said Open-Closed Principle (OCP)!

Conclusion

Working with the Xamarin platform is an exciting place to be. The acquisition of Xamarin by Microsoft has already resulted in better .NET platform integration and Visual Studio support, but, the journey is still in progress! The introduction of things like .NET Standard and .NET Core will continue to have an impact on how Xamarin applications are constructed. Just remember that as the technologies continue to evolve, they do not replace good software design practices and principles – they enable them. Learn about all the new things and use them in your projects if you can, but always try to be a good lazy programmer: just write it once or avoid writing it altogether if you can.


Author: Jason Bell, one of Accelebrate's Mobile Development instructors


In-Depth Xamarin Training

For in-depth Xamarin training, click here to view all of Accelebrate's Xamarin training courses for you and your staff.



Contact Us:

Accelebrate’s training classes are available for private groups of 3 or more people at your site or online anywhere worldwide.

Don't settle for a "one size fits all" public class! Have Accelebrate deliver exactly the training you want, privately at your site or online, for less than the cost of a public class.

For pricing and to learn more, please contact us.

Contact Us Train For Us

Toll-free in US/Canada:
877 849 1850
International:
+1 678 648 3113

Toll-free in US/Canada:
866 566 1228
International:
+1 404 420 2491

925B Peachtree Street, NE
PMB 378
Atlanta, GA 30309-3918
USA

Subscribe to our Newsletter:

Never miss the latest news and information from Accelebrate:

Microsoft Gold Partner

Please see our complete list of
Microsoft Official Courses

Recent Training Locations

Alabama

Huntsville

Montgomery

Birmingham

Alaska

Anchorage

Arizona

Phoenix

Tucson

Arkansas

Fayetteville

Little Rock

California

San Francisco

Oakland

San Jose

Orange County

Los Angeles

Sacramento

San Diego

Colorado

Denver

Boulder

Colorado Springs

Connecticut

Hartford

DC

Washington

Florida

Fort Lauderdale

Miami

Jacksonville

Orlando

Saint Petersburg

Tampa

Georgia

Atlanta

Augusta

Savannah

Idaho

Boise

Illinois

Chicago

Indiana

Indianapolis

Iowa

Ceder Rapids

Des Moines

Kansas

Wichita

Kentucky

Lexington

Louisville

Louisiana

Banton Rouge

New Orleans

Maine

Portland

Maryland

Annapolis

Baltimore

Hagerstown

Frederick

Massachusetts

Springfield

Boston

Cambridge

Michigan

Ann Arbor

Detroit

Grand Rapids

Minnesota

Saint Paul

Minneapolis

Mississippi

Jackson

Missouri

Kansas City

St. Louis

Nebraska

Lincoln

Omaha

Nevada

Reno

Las Vegas

New Jersey

Princeton

New Mexico

Albuquerque

New York

Buffalo

Albany

White Plains

New York City

North Carolina

Charlotte

Durham

Raleigh

Ohio

Canton

Akron

Cincinnati

Cleveland

Columbus

Dayton

Oklahoma

Tulsa

Oklahoma City

Oregon

Portland

Pennsylvania

Pittsburgh

Philadelphia

Rhode Island

Providence

South Carolina

Columbia

Charleston

Spartanburg

Greenville

Tennessee

Memphis

Nashville

Knoxville

Texas

Dallas

El Paso

Houston

San Antonio

Austin

Utah

Salt Lake City

Virginia

Richmond

Alexandria

Arlington

Washington

Tacoma

Seattle

West Virginia

Charleston

Wisconsin

Madison

Milwaukee

Alberta

Edmonton

Calgary

British Columbia

Vancouver

Nova Scotia

Halifax

Ontario

Ottawa

Toronto

Quebec

Montreal

Puerto Rico

San Juan

© 2013-2019 Accelebrate, Inc. All Rights Reserved. All trademarks are owned by their respective owners.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.