Programmatically working with Device Channels

There are several questions about how to create and assign device channels programmatically.  I just attempted to do the same and found the following:

  • You can create a Device Channel using code and Windows PowerShell as they are stored in a list
  • Creating a master page to device channel mapping is not technically available via object model or Windows PowerShell (at least via the APIs that they have provided you)

To create a device channel, you can do this:

using (SPSite site = new SPSite("http://intranet.contoso.com"))
            using (SPWeb web = site.RootWeb)
            {
                SPList list = web.Lists.TryGetList("Device Channels");

                SPListItem li = list.AddItem();
                li["Name"] = "Windows Phone";
                li["ContentType"] = "Device Channel";
                li["Active"] = true;
                //alias can contain no spaces
                li["Alias"] = "WindowsPhone";
                li["Description"] = "The windows phone mobile channel";
                li["Device Inclusion Rules"] = "Windows Phone";
                li.Update();               
            }

If you look at how the master page settings page is laid out, it shows you all the device channels and any master pages that are tied to them.  When you look at the code, you will find that the settings are converted into a MasterPageMappingsFile object (in the Microsoft.SharePoint.Publishing.Mobile namespace). It inherits from a base class called MappingsFile<T>, both of which are marked as internal and thus you cannot use them.  When you review how it builds the list of mappings, it does so using a file called __DeviceChannelMappings.aspx that is stored in the "/_catalogs/masterpage/__DeviceChannelMappings.aspx".  It looks like this:

<%@ Reference VirtualPath="~CustomMasterUrlForMapping0" %><%@ Reference VirtualPath="~CustomMasterUrlForMapping1" %><%@ Page Language="C#" Inherits="Microsoft.SharePoint.Publishing.Internal.WebControls.MappingsFileBasePage" %><html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"><%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<head>
<meta name="WebPartPageExpansion" content="full" />
<!–[if gte mso 9]>
<SharePoint:CTFieldRefs runat=server Prefix="mso:" FieldList="FileLeafRef"><xml>
 
<mso:CustomDocumentProperties>
<mso:ContentTypeId msdt:dt="string">0x010100FDA260FD09A244B183A666F2AE2475A6</mso:ContentTypeId>
</mso:CustomDocumentProperties>
</xml></SharePoint:CTFieldRefs><![endif]–>
</head><body><mappings>
  <mapping>
    <channelAlias>WindowsPhone</channelAlias>
    <masterUrl href="/_catalogs/masterpage/windowsphone.intranet.master" token="~sitecollection/_catalogs/masterpage/windowsphone.intranet.master" />
  </mapping>
  <defaultChannelMapping>
    <siteMasterUrl token="~sitecollection/_catalogs/masterpage/seattle.master" href="/_catalogs/masterpage/seattle.master" />
    <systemMasterUrl token="~sitecollection/_catalogs/masterpage/seattle.master" href="/_catalogs/masterpage/seattle.master" />
    <alternateCssUrl token="" href="" />
    <themedCssFolderUrl token="" href="" isthemeshared="false" />
  </defaultChannelMapping>
</mappings></body></html>

Now that you know where the values are stored, you can programmatically modify the file using XML tools by downloading the files, changing it and then uploading it.  It should be noted that the file format may change in the future and its most likely why they have locked it down from an object model code standpoint.

Enjoy!
Chris