This is Part 5 of the "VB Universal Windows App" series:
- Part 1: Setting up the universal Windows app in the Dev Centers, and in VS Solution Explorer
- Part 2: Sharing XAML, Assets and Code
- Part 3: Local and Roaming settings, and In-App purchases
- Part 4: Sound effects with SharpDX
- > Part 5: How to call platform-specific APIs from common code
- Download full source code [June 21st]
So far we've been able to re-use all our code and XAML by placing them in the PCL. Actually, PCLs can only ever contain calls to APIs that are common to the platforms they target. This generally isn't a problem, because most APIs on Windows also exist on Windows Phone, and vice versa.
Today we'll explore how to call platform--specific APIs from Common code. In particular, we'll make it so our common main page can hide the Windows Phone statusbar (with connection quality, battery, clock) - when it's running on Windows Phone, of course. There's nothing that needs hiding on Windows.
Inversion of Control
We'll use a technique known as "Inversion of Control" (IOC). It sounds complicated but is easy in practice. Advanced developers frequently use IOC for unit-testing as well.
Step 1: Declare a new interface "IPlatformAbstraction" in App1_Common > App.vb, and a public field of that type.
Public Interface IPlatformAbstraction
Function SetStatusbarVisibilityAsync(isVisible As Boolean) As Task
End Interface
Public Class App
Public Shared Platform As IPlatformAbstraction
....
End Class
Step 2: Any time you want to play audio from within App1_Common, do so via the platform abstraction layer:
Await App.Platform.SetStatusbarVisibilityAsync(False)
Step 3: Now you have to provide two implementations of the interface, one in App1_Windows, and one in App1_Phone. I chose to provide it inside my two App.xaml.vb files. Remember also to assign "App1_Common.App.Platform" inside the OnLaunched method.
NotInheritable Class App
Inherits Application
Implements App1_Common.IPlatformAbstraction
Public Async Function SetStatusbarVisibilityAsync(isVisible As Boolean) Implements IPlatformAbstraction.SetStatusbarVisibilityAsync
' TODO: implement this!
End Sub
Protected Overrides Sub OnLaunched(e As LaunchActivatedEventArgs)<
App1_Common.App.Platform = Me
....
End Sub
....
End Class
How to deal with status-bar visibility on Windows Phone
Look at these screenshots. (To test how my app behaves with "software-buttons" I launched either the 720p or 1080p emulators, clicked on >> then Sensors, and turned on software buttons).
ApplicationView.GetForCurrentView().SetDesiredBoundsMode(
ApplicationViewBoundsMode.UseCoreWindow)
The screenshot on the left used ApplicationViewBoundsMode.UseVisible. You can see that it calculated the layout rectangle of my page based only on what's visible, after you take away the space for software-buttons and status-bar.
The screenshot on the right used ApplicationViewBoundsMode.UseCoreWindow. You can see that it calculated the layout rectangle of my page based on the full screen size, regardless of software-buttons and status-bar.
The status-bar visibility (at the top) is under the app's control. The app can show or hide it. Showing and hiding takes about half a second, since it's accompanied by a nice animation. These are the two methods you can use:
Await StatusBar.GetForCurrentView().ShowAsync()
Await StatusBar.GetForCurrentView().HideAsync()
The software-button visibility (at the bottom) is under the user's control. And most phones come with hardware buttons, not software buttons, so they don't even show these.
Step 4: Implement the SetStatusbarVisibility method of our Platform Abstraction Layer:
' PHONE IMPLEMENTATION, in App1_Phone > App.xaml.vb
Public Async Function SetStatusbarVisibilityAsync(isVisible As Boolean) Implements IPlatformAbstraction.SetStatusbarVisibilityAsync
If isVisible Then
Await StatusBar.GetForCurrentView().ShowAsync()>br/> Else
Await StatusBar.GetForCurrentView().HideAsync()
End If
End Sub
' WINDOWS VERSION, in App1_Windows > App.xaml.vb
Public Async Function SetStatusbarVisibilityAsync(isVisible As Boolean) Implements IPlatformAbstraction.SetStatusbarVisibilityAsync
If False Then Await Task.Delay(0) ' dummy to silence the compiler warning
End Sub
Fire-and-forget async methods
There's one final tweak I want to mention. It's inside App1_Common > AdaptiveMainPage.xaml.vb > OnNavigatedTo that I want to call SetStatusbarVisibilityAsync.
But hiding the statusbar has a half-second animation, and I don't want to delay my OnNavigatedTo method while waiting for it to finish. In effect, I want to just kick off the async method in a fire-and-forget manner.
Here is a nice idiom for fire-and-forget asyncs. It uses an extension method "FireAndForget" which I wrote. It silences the compiler warning ("hey you're not awaiting this async method"). And it demonstrates to anyone reading my code what I'm trying to do:
App.Platform.SetStatusbarVisibilityAsync(False).FireAndForget()
And here's how I implement that FireAndForget extension method:
Module AsyncHelpers
<Extension>Async Sub FireAndForget(task As Task)
Try
Await task
Catch ex As Exception
App.SendErrorReport(ex)
End Try
End Sub
End Module
Actually, in practice, I also often write two additional FireAndForget overloads, to make it easy to use with asynchronous WinRT APIs. They're implemented exactly the same way:
<Extension>Async Sub FireAndForget(task As IAsyncAction)
<Extension>Async Sub FireAndForget(Of T)(task As IAsyncOperation(Of T))
Conclusion
We've now created a complete VB Universal app - although under the hood, a universal app is really two separate apps. In this blog series we've used two techniques for sharing code between the two apps. We've been able to share most of our code, XAML and assets by putting them inside a PortableClassLibrary. And we've used Inversion Of Control (IOC) to let the PCL call into platform-specific APIs.
Good luck, as you go out and build your own VB Universal Apps! It's an open app-store out there, ready for you to make your impact.
And stay tuned for tomorrow's blog post, with complete source code for the minimal "App1.vb" that we've been creating so far, and also complete source code for a fully-fledged universal VB game "Breakout Universal".