For those who just want code: https://github.com/SuavePirate/Xamarin.Onion
Don’t forget:
- Part 1 on the general project structure: Onionizing Xamarin Part 1
- Part 2 on our Domain and Application layers: Onionizing Xamarin Part 2
- Part 3 on our Infrastructure layer: Onionizing Xamarin Part 3
- Part 4 on our Client layer and Xamarin.Forms implementation: Onionizing Xamarin Part 4
A strong and scale-able architecture is important in applications, especially in Mobile Apps. APIs and SDKs are constantly changing, new technology is constantly released, and team sizes are always changing. A solid Onion Architecture can save a development team a lot of time by making it simple to change service implementations, restrict access to certain areas, making logic flow easy to follow, and making testing isolated blocks of code easier.
Some of the important topics this will cover:
- Separation of Concerns
- Inversion of Control
- Dependency Injection
- Model-View-ViewModel
- Testability
- Why all these things are important
Part 5
In this section, we will look at how to expand our Inversion of Control container with platform specific code. Specifically, we will implement some pieces of the HockeyApp SDK so that we can make calls to it from our Client or Infrastructure layers.
Our example will focus on just Android, but the same principles can be applied to any of the unique platform projects.
Platforms.Android
First thing we need to do is make sure we also install the MvvmLight nuget package in your Android project, as well as the HockeyApp Xamarin package.
From here, we can go back to our Application.Interface layer and create a new service:
ICrashAnalyticsService.cs
public interface ICrashAnalyticsService { void Initialize(); void GetFeedback(); }
Setting it up generic like this allows us to switch providers from HockeyApp to some other service should that be a need in the future.
Back in our Android project, let’s implement the ICrashAnalyticsService
with our HockeyApp logic.
HockeyAppService.cs
public class HockeyAppService : ICrashAnalyticsService { private const string HOCKEYAPP_KEY = "YOUR_HOCKEYAPP_KEY"; private readonly Android.App.Application _androidApp; private readonly Activity _context; public HockeyAppService(Activity context, Android.App.Application androidApp) { _context = context; _androidApp = androidApp; } public void GetFeedback() { FeedbackManager.ShowFeedbackActivity(_context.ApplicationContext); } public void Initialize() { CrashManager.Register(_context, HOCKEYAPP_KEY); MetricsManager.Register(_androidApp, HOCKEYAPP_KEY); UpdateManager.Register(_context, HOCKEYAPP_KEY); FeedbackManager.Register(_context, HOCKEYAPP_KEY); } }
Now we can create an IoCConfig
class specific to our Android project. Because SimpleIoC
uses a singleton for its container, we can register classes in our platform specific classes before our registrations in the Client layer.
AndroidIoCConfig.cs
public class AndroidIoCConfig { public void RegisterAndroidServices(Android.App.Application application, Activity activity) { var hockeyService = new HockeyAppService(activity, application); hockeyService.Initialize(); SimpleIoc.Default.Register<ICrashAnalyticsService>(() => hockeyService); } }
Don’t forget to add a reference to the Application.Interfaces
project in your platform project.
Lastly, let’s update our MainActivity
to initialize our AndroidIoCConfig
before we start up the Xamarin.Forms app:
MainActivity.cs
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { protected override void OnCreate(Bundle bundle) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; base.OnCreate(bundle); global::Xamarin.Forms.Forms.Init(this, bundle); InitializeIoC(); LoadApplication(new App()); } private void InitializeIoC() { var container = new AndroidIoCConfig(); container.RegisterAndroidServices(Application, this); } }
Now we can make calls to our ICrashAnalyticsService
from the Client layer, and use the Android specific logic. For example, we can pass the ICrashAnalyticsService
into the constructor of a ViewModel
, and call the GetFeedback()
method to get access to the HockeyApp Feedback view.
ExampleViewModel.cs
public class ExampleViewModel : BasePageViewModel { private readonly ICrashAnalyticsService _crashAnalyticsService; private ICommand _feedbackCommand; public ICommand FeedbackCommand { get { return _feedbackCommand ?? (_feedbackCommand = new RelayCommand(() => { _crashAnalyticsService.GetFeedback(); })); } } }
It’s all that simple! The same pattern can be applied to anything that needs to be platform specific.
What’s Next
In the next and final segment, we will look at building mock implementation of our Infrastructure layer and using them to test layers individually in Unit tests.
2 thoughts on “Onionizing Xamarin Part 5”