Petal

Creating a Kentico Cloud-powered Xamarin App—Part 1

As a Headless CMS, Kentico Cloud is all about delivering content to any channel. Whether it’s web, mobile, smartwatch, or carrier pigeon, companies need to edit their information in a single location and have it accessible to all their applications. In this article, I’ll show you how to leverage Kentico Cloud’s new Xamarin support to build a cross-platform mobile app using KC-hosted content.

Avatar fallback - no photo

Bryan SoltisPublished on Jul 26, 2017

Everyone loves their phone. Their make/model/design is of course the best, and all others are just a waste of time and technology. People have sculpted their lives around these devices and for many, it’s their primary channel for all things digital.

While phones are nothing new (yeah, this little beauty was my first phone), how they consume and display content is always evolving. For years, companies have focused on creating applications for each major OS to give people an immersive experience on their devices. With Xamarin, that process is a bit easier because it enables developers to create a single codebase for all platforms. 

Now let’s think about content. In the past, companies would A. Create content for each app, B. Develop complex APIs/systems to deliver centrally-based content, or C. Just load a web page within the app (lame). While these solutions do deliver information to mobile users, they either require a lot of work and/or are just a workaround. Luckily, the Headless CMS model is perfectly matched for this scenario!

In this article, I’m going to show you how I built a cross-platform app, leveraging Kentico Cloud content. By using the Delivery API, the amount of coding was greatly reduced and the development experience was pretty enjoyable. There are few different steps to the process, so I’ve decided to break the post up into 2 parts. In the first article, I’ll explain how I created the initial project and set up my architecture. Then, in Part 2, I show you how I leveraged the Kentico Cloud Delivery API and a little XAML to build my app. While there is a lot of code samples, don’t worry! In Part 2, there will be link to a GitHub project containing the full source code.

Let’s get to it!

Start with Kentico Cloud Content

The first step of the process was to create my content. In my case, I wanted to make a news reader app (exciting, I know) so I opted to use the KenticoCloud.com blog articles. Because we have several articles already published, I knew I would be able to use their structure within my app quickly.

Kontent.ai

Setting up my environment

Before you can embark on any Xamarin development, you have to install the tools. For me, this included Visual Studio 2017 and the Xamarin SDKs. In the Visual Studio Installer, you will want to select Mobile & Gaming / Mobile Developer with .NET. This will install all the necessary SDKs and emulators for your environment.

Kontent.ai



Technically, you could develop an app in Xamarin Studio or Visual Studio for Mac. The main point is you need to make sure you have all the right components installed. You can read more about the Xamarin requirements here.

Creating the Xamarin Project

Next, I created my Xamarin project. While I could have opted for a Blank / Sample Xamarin template, I decided to make use of the new Kentico Xamarin Demo project on NuGet. This project is pre-configured to use .NET Standard 1.4, a pre-requisite for using the Kentico Cloud API with Xamarin. This project contains the basic functionality needed to retrieve and display Kentico Cloud content. This includes references to the KenticoCloud.Delivery API, as well as Xamarin.Forms.

Kontent.ai


You can learn more about the Kentico Xamarin Sample Project here.

NOTE
The Kentico Xamarin demo project is a Portable Class Library (PCL). When developing, there are a few options when it comes to architecting your application. Be sure to choose the right option for your organization.

You can learn more about code sharing strategies here.

Creating a service

With the demo project configured and running, I decided to add some additional functionality. First, I added a new service to handle my Kentico Cloud client creation and calls.

        private DeliveryClient client;
        private static string strKenticoCloudProjectID = "XXXXXXXXXXXXXXXX"; // Update to your Kentico Cloud Project ID
        public KenticoCloudService()
        {
            client = new DeliveryClient(strKenticoCloudProjectID);
            client.InlineContentItemsProcessor.RegisterTypeResolver(new HostedVideoResolver());
        }


I then created an interface to implement the service.

    public interface IKenticoCloudService
    {
...
    }

Creating Models

After creating the service, I created my model for the BlogPost content. I leveraged the Kentico Cloud .NET Code Generator to create the models, removing any fields I know I wouldn’t be using.

    public partial class BlogPost
    {
        public const string Codename = "blog_post";
        public const string TitleCodename = "title";
        public const string PerexCodename = "perex";
        public const string DateCodename = "date";
        public const string AuthorCodename = "author";
        public const string HeaderImageCodename = "header_image";
        public const string TopicCodename = "topic";
        public const string UrlSlugCodename = "url_slug";

        public string Title { get; set; }
        public DateTime? Date { get; set; }
        public IEnumerable<Author> Author { get; set; }
        public IEnumerable<Asset> HeaderImage { get; set; }
        public string UrlSlug { get; set; }
        public ContentItemSystemAttributes System { get; set; }
        public IEnumerable<MultipleChoiceOption> Topic { get; set; }
        public string Perex { get; set; }
    }


I also copied the Author class to my project to be able to extract the full Author name.

    public partial class Author
    {
        public const string Codename = "author";
        public const string NameCodename = "name";

        public string Name { get; set; }
        public ContentItemSystemAttributes System { get; set; }
    }


Lastly, I created a BlogPost partial class, to handle code to extract values from modular content.

    public partial class BlogPost
    {
        public string ImageUrl => HeaderImage.FirstOrDefault().Url;
        public string AuthorName => Author.FirstOrDefault().System.Name;
        public string AuthorInternalName => Author.FirstOrDefault().System.Codename;
        public string PerexText => Regex.Replace(Perex.ToString().Replace("&nbsp;",""), "<.*?>", String.Empty);
        public string TopicName => Topic.FirstOrDefault()?.Name ?? "General";
    }

Retrieving the content

With my models in place, I was ready to add the functionality to retrieve the content. In my service, I created a GetBlogPosts function to return the last 10 blogs posts.

        public async Task<List<BlogPost>> GetBlogPosts()
        {
            List<BlogPost> lstBlogPosts = new List<BlogPost>();

            try
            {
                var response = await client.GetItemsAsync<BlogPost>(
                    new EqualsFilter("system.type", BlogPost.Codename),
                    new ElementsParameter(BlogPost.TitleCodename, BlogPost.DateCodename, BlogPost.AuthorCodename, BlogPost.UrlSlugCodename, BlogPost.HeaderImageCodename, BlogPost.TopicCodename, BlogPost.PerexCodename),
                    new LimitParameter(10),
                    new OrderParameter("elements." + BlogPost.DateCodename, SortOrder.Descending)
                );

                foreach(BlogPost blog in response.Items)
                {
                    lstBlogPosts.Add(blog);
                }
            }
            catch (Exception)
            {
            }
            return lstBlogPosts;
        }


Note that I am using several filters to return the specific articles I want. Also, the generated class for the content types include a “XXXcodename” string for the field. I decided to use this in my API calls, to keep this as clean as possible.

I then added another function to return articles for a specific author. This would be used in my application to view other posts by the author.

        public async Task<List<BlogPost>> GetAuthorBlogPosts(string strAuthor)
        {
            List<BlogPost> lstBlogPosts = new List<BlogPost>();

            try
            {
                var response = await client.GetItemsAsync<BlogPost>(
                    new EqualsFilter("system.type", BlogPost.Codename),
                    new ElementsParameter(BlogPost.TitleCodename, BlogPost.DateCodename, BlogPost.AuthorCodename, BlogPost.UrlSlugCodename, BlogPost.HeaderImageCodename, BlogPost.TopicCodename, BlogPost.PerexCodename),
                    new ContainsFilter("elements." + BlogPost.AuthorCodename, strAuthor),
                    new OrderParameter("elements." + BlogPost.DateCodename, SortOrder.Descending)
                );

                foreach (BlogPost blog in response.Items)
                {
                    lstBlogPosts.Add(blog);
                }
            }
            catch (Exception)
            {
            }
            return lstBlogPosts;
        }


I then updated my interface with the new functions.

    public interface IKenticoCloudService
    {
        Task<List<BlogPost>> GetBlogPosts();

        Task<List<BlogPost>> GetAuthorBlogPosts(string strAuthor);
    }

Creating the ViewModels

In my application, I wanted to have a BlogPostsPage and a BlogPostDetailPage. By having a different view model for each page, I could separate the functionality and have a nice foundation to build on. For my ViewModels classes, I created an instance of the service in the constructor. This allowed me to always have the service available on the page using the ViewModel.

    public class BlogPostsViewModel
    {
        public BlogPostsViewModel(IKenticoCloudService kenticocloudService)
        {
            _kenticocloudService = kenticocloudService;
        }
        private readonly IKenticoCloudService _kenticocloudService;

        public async Task<List<BlogPost>> GetBlogPosts()
        {
            var blogposts = await _kenticocloudService.GetBlogPosts();
            return blogposts;
        }
    }

    public class BlogPostDetailViewModel : BaseViewModel
    {
        public BlogPost BlogPost { get; set; }
       
        public BlogPostDetailViewModel(BlogPost blogpost = null)
        {
            Title = blogpost.Title;
            BlogPost = blogpost;
        }
    }


With the Service, Models, and ViewModel classes created, I was ready to designing my UI.

Moving Forward

Whew, that was a lot of code! Like I said in my intro, I’ve decided to break this article up into 2 parts. In Part 2 of this series, I’ll show you how I retrieve content within my layout to create a cross-platform application.

Check out Part 2 here!

Avatar fallback - no photo
Written by

Bryan Soltis