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

=> 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:
Name (the app name and multiple Labels within the app),
Logo (Image controls in the app that access a image address on the web),
Connection String (this will be a const in the app),
The main color of the app.
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!

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.

I don't recommend this way of doing because when you will need to sign your iOS and it will not work because of the limitation of mtouch compiled.
I suggest to create a common project with all resources. And, by client, create needed projects.
I think that we can have an solution like this:
ProjectName.Common.Forms
ProjectName.Common.iOS
ProjectName.Common.Android
ProjectName.Client1.Forms
ProjectName.Client1.iOS
ProjectName.Client1.Android
ProjectName.Client2.Forms
ProjectNAme.Client2.iOS
ProjectName.Client2.Android.
You can have many solution by clients. Or one solution for all clients.
When you want to build you need to change project target. This way you will able to support different signing certificate for all your clients.

Related

How to add Windows Phone project with resx localization to Xamarin PCL solution?

I have a working PCL project for iOS and I'm trying to create the Windows Phone 8.1 version.
I'm following this tutorial: https://developer.xamarin.com/guides/xamarin-forms/advanced/localization/
And checking the app at: https://github.com/xamarin/xamarin-forms-samples/tree/master/UsingResxLocalization
But it is too deprecated. Even the git project is different from the tutorial, and none of them works.
The ILocalize interface for Windows should look like:
[assembly: Dependency(typeof(UsingResxLocalization.WinPhone.Localize))]
namespace UsingResxLocalization.WinPhone
{
public class Localize : UsingResxLocalization.ILocalize
{
public System.Globalization.CultureInfo GetCurrentCultureInfo ()
{
return System.Threading.Thread.CurrentThread.CurrentUICulture;
}
}
}
But System.Threading.Thread.CurrentThread.CurrentUICulture simply doesn't exist. I found out that I can use Windows.System.UserProfile.GlobalizationPreferences.Languages[0].ToString() instead.
It works for the localized language resources but the default Resource is not working either for the default language "en" or any other non localized language like "ru". I get another error:
In the TranslateExtention class ProvideValue() method I get:
Key 'Start' was not found in resources 'AppNameSpace.AppResources' for
culture 'en'
Being "Start" the first key it tries to get from the resource. It happens for all the other keys on the project.
AppNameSpace.AppResources would be the right file, and "en" is the region I set, so it should work. But it's not.
I'm also getting the following warning when compiling:
The assembly "MyApp.dll"
does not have a NeutralResourcesLanguageAttribute on it. To be used in
an app package, portable libraries must define a
NeutralResourcesLanguageAttribute on their main assembly (ie, the one
containing code, not a satellite assembly). 4>C:\Program Files
(x86)\MSBuild\Microsoft\VisualStudio\v14.0\AppxPackage\Microsoft.AppXPackage.Targets(1216,5):
warning APPX2002: Cannot find the neutral resource language for the
resources for portable library 'MyApp'. Verify that
the portable library defines a NeutralResourcesLanguageAttribute. The
build is continuing assuming the project's default culture of 'en-US'
correctly identifies the portable library's neutral resources.
4>MakePRI : warning 0xdef00522: Resources found for language(s) 'de,
es, fr, pt' but no resources found for default language(s): 'en-US'.
Change the default language or qualify resources with the default
language. http://go.microsoft.com/fwlink/?LinkId=231899
But I have no idea how to fix it.
On the tutorial it also says:
Windows Phone projects must be properly configured for localized text
to be displayed. Supported languages must be selected in the Project
Options and the WMAppManifest.xml files. If these settings are not
updated the localized RESX resources will not be loaded.
Fine, but those options doesn't exist anymore. At least where they should be. I even found a Package.appxmanifest file in my project, but it doesn't have those regional options.
So, I need help with an updated way to do it.
Thanks
So I found out that when you add a Windows Phone project to a solution with no Windows Phone projects, it doesn't add everything it needs.
Also the tutorials don't show everything that is necessary (no big news there).
All my project was missing was [assembly: NeutralResourcesLanguage("en-US")] in my PCL AssemblyInfo.cs file.
The RESX tutorial also says that you should use:
if (Device.OS == TargetPlatform.iOS || Device.OS == TargetPlatform.Android)
{
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
}
In the TranslateExtention.cs file because Windows Phones don't need it. Well, that's false. At least for the emulator to get the right language, it needs to use the DependencyService and get the CultureInfo this way:
System.Globalization.CultureInfo ci = null;
ci = new System.Globalization.CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0].ToString());
return ci;

Xamarin Forms - Access controls in Target application (iOS/Android)

I am using Xamarin.Forms, shared project template.
Here, I add controls to the content page such as a Label through say framework provided StackLayout.
Now in target apps - say for iOS/Andriod, I just need to set some text for this label. I have some platform specific code where I want to change the text value for the Label created in Shared Project.
How to do that?
I understand, Custom Renderers could be used. Is there any straight forward way that I am missing here?
You can, of course, use custom renderers... but imho it would be an overkill.
I'd use OnPlatform method - something like:
myLabel.Text = Device.OnPlatform<string>("text for iOS", "text for Android", "text for Windows Phone");
You can also do the same from XAML if you wish, like shown in this article (search "OnPlatform" there):
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/xaml-for-xamarin-forms/essential_xaml_syntax/
If the text you need is dynamic and you need to set it at run time from platform-specific project, than you need to assign your Label to some variable in the shared project and then reference this variable from platform projects.

Accessing resources XML from another library project in Xamarin.Android

I am trying to create a Xamarin.Android Component to send to the Xamarin Component Store, and I need to bundle my Colors.xml with it, so it is accessible to everyone using my component. I am setting the build action for the Colors.xml tp "AndroidResource".
So I created an Android sample application, when I add a reference to my library project's dll, I am able to use the colors defined, my project compiles and it runs, but I get no intellisense on Xamarin Studio. So that would be a bad thing for anyone using my library, as they would not be able to even see that the colors are available to use. You can see in this picture the colors defined are not available in the suggestions box.
If I add the Colors.xml directly into my project, I get Intellisense support, like this:
Is there a way to achieve the same result above when adding just the dll reference? Did I do something wrong or Xamarin.Android/Xamarin Studio doesn't support this kind of scenario?
EDIT: To be clear, I know this is a problem with Intellisense not being able to pick up the values, but is there anything I can do to make it work?

URL Scheme: what kind of string results

I'm using Marmalade to develop iOS applications via VisualStudio and a PC. The integration of a social feature like HeyZap needs its initialization by the use of:
loadHeyzap("YOUR_APP_ID_HERE","YOUR_APP_URL_HERE", true);
App_ID is the ID as defined in the itunes app page (I got it).
App_URL "should also similarly be replaced with your URL scheme for the iPhone" [from the HeyZap integration doc].
Well, the HeyZap help desk weren't useful to obtain this string via the use of VisualStudio+PC (in fact, they told me "use XCode+Mac instead...").
Since this is a simple string, I suppose I could obtain it starting from known parameters of my app. I suppose to find inside it something like [app_name]&=other-chars-....
Is there a way to build this string without the use of XCode, just starting from info I already have and putting here and there some special chars?
In other words, is there a standard way to automate the build of this string without the neeed to do it via XCode? I wonder to prepare a function in which I would pass my app parameters and I got the URL Scheme string as a result.
Cheers,
Zapp
The answer by Creator is incorrect. A URL schema is how apps can communicate with each other in iOS.
Here is what Apple has to say
http://developer.apple.com/library/ios/#featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007899
An example would be:
yourgame://
Here's how you would define one in XCode
When you define a URL schema in XCode, you can call that URL from Safari or any app installed on the device and it will switch to your game.
The way you define it in XCode is by going to your project settings, clicking the Info tab at the top, going to the bottom where it says "URL Types", expand that, and click the + button at the bottom. Then define both the identifier and the URL schemes with something reasonably unique like "yourgamename". Done!
http://i.stack.imgur.com/pxEKd.png
URL scheme is most probably the url of your app in App Store. You can obtain it from iTunesConnect. Go to your application and copy the url of View in App Store link. That's the string you wanted ;-)
Let me know if it doesn't work.
Edit:
Well App url worked for me, dunno why its not working for you. If you want to edit the URL scheme, you can do it without using XCode too. You need to include Info.plist file in the mkb settings. You can edit or check the current URL scheme being used by marmalade there. The default plist file is in the s3e folder. Don't know the exact location.

Best way to deploy and reference an XSLT file

In a visual studio project I have three layers, Data Layer, Business Layer and Presentation Layer.
In the Data Layer I have a few XSLT's that transform some objects into an email, all works fine but I have discovered that the XSLTs do not get built/copied when building.
I have currently, created a folder in the deploy location and placed the XSLT's there but I am concerned about relying on a manual process to update these.
Has anyone encountered a similar issue and if so how did they get around it.
It smacks of changing the MSBuild script to copy the build artifacts to the required location, does anyone have examples of this?
Thaks
If you are using Visual Studio 2005/2008, the easiest way to do this is by including your XSLT files as project resources.
Open the Properties for your project.
Select the Resources tab. You will probably see a link that says "This project does not contain a default resources file. Click here to create one." Go ahead and click on that.
Click the Add Resource drop-down near the top and select Add Existing File.
Browse to your XSLT files and select them.
After you have done this, you can easily access the resources in the following manner:
// To get the contents of the resource as a string:
string xslt = global::MyNamespace.Properties.Resources.MyXsltFile;
// To get a Stream containing the resource:
Stream xsltStream = global::MyNamespace.Properties.Resources.ResourceManager.GetStream("MyXsltFile");
If you are using Visual Studio 2003, your best bet is to include those XSLT files as embedded resources for the DLL. In Visual Studio, select the file(s) in Solution Explorer, open the Properties pane, and change the Build Type to "Embedded Resource". You can then use the GetManifestResourceStream method to get a Stream containing the XSLT(s). The name to pass will be based on the default namespace of your assembly, the folder containing the file, and the name of the file.
For example, say your data layer assembly has a default namespace of My.DataLayer. Within your data layer project you have a folder named Templates which contains a file called Transform.xslt. The code to get your XSLT would look like this:
// There are numerous ways to get a reference to the Assembly ... this way works
// when called from a class that is in your data layer. Have a look also at the
// static methods available on the Assembly class.
System.Reflection.Assembly assembly = (GetType()).Assembly;
System.IO.Stream xsltStream = assembly.GetManifestResourceStream("My.DataLayer.Templates.Transform.xslt");
For more information check out this article on CodeProject.
Obvious question maybe, but still has to be asked, did you include the folder containing the XSLT's in the project itself? Is this a web or forms app?
In VS, it is easy to set the properties of the XSLT files in the project to copy on build, by default they do not.
I may have explained myself poorly.
THe Data layer is a class library that a the presentation layer references.
On building the DataLayer I can get the XSLTs to output to the Bin directory of the DataLayer. However when I build and publish the presentation layer, it correctly grabs the DLL but not the XSLTs

Resources