Xamarin Android: network_security_config.xml for debug only - visual-studio

I have a Xamarin.Android project (as a part of a Xamarin.Forms project) where I use network-security-config.xml to allow traffic to/from a test server using http.
I wonder if there is a way to exclude this from release build.
I found out two approaches, but none of them seem to apply to my situation:
If I was using Android Studio, I could have two different files, in different folders, one for debug and one for release. I think this is not supported in Visual Studio/Xamarin.
There is a directive in network_security_config.xml, "", but I think it only applies to CA certificates.
Any clue?
Thank you!

In your Android project you can create your own Application class and extend the Android.App.Application class. This way you can enable/disable debugging of the app also.
The build will now that this is your manifest's Application node when you apply an ApplicationAttribute to it like so:
#if DEBUG
[Application(Debuggable = true, NetworkSecurityConfig = "#xml/network_security_config")]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Android.App.Application
{
}
Where network_security_config is your configuration file.

Related

Maui class library can't compile Android (No Android nameapace)

I'm trying to create a Maui class library that has platform dependent sections.
In the class library's platform section for Android I've added code for Android, but when I compile it tells me that it can't find the Android namespace. I've check the Nuget packages against the main program that does compile Android and there the same. I've unloaded both the main project and the class library and check the project code against each other and there almost identical. The only difference that I can find between the main project that does compile Android is that the class library has an extra net6.0 dependency.
I've created a ".NET MAUI Class Library (Preview)" in VS 2022 Preview 3. Indeed, something is wrong - especially with Intellisense. I did not find a way to suppress certain Intellisense errors, but I did succeed in getting it to build.
NOTE: I confirmed that most of the issues do not interfere with Building the project. Indeed, its possible that the problem is ONLY with Intellisense; I didn't rigorously determine whether Build always worked.
1) OPTIONAL: In .csproj, REMOVE .net6.0; from start of <TargetFrameworks>. BUT DON'T remove, if you are making a library that doesn't contain platform-specific code.
EXPLANATION: This only affects Intellisense; can Build without doing this.
Normally this is wanted in a .net6 class library, but until VS Intellisense correctly handles Maui Class Libraries, with their platform-specific code, this tends to cause extra Intellisense complaints. If you do (4) for all platform-specific files, you can probably leave .net6.0; in, without extra Intellisense errors.
2) Above any source file, is a dropdown that says YourLibName (net6.0-xxx). When working on Android code, pick YourLibName (net6.0-android).
EXPLANATION: This only affects Intellisense; can Build without doing this.
3) In your code, use global::Android instead of Android.
EXPLANATION: Intellisense seems to be confused about the context it is in. global:: ensures that it is looking for a "top-level" namespace.
4) In a class library, Intellisense isn't recognizing platform folders - wrap all code in appropriate #if ANDROID, #if IOS, etc.
EXPLANATION: This only affects Intellisense; can Build without doing this.
This removes errors for a class that is defined differently in multiple platforms; e.g class PlatformClass1.
5) using Android;, using Android.App, etc - do work (in platform-specific folder) when "Build" - even if Intellisense complains.
I had the same problem -- I was determined not to believe #ToolmakerSteve's response but I'm afraid he's correct. Especially #4 of his post about wrapping all platform specific content with
#if ANDROID
#endif
Also add it to your interfaces that reference platform specific namespaces.
Here's a link to a Microsoft page regarding this:
invoke platform specific code

iOS project doesn't reference a static library from Binding project when in Release mode

I've got a static library, which was used to generate the wrapping code by Sharpie. The library was Built after that (including, generated *.dll) successfully.
AppDefinition.cs contains the namespace and the mappings, like this:
namespace TheNamespace
{
// #interface TheParameters : NSObject
[BaseType(typeof(NSObject))]
interface TheParameters
{
The library itself built in Release mode with LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Arm64.
However, when referencing this binding project from my iOS project, it works only in Debug mode.
When I change it to Release, the namespace (and all the related clasees) not available. Also, when exploring the binding library reference in Object Browser, it doesn't display any elements: it's totally empty.
Just to point that: it gets available when changing it in the dropdown to Debug and disappears on Release, what's interesting, undependently on what actually project is selected in Current Project dropdown!
What might be the issue? Thanks!
I think the problem should come from when building static library .When generating static library , there is a build type of release/debug to select.
Above screenshot shows static library types after building , there are three types (Two is Debug and One is Release ). You can see that tt distinguishes between release and debug .
After some Googling I found the solution.
The issue happens because of Visual Studio bug, I guess. And also referred here. (And it's weird it's not mentioned in Xamarin docs on Microsoft website.
To resolve the issue the Binding Project(s) must not reside in the same solution with the main project. Just remove them and attach the library as regular reference.

Create a Xamarin.Forms library from a Xamarin.Android / Xamarin.IOS library

Maybe this is a very basic question but here it is :
I have 2 libraries :
1 Xamarin.Android library
1 Xamarin.iOS library
What's the simplest way to create a Xamarin.Forms library that wraps the native libraries and will call them when needed?
I assume you mean actual platform libraries and not apps.
If you do mean the apps:
You're thinking of the projects backwards. The X.Forms library doesn't reference or call the platform libraries (X.Android & X.iOS); the platform libraries call the Xamarin.Form library. Just make sure both platform implementations implements the same interface and code against that interface in the Xamarin.Forms project.
If you're creating something like a plugin or control to use in Xamarin.Forms then you need to jump through a few hoops. I would suggest following James Montemagno's pattern(s). (He's a PM for Xamarin that makes a ton of nugets)
Use the old Visual Studio Extension that will stub out the projects for you. Unfortunately it uses PCLs.
Use the pattern he uses for Xamarin.Essentials. It uses fancy build conditions and only has one project.
If you want to hand roll a reusable control/nuget it yourself, you will need an abstraction to code against in your Xamarin.Forms library and some form of Dependency Injection to get to the native implementation.
Here is a good blog post about PCL bait and switch (which is what happens with the nugets)
tl;dr
You will need dependency injection. If aren't already using it, use the DependencyService that comes with Xamarin.Forms.
Assuming both the libraries do the same thing: you can use the strategy pattern to expose those libraries to X.Forms:
1.) In your X.Forms project, create a common Interface that exposes the methods you want to call in the libraries:
public interface ICommonService
{
void DoSomething();
void DoSomethingElse();
}
2.) In both of your platform projects, provide a concrete implementation of this interface:
public class CommonService : ICommonService
{
public void DoSomething(){...}
public void DoSomethingElse(){...}
}
Because the concrete implementation are in your platform projects, they have access to the Xamarin.Android and Xamarin.iOS libraries you want to leverage.
3.) Use dependency injection to create an instance of the service in your X.Forms project. One way is to use the DependencyService in your X.Forms project:
DependencyService.Get<ICommonService>().DoSomething();
Depending on if you are running the iOS or Android app, this will call the provided concrete implementation.
Note: If you plan on using DependencyService, you will need to register your concrete implementations first.
The following documentation has a very nice walkthrough of how to use the Xamarin.Forms DependencyService to achieve the strategy pattern:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction

MvvmCross with two core libraries

Is it possible to link two Core libraries into your app?
I would like to create one Common.Core library that has login and account view models.
I would like another one Domain.Core library that has some domain view models in it.
These could be used across a couple different projects.
In my app, I do a new Setup().Initialize().
My Setup class overrides CreateApp() ...
public class Setup : MvxPhoneSetup
{
protected override IMvxApplication CreateApp()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
return new Common.Core.App();
// TODO: can I setup a Domain.Core library here too?
}
}
I have tried doing this ...
CreatableTypes(Assembly.Load("Domain.Core")).EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
but I'm getting a ReflectionTypeLoadException when I try to resolve a domain model from there.
Anyone tried something like this?
Thanks!
Yes, using multiple 'core' projects should work.
The ReflectionTypeLoadException occurring on Resolve suggests that maybe your second Assembly requires another Assembly that isn't available? Do you get the same problem with a very simple second core project? Can you get any more information about the exception? Which platform is this occurring on?
If you want to load ViewModel types from multiple assemblies, then there is a Setup method you can override - The default ViewModelLocator in MvvmCross gets its list of ViewModels from the assemblies listed in Setup - see MvxSetup.cs
(Sorry this list is in the ui project - should really be in the main core project)
For cross-platform compatibility, I don't recommend using Assembly.Load - better to use a more static method like typeof(Domain.Core.Something).Assembly
Working on 'packaged application' platforms like xamarin.android and (especially) xamarin.ios I don't recommend using Assembly.Load - this will only work on the iOS platforms if the assembly is referenced statically and has already been loaded - that's the reason plugins have a special bootstrap file on iOS. Also be aware that the name used in Assembly.Load is different on different platforms - eg in Android you must use the filename ending in .dll - see MvxAndroidSetup.cs. For other platforms like WP and winRT, then Assembly.Load may work more conventionally though - although I've personally spent hours/days/weeks swearing at this sort of code in the last year.

MvvmCross vNext: Using System.IO.Compression in PCL

I have some Model code that requires some methods from the System.IO.Compression namespace. However it is not present when using a PCL that targets VSMonoTouch and MonoAndroid as well. I see that some stuff is TypeForwarded in the MvvmCross solution, though when creating a similar project I can't seem to find out how to use it.
I created a MonoAndroid library project and added a Forward.cs class with the following content:
using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(System.IO.Compression.CompressionMode))]
[assembly: TypeForwardedTo(typeof(System.IO.Compression.DeflateStream))]
[assembly: TypeForwardedTo(typeof(System.IO.Compression.GZipStream))]
I have set the namespace of the project to System.IO.Compression. Trying to add it as a reference to the PCL project I have with my Model code which contains ViewModels, Services and what not it of course says that it can only reference other PCL projects and assemblies.
I especially need GZipStream and I cannot seem to find out how to add it to my project, so the question is how do I do that?
PCL Extension route
How to do this by extending PCL... I'm not entirely sure! One of the PCL guys might be able to assist with that.
Plugin route
The way I'd go about this is by defining the functionality I want in an interface and wrapping the code in a plugin.
For example in Cheesebaron.Plugins.Gzip.dll you could create an interface like:
public interface IGZipStreamFactory
{
Stream Decompress(Stream binaryStream);
}
This interface would then get plugged inside a PCL library that just contained this interface and the pluginmanager class.
Your PCL Core project can then reference this PCL plugin library and your ViewModel can use code like:
Cheesebaron.Plugins.GZip.PluginLoader.Instance.EnsureLoaded();
followed by
var service = this.GetService<IGZipStreamFactory>();
var unzipped = service.Decompress(inputStream);
For each actual platform implementation, you then prepare a platform specific library, you implement the GZip factory interface, and you provide a simple Plugin class implementation.
For example, for Droid you might create Cheesebaron.Plugins.Gzip.Droid.dll:
public class MyDroidGZipStreamFactory : IGZipStreamFactory
{
// the implementation
}
And you'd then add:
public class Plugin
: IMvxPlugin
, IMvxServiceProducer
{
public void Load()
{
this.RegisterServiceInstance<IGZipStreamFactory>(new MyDroidGZipStreamFactory));
}
}
Finally... to pull it all together, for MonoDroid you then reference both the PCL and the platform specific implementation in your UI project - and it should all work!
Note that there is a little convention based magic going on behind the scenes here - the framework loads the Assembly Cheesebaron.Plugins.Gzip.Droid.dll based on the PCL Plugin namespace being Cheesebaron.Plugins.Gzip
(For WP7 and other platforms, there's one additional step - there's a setup method to override which registers the plugin)
Note you can register as many services as you want to inside a single PlugIn, and you can perform extra common initialization/setup code too. This can help to reduce some project maintenance overhead: you can put your CheeseBaron IoC objects inside one single CheeseBaron.Plugins.Utils project if you like and then share just this one plugin across all your apps.
The DownloadCache Plugin provides a small sample of this - it registers all of IMvxHttpFileDownloader, IMvxImageCache and IMvxLocalFileImageLoader.
The downside with doing this is: eventual linked exe size - you're potentially adding unneeded code to each app.
Obviously this plugin approach has a little bit of a learning curve... and it does add a little project maintenance - but the good news is that these plugins can be used over and over again between projects - and can be shared between organisations (at least, that's my hope!)
More on creating plugins at:
MvvmCross vnext: merge plugins with monodroid
http://slodge.blogspot.co.uk/2012/06/mvvm-mvvmcross-monodroid-monotouch-wp7.html
For examples of plugins (not all available on all platforms), see https://github.com/slodge/MvvmCross/tree/vnext/Cirrious/Plugins
Other routes
If you don't want to use Plugins - e.g. if you are ever in a hurry or if you are writing code for a module that you don't want to reuse, then there are alternatives:
You can define an interface like IGZipStreamFactory in your share Core PCL library. You can then provide a platform specific implementation of this interface within each UI project, and can then use normal IoC/DI in the ViewModel/Model/Service layer in order to locate the correct implementation at runtime.
Or...
You can just dump the shared PCL core library and create separate platform-specific DLLs into which you then manually link in platform-specific files (I try never to do this, but others like it)

Resources