Showing posts with label Universal App. Show all posts
Showing posts with label Universal App. Show all posts

Thursday, May 29, 2014

Xamarin 3.0 and Xamarin.Forms - Getting Started

A while back I blogged about the possibility of Xamarin using something like XAML as a standard way to write UX because it isn't the platform specific syntax that's important; it's the platform specific look and behavior that's important.  Today Xamarin introduced Xamarin 3.0 and with it Xamarin.Forms that appears to do just that; we write in XAML and we get native controls out the other side.  The promise of Xamarin.Forms is that (for the most part) we need to know one UI syntax, XAML.

Please note, this does not mean that we want to make the same exact UI for Android, iOS and Windows Phone.  In fact that would produce a substandard user experience.  But to the extent possible, it's isn't the syntax that matters, only appearance and behavior.  Xamarin.Forms gives us a much greater possibility of sharing UI code across platforms than ever before while still maintaining a native experience.

For the most part I don't think we are going to be using Xamarin.Forms for a lot of applications that we would have considered using complex native UIs a few months ago because there are going to be some platform specific tweaks that are still going to demand a native design experience.  But that's OK because in such an application you can mix Xamarin.Forms for the more generic native experiences in the application with native forms where we need to do something very platform specific.

So where does that leave Xamarin.Forms?  Its sweet spot would seem to be when we may have considered using a hybrid tool like PhoneGap or Appcellerator for cross platform development.  Because Xamarin.Forms still produces a native UI it will produce a much better native experience for the user while giving us all the cross platform UI code sharing that we would get from these tools.  It would seem to be a far superior choice and extremely compelling.

I wanted to try this out.  Xamarin has an introduction that I found useful here:
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/introduction-to-xamarin-forms/

It is day two of playing around with this for me and let me tell you Xamarin.Forms seems vast, very vast.  There is a lot to learn here and I look forward to attending next weeks Xamarin University class on Xamarin.Forms.  It is going to take a bit of time to really learn how to use it well.  For my first project I wanted to use actual XAML files and also use the new Universal Application Shared Projects.  For many reasons I believe this will be a better approach for most cross platform projects than using a PCL.

Here's what I did:

Step 1: Install Xamarin 3.0.  Just use the normal update process, no magic here.

Step 2: Create a new solution with projects for the platform specific UIs we want to support.  For my solution I selected an Android Application and an iOS empty Universal Application.




Step 3: Add a Xamarin.Forms project.  A Xamarin.Forms project is a project that provides shared code to the Android and iOS projects we just created.  This can be accomplished by using a portable class library or the new universal shared application.  Unfortunately in Visual Studio there are only three templates currently available under the Mobile Apps section.  One is used to create a multi-project solution with shared code through a portable class library, one to create a multi-project solution using a universal application shared project and one to create a new Xamarin.Form portable class library on it's own.  There is currently no template to create a Universal Application Shared Xamarin.Forms project on its own.  Luckily this is possible using the Universal Application Extension.  With this extension I created a new Universal Application Shared Project for my Xamain.Forms that I want to share with both projects and then put my Xamarin.Forms code in there.


Step 4: Add a reference to the Xamarin.Forms project to our iOS and Android projects.  This can be done by right clicking on references and selecting Add Nuget Package.  Search for the Xamarin.Forms project and add it.  Also add a Shared Project Reference for the new Universal Application Shared Project in the iOS and Android projects.


Step 5: Add a new Forms XAML Page to the Shared Project we created.  I called mine SharedForm.xaml.


Note: When I try to open the XAML file I get a designer error but I am still able to edit the XAML directly. From the Xamain.Forms forum on the Xamarin site it looks like there is currently no visual designer for this.  It was strongly hinted that one is in the works however.  I added a label and a button to make a very simple form that I called SharedForm.xaml.  The following is the code in my XAML file:


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="XamarinFormsTest.Shared.SharedForm">
    <StackLayout Spacing="10">
        <Label Text="Foo" VerticalOptions="Center" HorizontalOptions="Center" />
        <Button Text="Bar" x:Name="btnBar" />
    </StackLayout>
</ContentPage>

Step 6: I want to show a popup window of some sort when they click on my new "bar" button.  It wouldn't surprise me to learn there is some sort of cross platform library for this in Xamarin.Forms but I don't know what it is.  Instead I used a Toast for Android and a UIAlertView for iOS.  This is where using a Universal Application Shared Project really shines.  Using the a conditional compilation symbol of __Android__ in the Android project and __IOS__ in the iOS project I was able to do the following:


   1:  public partial class SharedForm : ContentPage
   2:  {
   3:      public SharedForm ()
   4:      {
   5:          InitializeComponent();
   6:          btnBar.Clicked += btnBar_Click;
   7:      }
   8:   
   9:      private void btnBar_Click(object sender, EventArgs e)
  10:      {
  11:  #if __ANDROID__
  12:          Android.Widget.Toast.MakeText(Android.App.Application.Context, "Test 123", Android.Widget.ToastLength.Short).Show();
  13:  #elif __IOS__
  14:          new MonoTouch.UIKit.UIAlertView("Test", "Test 123", null, "Ok", null).Show();
  15:  #endif
  16:      }
  17:  }
  
First I made the SharedForm partial class inherit from ContentPage.  This shouldn't be necessary because the generated version of SharedForm also inherits from ContentPage but there seems to be some bug in the Universal Shared Projects where this wasn't recognized in the Visual Studio designer.  It was just easier to add it.

I also tied the click event of the button to a new method, btnBar_Click.  If we are compiled into the Android application the Toast message is used in the method, otherwise the UIAlertView is used for iOS.

Step 7: I went into the android project's main activity and changed it so it inherits from AndroidActivity instead of Activity.  I also made a call to Forms.Init() and created a new instance of my SharedFrom.  A quick call to SetPage and my XAML form is used.


   1:  [Activity(Label = "XamarinFormsTest", MainLauncher = true, Icon = "@drawable/icon")]
   2:  public class MainActivity : AndroidActivity
   3:  {
   4:      protected override void OnCreate(Bundle bundle)
   5:      {
   6:          base.OnCreate(bundle);
   7:  
   8:          Xamarin.Forms.Forms.Init(this, bundle);
   9:   
  10:          var form = new SharedForm();
  11:          SetPage(form);
  12:      }
  13:  }

When I run the application and click on the "Bar" button this is what I see:


Step 8:  I want to try the same thing for iOS.  So I go to the iOS project's AppDelegate.  In the FinishedLaunching event I again call Forms.Init() and then create an instance of my XAML form.  On the form there is a CreateViewController() method that I call to set the window's RootViewController.


   1:  public override bool FinishedLaunching(UIApplication app, NSDictionary options)
   2:  {
   3:      // create a new window instance based on the screen size
   4:      window = new UIWindow(UIScreen.MainScreen.Bounds);
   5:   
   6:      // If you have defined a view, add it here:
   7:      // window.RootViewController  = navigationController;
   8:      Forms.Init();
   9:   
  10:      var form = new SharedForm();
  11:      window.RootViewController = form.CreateViewController();
  12:   
  13:      window.MakeKeyAndVisible();
  14:   
  15:      return true;
  16:  }

I then run the project on the iOS simulator, click on the "Bar" button and this is what I see there:



Similar but different.  I used the same UI syntax for a button and in one case I got an android button and here I got an iOS 7 style button, nice and flat.  Granted this was a simple example and it looks like my label got a bit mixed up with text at the top of the iOS simulator.  There is clearly more experimentation and learning I need to do.  But the idea seems to work.  Almost all of my code was shared and I was able to do it with little fuss or muss.

Very exciting and I'm ready to learn more.

Tuesday, May 6, 2014

Universal Application Extension - Working with Xamarin

One thing I mentioned in my blog post last month was how to use the new universal shared application concept in your Xamarin applications.  At the time (all of a month ago) the only way to do add them to our Xamarin projects was through directly editing the project files to add a reference to the universal shared project.  OK, not too difficult but still a bit of a PITA.  Now there is a new extension for Visual Studio 2013 Update 2 that makes this easy and it can be obtained here:

http://visualstudiogallery.msdn.microsoft.com/315c13a7-2787-4f57-bdf7-adae6ed54450

After installing the extension here is how to use it:

  • Have a new or existing solution with two different projects where you want to share code, such as a solution that contains an iOS project and an Android project.
  • Add a new project for code sharing, use the "Shared Project (Empty)" template:
           Note: even if you don't have a Windows 8.1 project in your solution, adding a universal shared project will require you to get a Windows 8.1 developer license, at least it did for me.
  • In the universal project add any shared modules, classes, constants, etc that you want.
  • In each of the platform specific projects under references right click and select the new "Add Shared Project Reference"


  • A list of all shared projects in the solution will be displayed, select the one you want:


That's all there is to it.  You can directly create empty shared universal projects and then through the Visual Studio UI add references to them to platform specific projects.  No direct editing of the projects required.  It would be nice if adding the Universal shared project didn't require a Windows 8.1 developer license if you don't have a Windows 8.1 platform specific project in your solution, but that's a minor nit.

Thursday, April 10, 2014

Universal Apps: What Are They And Can I Use Them With Xamarin?

At Build this year the new Universal App type was announced that allows you to write apps on for both the Windows Store and Windows Phone 8.1 platforms with one code base.  There were also hints that this would be supported in Xamarin as well.  Exactly how these work was a little unclear to me so I downloaded the Visual Studio 2013 update 2 RC and did some experimentation, at least what is possible in the release candidate.  The Visual Studio 2013 Update 2 RC can be found here:

http://www.microsoft.com/en-us/download/details.aspx?id=42307

I opened up the new project window and with a little searching around this is what I found:



There are four new project types:

  • Blank App (Universal App) - Very simple solution to create two projects (Windows Store and Windows Phone 8.1) and one shared universal project with a nifty new icon
  • Hub App (Universal App) - Slightly more complex than the Blank app, it still creates a Windows Store and Windows Phone 8.1 projects both using the same shared project
  • Class Library (Portable for Universal Apps) - Creates a project to create a Portable Class Library (DLL) in the profile that supports Windows Store 8.1 and Windows Phone 8.1 applications.  Currently there are no profiles that support Windows Phone 8.1 and Xamarin so I was not able to make one of these that also supports Xamarin but I suspect this will be updated soon enough.  This project type is intended to create libraries that can be shared outside the solution.
  • Windows Runtime Component (Portable for Universal App) - Similar to the Class Library type except compiles into a winmd file instead of a dll.

Blank App (Universal App) - This creates a new universal app solution with three projects, One for a Windows Phone 8.1 UI, one with a Windows Store Application and one shared universal application which would seem to be where the interesting bits are.


The new shared app type just shows up with an xaml file and is referenced by both the Windows Store application and the Windows Phone 8.1 application.  This is a project type unlike what you may be used to, in fact it appears to be only a repository for shared code that can be used by other projects in the solution.  Here are some things that are of interest:

  • If you right click on the shared universal project and select properties all you can change is the root namespace.  That's it.
  • When compiled no DLL is generated for this project, all code in it is compiled directly into the Windows Store and Windows Phone 8.1 applications.  These projects cannot be independently be shared or used outside of the projects that directly reference them in a solution.
  • You cannot compile only the Shared project on the build menu, it cannot be built independently.  This makes sense give that it has no output and is compiled directly into a referencing project.
  • As of the time of the writing there is no references nor ability to add references to the shared project through the Visual Studio UI.  What is available to you within code of these projects is the subset of the .NET framework for this project and that's it.  That means no referencing Autofac or any third party library in code through the Visual Studio UI. 
  • EDIT TO PREVIOUS VERSION - The shared project *WILL* pickup references in the projects that reference them.  You have to select the proper project in the upper left dropdown when editing a file in the shared project and it will pickup the proper references.

Here is a screenshot of the project selection dropdown where you can select the right platform specific project and get the proper references and conditional compilation symbols:


I wasn't satisfied with the last point as it would be extremely limiting so I decided to do some experimentation.  I went out to Nuget and added the latest stable version of Windows Azure Mobile Services to the Windows Store and Windows Phone 8.1 projects.  I then opened up the Windows Store project file in Notepad and copied the following code to the shared project file from the Windows Store project file:

  <Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\..

\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
    <Error Condition="!Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This 

project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more 

information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
    <Error Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build 

restored NuGet packages. Build the project again to include these packages in the build. For more information, see 

http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
  </Target>

When I refreshed the shared project I still had no references section visible in the project on the Visual Studio UI.  However, I then created a new class in the Shared project with the following code:

using Microsoft.WindowsAzure.MobileServices;

namespace App1
{
    class ReferenceTest
    {
        private MobileServiceClient Test1()
        {
            return new MobileServiceClient("");
        }
    }
}

Granted this code is rather useless but Visual Studio now recognized that Microsoft.WindowsAzure.MobileServices is valid in the shared project.  I was able to compile both projects using the shared project just fine.  So there may not be support in the Visual Studio UI for this at the present time but it does appear possible to reference other assemblies in your shared project.  Of course when I removed the Windows Azure Mobile Services reference from my Windows Phone 8.1 project, it no longer compiled though the Windows Store project continued to compile so any references added to the shared project also need to be added to any project that reference it, which makes perfect sense.

How about Xamarin?  As I stated before I couldn't create a Portable Class Library for Universal Apps that also referenced either Xamarin iOS or Android as there did not seem to be a profile for that combination.  What about the shared project?  I went ahead and added Xamarin iOS and a Xamarin Android UI projects to the solution.  I then went to the references section of the Android project and tried to add a reference to App1.Shared like there was in the Windows Store and Windows Phone 8.1 projects.  No luck, that wasn't an option when looking at the solution nor could I browse out to a DLL because one does not exist.



I did, however, find the following blog post that states how to modify the project file:

https://medium.com/p/141c2b7bae4f

I took the advice and added the following code to my Android project file in Notepad (As noted in the blog, be careful about the path being correct or your project will not load):

<Import Project="..\App1\App1.Shared\App1.Shared.projitems" Label="Shared" />

When I then reloaded the Android project as the blog post indicated I suddenly has a reference to the shared universal app project.


When I tried to compile I couldn't for two reasons.  First the default Blank App added a Xaml file to the shared app, App.xaml. Currently xaml isn't going to be usable by the Android or iOS projects and so can't exist in App1.Shared.  I moved this to the individual Windows Store and Windows Phone 8.1 applications (I could also have used pre-compilation directives so it wouldn't be visible to the Android project to the same effect). 

The second reason is because the shared project uses the Windows Azure Mobile Services component and my Android project does not reference it.  I added this and the problem was resolved (Note: sometimes when getting the Windows Azure Mobile Services package for Xamarin from Nuget it drags along some extra system DLLs that I have to delete: System.IO, System.Runtime and System.Threading.Tasks).

With these issues resolved I am able to use the shared project in Xamarin Android.  By following the same steps I am able to do it with the Xamarin iOS project as well.

In conclusion, what have I learned about the present state of Universal Apps and Xamarin?

  • Universal PCLs and winmd projects won't work with Xamarin at the present time because there is no profile that supports Windows Phone 8.1 and Xamain project types.  I expect that to be resolved.
  • Creating a Universal Blank App or Hub app creates a shared project type
    • The shared project cannot be created directly through the Visual Studio UI and instead must be created through one of those two project types
    • Code in the shared project does not create a DLL or winmd file but instead is compiled directly into the projects that reference the project
    • There is no way through the Visual Studio UI to add a reference to an external dll to a shared universal project but references can still be added by editing the project file directly
    • You do not need references in the shared project because it picks up references form the projects that use it.  When in a code file you can switch between projects to pick up their references and conditional compilation constants
    • All projects that reference the shared universal project must reference and be able to use any code in the shared project or measures such as pre-compilation directives must be used
    • Xamarin iOS and Android UI projects can use the shared project but only if their project files are edited directly as there is not currently any way to do it through the Visual Studio UI

In general the shared universal projects would seem to be a new alternative to the old method of simple linking a shared code file between two or more different projects.  As is common with that method platform specific differences can be handled via pre-compilation directives.  Any sharing of the UX may work on projects that use xaml but of course such code is not currently workable in Xamarin Android and Xamain iOS and would have to be hidden from those project types.

UPDATE: If you want to create a PCL today that targets Windows Phone 8.1 and Xamarin Android and/or Xamarin iOS @danrigby has a great blog post that explains how to do it until an update is released:

http://danrigby.com/2014/04/10/windowsphone81-pcl-xamarin-fix/