compilationxamarin.formstargetsdynamic-compilation

How to target multiple customers with the same app (Xamarin Forms)?


=> Xamarin Forms

=> Using Xamarin Studio on Mac (but I have access to visual studio as well)


Imagine a generic login app with a Image (Customer Logo), Login (Entry control), Password (Entry Control) and a button to login.

I want to build this very same app to multiple customer (from 1 to 99). Each app will differ on:

I thought of using Resources (.resx) for doing it, or maybe some kind of compilation directives. But I'm not sure of how doing any of this properly.

Thank you in advance!


Solution

  • I am assuming you want to build different apk/ipa for different clients. If not please update your question.

    You can set up a build configuration for each client. In each configuration, define appropriate symbols. For example configurations "DebugClientA" and "ReleaseClientA" may have symbol CLIENT_A.

    Then in your code, first declare your properties/fields, including string literals, paths to images, colors, etc. Put the assignments elsewhere. I put them in a method call invoked by App() constructor.

    For the assignment, put them in #if and #elif blocks (MSDN doc). The code should look like this:

    #if CLIENT_A
      MyString = "ClientA";
      // Following is for ImageSource.FromResource()
      MyPathToImage = "MyAssembly.images.clienta.image.png";
      MyColor = Color.FromHex("012345");
    #elif CLIENT_B
      MyString = "ClientB";
      MyPathToImage = "MyAssembly.images.clientb.image.png";
      MyColor = Color.FromHex("6789AB");
    // repeat as needed
    #endif
    

    Your app should now have specific literals, images, and colors for each client.

    Customizing the app name comes the tricky part: Customized Android AndroidManifest.xml and iOS Info.plist. My way of doing involves some (IMO) nasty hacks. The method is the same for both platforms so I will write only the Android version.

    Edit the properties of Android project. Put placeholders into fields that you want to customize for each client, e.g. "AppNameCustomized" and "package.name.customized".

    Still in project properties, add a pre-build event to modify Properties/AndroidManifest.xml and save the output to Properties/AndroidManifest_ClientA.xml (without altering the original file). You want to modify it so that "AppNameCustomized" is replaced by the app name of Client A. Same for "package.name.customized" and the like. On Mac sed should do the trick. Repeat for other clients.

    Open Android project .csproj file using text editor (not from XS). After the last PropertyGroup and before the first ItemGroup, add the following PropertyGroup for each client:

    <PropertyGroup Condition=" '$(Configuration)' == 'DebugClientA' Or '$(Configuration)' == 'ReleaseClientA' ">
        <AndroidManifest>Properties/AndroidManifest_ClientA.xml</AndroidManifest>
    </PropertyGroup>
    

    For the app name and package name this basically boils down to: Generate a customized AndroidManifest for each client, which contains the desired app/package name. Then use the correct AndroidManifest according to build configuration.

    And you're done! Just test with DebugClientA and publish with ReleaseClientA.