I created a Xamarin.Forms project/library. The project/library contains pages, views, renderers and other shareable components.
I then created my main project that will reference the shared project. I added each project (shared, android, ios) as an existing solution project.
The problem is when I try to use ShareProject's custom renderer in my MainShareProject, the implementation in SharedProjectAndroid and SharedProjectiOS is not called. When I call ISomeService in MainShareProject via DependencyService it is null
Solution Structure:
Shared Project Structure (Purpose of SharedProject is to reuse it in other projects)
ShareProject (NET standard library)
custom renderer
ISomeService
SharedProjectAndroid (Reference ShareProject; Xamarin.Android library)
custom renderer implementation
ISomeServiceImpl
ShareProjectiOS (Reference ShareProject; Xamarin.iOS library)
custom renderer implementation
ISomeServiceImpl
Main Project Structure
MainShareProject (Reference ShareProject)
use custom renderer (calls custom renderer constructor in ShareProject but not its implementation
use ISomeService by DependencyService (returns null)
MainProjectAndroid (Reference ShareProject and ShareProjectAndroid)
MainProjectiOS (Reference ShareProject and ShareProjectAndroid)
var someService = DependencyService.Get<SharedProject.ISomeService>(); //returs null
Android
[assembly: Dependency(typeof(SharedProjectiAndroid.SomeService))]
{
public class UserPreference : ISomeService
}
I was fighting with the same problem that custom renderer from external assemblies are not called. I never investigated deeper, but it seems that it is somehow related to the code optimization.
For me the solution was to add an explicit call from my project to the external assembly.
Like this:
Assembly
public static class CoreUI
{
public static void Init() { }
}
Project
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
CoreUI.Init(); // Initialisation of CoreUI
}
Related
I have provided an aplication made in android that has a navigation drawer and in it has a list of games. I have to create another game and to put it there. The game that has to be created by my must use libGDX but the original application didn't use this library.
Is it possible to do this ? If Yes, how can I add the libgdx to the exiting project. On github I found only how to start a new project with libGDx, an not how to add it to exising code. thanks.
You can achieve this with these 2 steps:
1. Add LibGDX to your project
On your android gradle file: build.gradle (app or android module)
dependencies {
...
// Add this line, it is recommended to use the latest LibGDX version
api "com.badlogicgames.gdx:gdx-backend-android:1.9.10"
}
2. Initialize LibGDX for a view or use a LibGDX managed activity
Option 1: Initialize for a view
Since you have a navigation drawer and more code native to android this option fits your needs better. From this question (How to add LibGDX as a sub view in android):
The AndroidApplication class (which extends activity) has a method named initializeForView(ApplicationListener, AndroidApplicationConfiguration) that will return a View you can add to your layout.
-- Matsemann
Also here's documentation on how to implement this (Fragment based LibGDX).
Option 2: Use a managed activity
This is the default/most common use of LibGDX, you will need to change your code as follows:
Your activity needs to extend Android application:
public class MainActivity extends AndroidApplication {
Create a class extending Game or ApplicationAdapter:
import com.badlogic.gdx.Game;
public class LibGDXGame extends Game {
#Override
public void create() {
System.out.println("Success!");
}
}
Initialize the LibGDX managed activity:
import android.os.Bundle;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
public class MainActivity extends AndroidApplication {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(new LibGDXGame(), config);
}
}
Generally what you want is possible, I reckon your best bet would be to create a new libgdx project with their GUI and to then manually merge the files that are needed.
I want to use my custom renderer inside a PCL. Is it possible? Or can I initialize my custom renderer inside this PCL?
No and No.
What you use in PCL is - let's say - component and it's abstraction. The 'materialization' (or not) of the component will be made by custom renders on each platform.
I can't see a reason to use it on a platform-independent implementation once it can be shown (or to behaves) differently on each one.
Custom Renderers let developers override this process to customize the appearance and behavior of Xamarin.Forms controls on each platform.
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/
Maybe with a real case, we can suggest another solution.
Finally, I've found a solution.
I've just created a class in my PCL and used it in XAML, let's say:
public class MyHelperEntry : Entry { public MyHelperEntry() { } }
that inherits Entry class. And in an App, where I use this PCL, I've created a class, that inherits MyHelperEntry:
public CustomHelperEntry : MyHelperEntry { public CustomHelperEntry() { } }
and used this CustomHelperEntry as a custom renderer.
We have a Xamarin.iOS project that shares a code backend with a WPF project that has been going through a refactor. All the shared code libraries have been converted to be .net standard.
The Xamarin project builds, but the simulator throws an exception on startup as such :
Foundation.MonoTouchException has been thrown
Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Unable to instantiate the UIApplication delegate instance. No class named AppDelegate is loaded.
Just for testing purposes, I added an empty UIApplicationDelegate to Main.cs and I'll still get the exception (only now referring to TestDelegate).
Main.cs
using Foundation;
using UIKit;
namespace App.IOS
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args, null, nameof(AppDelegate));
}
}
}
Appdelegate.cs (very large file, so just the declarations here).
namespace App.IOS
{
public class MiniSetup
{
public static readonly MiniSetup Instance = new MiniSetup ();
public void EnsureInit()
{
//Setting up Binding and Dependency Injection Here.
}
}
[Register (nameof(AppDelegate))]
public partial class AppDelegate : UIApplicationDelegate
{
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
//Invoke Minisetup here
}
public override void WillEnterForeground (UIApplication application)
{
//snip
}
public override void DidEnterBackground (UIApplication
application)
{
//snip
}
// snip other code for setting UI controls and other app logic.
}
It seems apparent that I've goofed up the project in some way, but I haven't found any leads as to where to look for a solution. Any ideas on how to troubleshoot this?
Two classed needed, the UIApplicationDelegate subclass and the class that defines the Main entry point that calls UIApplication.Main will the Xamarin.iOS registered name that you used on the UIApplicationDelegate subclass.
Basic/Minimum UIApplicationDelegate:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window
{
get;
set;
}
}
Basic/Minimum Main entry point:
public class Application
{
static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
}
}
I don't have a smoking gun here, but near as I was able to figure out, an incompatible (with xamarin) reference or nuget package was added to the IOS project. While the native code was throwing a native assembly, I'd imagine that AppDelegate was actually throwing a NotSupportedException or an AssemblyLoader Exception or similar.
So removing all references and nuget packages, then re-adding just the bare minimum seems to have resolved this issue.
Set the Build Action property of AppDelegate.cs to Compile.
Rebuild your solutions then restart your IDE.
Nothing stands out as a problem in the code you have posted.
However, you can try the following :
AppDelegate code is missing a 'Window' property. If you have just not added it to your code snippet in the question for brevity, fine. If not, do add it to your app delegate. Both Xamarin and Apple mention this in their documentation for ApDelegate and Storyboards.
public override UIWindow Window { get; set; }
Make sure the Build action for you AppDelegate is set to Compile and not mistakenly changed to none or any other value. This is highly unlikely, but because you mentioned you're going through a huge refactor, this could have been changed accidentally.
Similar problems were reported with different Xamarin.iOS versions before. So try running you project with a different xamarin version setup.
Although, i presume, you've tried this multiple times before posting the question, i'd mention : try a complete clean and rebuild. (Manually delete the bin' andobj` folders in your iOS project folder, clean the trash, and then do a rebuild just to be sure. Also, try out a full machine restart, remember you're using a Microsoft product!)
I also found this weird line in the same Xamarin documentation, although i am not sure how this can be checked, because the storyboards do not have an owner/AppDelegate reference.
Application's that are launched from a XIB or storyboard use the
UIApplicationDelegate specified in the XIB or storyboard.
Hope either of these steps helps you out. Good luck.
For me it was some missing reference in the iOS project.
Make sure that whatever the Shared and the iOS projects reference at least the same packages.
I'm trying to get access to the device lockscreen in a xamarin forms pcl project. I have heard about third-party components such as Lockscreen and Passcode but i dont know how to go about it since this is a xamarin forms app not xamarin.android. How would i implement let's say Lockscreen in the android project of my xamarin forms application?
One way to call Locker.Activate() within Xamarin Forms is to use a dependency service. In your Xamarin.Forms Project, you can add the following code to make the call to the dependency service:
switch (Device.RuntimePlatform)
{
case Device.Android:
DependencyService.Get<IAndroidMethods>().activateLock();
break;
case Device.iOS:
DependencyService.Get<IAppleMethods>().activateLock();
break;
}
Then in your Xamarin.Forms project, create two interfaces: IAppleMethods and IAndroidMethods that contain the activateLock() method.
I'll show the implementation for IAndroidMethods:
public interface IAndroidMethods
{
void activateLock();
}
Then, in your iOS and Android projects, create classes that implement the interfaces you just created. This would be your android class:
//add appropriate using declarations
[assembly: Xamarin.Forms.Dependency(typeof(AndroidMethods))]
namespace <YourApp>.Droid
{
public class AndroidMethods : IAndroidMethods
{
public void activateLock()
{
Locker.Activate(Xamarin.Forms.Forms.Context); //Not sure about any other parameters you need to pass in
}
}
}
I am not sure how to use Dependency Injection on Xamarin Android project solution. Currently my Android solution holds a reference to another class library solution. I have used Unity on my service layer and registered the container via WebApiConfig.cs.
My question is, how do i go about using Unity on Android side in order to run on start up, would be grateful if code was included. I dont want to new-up the container through main activity of Android. I want the container to register behind the process i.e. AppStart or Global asax where it does it for you for MVC apps. Is there a way to do it for Android? Also I noticed on Main Activity I am unable to create constructor. I guess this isnt possible but how do I go about holding object reference to my Class Library solution ? example that i attempted to do:
private IExample _ex;
MainActivity(IExample ex){
_ex = ex; //depedency Injection rather than newing it up
}
public void DoSomething(){
_ex.HelloWorld();
}
Is there a way to do it via Attribute ? Also for each of my layer do I need to install and create container in order to resolve current solution dependency ? or can I use container from android which would resolve all dependency in each layer as DDD architecture goes from outer to inner ?
In terms of setting up DI at startup you can create a custom Application implementation like so:
// Must include this attribute so that Android knows we want to use this as our Application implementation
[Application(Icon = "#drawable/Icon", Label = "#string/ApplicationName")]
public class MyApplication : Application
{
public override void OnCreate()
{
base.OnCreate();
// Do your DI initialization/registration here
}
}
I'm not sure exactly what you mean by not being able to create a constructor on the main activity. You can create constructors for any activity you feel like. You don't always see it though because people tend to put their initialization logic in OnCreate.