Don’t do this

Don’t do this.  It’s a bad idea.  Best to use resource files to localize your app, and ship a single build of your app to all marketplaces.

Except

Except … We recently submitted an update of an app to the Microsoft Marketplace and checked “all markets”.  The submission was rejected by Microsoft because one of the pages in the app uses Bing Maps.  It turns out you are not supposed to use the Bing Map control within apps that are available from the Chinese marketplace (see 3.10 here).

The simple solution would be to remove the page that uses Bing Maps, and resubmit the app.  The obvious downside to doing this is that all those users that already use the app outside of China will suddenly discover that the page is missing.  Why make everyone suffer?

So the next solution is to build two separate versions of the app, one for China and one for the rest of the world.  The question is, how to do this in the most efficient way.  That is what this blog post is about.

This isn’t necessarily the solution, it is just the solution I came up with.  Please comment if you have better or different ideas.

I wanted to be able to build the app for the different markets just by specifying different build parameters.  The trick is that I suspect that Microsoft uses automatic testing to determine whether the Bing Maps control is used in the app, so it isn’t enough to just hide access to the page.  Instead I didn’t want to include the page at all in the China build.

The build process

I build the app using the command line like this:

devenv /rebuild release MyApp.sln


After making the changes described below, in order to create the build for the rest of the world I do:

set Market=World
devenv /rebuild release MyApp.sln


To do a China-specific build I do:

set Market=China
devenv /rebuild release MyApp.sln

 

Updating the project (csproj)

To make the changes I right-clicked on the project within Visual Studio, selected Unload Project, and right-clicked again, and selected Edit.

The first thing I wanted to do was to only include the Bing Maps control if I was not doing a China build. I did this by scrolling down to the ItemGroup used for adding references, and adding a condition on the Market environment variable set above, to the inclusion of that control:

  <ItemGroup>
    <Reference Include="Microsoft.Phone.Controls.Maps, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e" 
               Condition="'$(Market)' != 'China'" />
    <Reference Include="GalaSoft.MvvmLight.Extras.WP71, Version=3.0.0.32981, Culture=neutral, processorArchitecture=MSIL" />
    <Reference Include="GalaSoft.MvvmLight.WP71, Version=3.0.0.32981, Culture=neutral, processorArchitecture=MSIL" />
    <Reference Include="Microsoft.Expression.Interactions, Version=3.8.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
    <Reference Include="Microsoft.Phone" />


I did a similar thing in the ItemGroup that built the MapView page:

<Compile Include="Views\MapView.xaml.cs" Condition="'$(Market)' != 'China'">
      <DependentUpon>MapView.xaml</DependentUpon>
    </Compile>


and

 <Page Include="Views\MapView.xaml" Condition="'$(Market)' != 'China'">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>

I also needed a pre-processor symbol defined so that I could conditionalize the inclusion of the menu item to navigate to the map page, so I added this towards the top of the project file.</p>

  <PropertyGroup Condition="'$(Market)'=='China'">
    <DefineConstants>$(DefineConstants);ChinaMarketBuild</DefineConstants>
  </PropertyGroup>

 

Updating the code

Once I was finished making these changes, I reloaded the project file (again by right-clicking on it in the Solution Explorer), and changed the code that added the menu item:</p>

#if !ChinaMarketBuild
            menuItem = new ApplicationBarMenuItem(AppResources.map);
            menuItem.Click += ShowMap;
            _mainApplicationBar.MenuItems.Add(menuItem);
#endif

Updating the manifest

I’m not quite done.  Each Windows Phone app has a unique ProductID associated with it, as defined in the WMAppManifest.xml file (under Properties in the Solution Explorer tree). 

You can’t submit two apps with the same ID to the Marketplace.  The (somewhat hacky) solution I came up with was to have a second “shadow” WMAppManifest.xml file called ChinaWMAppManifest.txt in the project, and as part of the build process I copy that file over the WMAppManifest.xml file when I do the China build.  I do the same thing for the AssemblyInfo.cs file, since that also has a unique Guid in it.

In summary

So there it is – I can now build the app to target China and exclude Bing Maps by using Conditions within the project file and by using a different WMAppManifest.xml, using three extra lines in the build.

I’ll let you know if there are any additional problems once the China-specific build has been submitted, but please do comment if you have a simpler way of doing this, or if you see any flaws in this approach.