I am trying to build a Home Launcher App in Xamarin
Currently I have a Xamarin Forms App with Access to Xamarin Android through interfaces. In Xamarin Android I have a method to find all package Names on the device like this:
[assembly: Xamarin.Forms.Dependency(typeof(Launcher.Droid.GetLauncher))]
namespace Launcher.Droid
{
class GetLauncher : MainActivity,IGetLauncher
{
public string GetPackageName(int index)
{
var apps = Android.App.Application.Context.PackageManager
.GetInstalledApplications(PackageInfoFlags.MatchAll);
return apps[index].PackageName; ;
}
}
}
I can access this function from Xamarin Forms to get the package names.
Now I want to launch an App with a certain package Name:
I have tried the following code also in Xamarin Android accessed by an Interface from Xamarin Forms:
[assembly: Xamarin.Forms.Dependency(typeof(Launcher.Droid.GetLauncher))]
namespace Launcher.Droid
{
class GetLauncher : MainActivity,IGetLauncher
{
public void RunApp(int index)
{
var apps = Android.App.Application.Context
.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
Intent intent =
PackageManager.GetLaunchIntentForPackage(apps[index].PackageName);
StartActivity(intent);
}
}
}
which results in the following error:
Java.Lang.NullPointerException
Nachricht = Attempt to invoke virtual method 'android.content.pm.PackageManager android.content.Context.getPackageManager()' on a null object reference
The Error occurs on the PackageManager.GetLaunchIntentForPackage Line.
I am testing on a physical device.
Any Help or hints would be highly appreciated.
Try to change your codes like below:
[assembly: Xamarin.Forms.Dependency(typeof(Launcher.Droid.GetLauncher))]
namespace Launcher.Droid
{
class GetLauncher : IGetLauncher
{
public void RunApp(int index)
{
var apps = Android.App.Application.Context.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
Intent intent = Android.App.Application.Context.PackageManager.GetLaunchIntentForPackage(apps[index].PackageName);
Android.App.Application.Context.StartActivity(intent);
}
}
}
Related
I am not sure of the terminology for what I'm looking to do, so sorry in advance!
I've found a FilePicker plugin for Xamarin.Forms (https://github.com/Studyxnet/FilePicker-Plugin-for-Xamarin-and-Windows) that implements device-specific functionality for selecting files via the CrossFilePicker class.
The way to use leverage this functionality would be something like
CrossFilePicker.Current.OpenFile("Filename.txt");
The most important part of this for me is that CrossFilePicker.Current is static and can be accessible from anywhere in the shared layer of my Xamarin.Forms app.
I need to implement a class with the same characteristics. I want to leverage device Accessibility functionality (i.e. determining if a screen reader is enabled) and I need to be able to do so with a static class.
My eventual plan is to then wrap this static class so that I can use it for unit tests too.
I don't want to import device libraries into my shared project.
TLDR: I need a static class that implements device-specific functionality.
Any help would be greatly appreciated! Thank you :)
EDIT:
Here are the files I have currently implemented in my project
IAccessibilityService Located in the shared .NET project
namespace Bitspace.Services
{
public interface IAccessibilityService
{
public bool IsScreenReaderEnabled();
public void Announcement(string message);
public void NavigationAnnouncement(string message);
}
}
DeviceAccessibility.cs Located in the shared .NET project
using System;
namespace Bitspace.Services
{
public class DeviceAccessibility
{
private static Lazy<IAccessibilityService> Implementation = new Lazy<IAccessibilityService>(() => CreateAccessibilityService(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
public static IAccessibilityService Current
{
get
{
var curr = Implementation.Value;
if (curr == null)
{
throw new Exception();
}
return curr;
}
}
private static IAccessibilityService CreateAccessibilityService()
{
return new DeviceAccessibilityImplementation();
}
}
}
DeviceAccessibilityImplementation.cs Located in the Android project
using Android.Runtime;
namespace Bitspace.Services
{
[Preserve (AllMembers = true)]
public class DeviceAccessibilityImplementation : IAccessibilityService
{
public bool IsScreenReaderEnabled()
{
return true;
}
public void Announcement(string message)
{
}
public void NavigationAnnouncement(string message)
{
}
}
}
If I try to build the project, I get an error on the return new DeviceAccessibilityImplementation(); line in DeviceAccessibility.cs that says DeviceAccessibility.cs(25, 24): [CS0246] The type or namespace name 'DeviceAccessibilityImplementation' could not be found (are you missing a using directive or an assembly reference?)
However, CTRL Clicking on that line takes me to the DeviceAccessibilityImplementation.cs
I am rewriting my vanilla Xamarin app to use Prism Library.
The current app uses Azure ADB2C for authorisation using this framework.
Android needs to have its parent window set, which is achieved by adding this code into the MainActivity.cs of the Android project:
var authenticationService = DependencyService.Get<IAuthenticationService>();
authenticationService.SetParent(this);
This doesn't work for the Prism app, authenticationService is null. For the record, the DependencyService used here is Xamarin.Forms.DependencyService.
I also tried the example from the Prism docs and put this code into the AndroidInitializer:
public void RegisterTypes(IContainerRegistry container)
{
// Register any platform specific implementations
container.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>("B2CAuthenticationService");
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(this);
}
In this code, Container (which is a DryIoC Container) had no definition for Resolve.
For completeness, this is my App.cs RegisterTypes:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>();
...
...
}
There are a few wrong assumptions you're making here. To start you'll notice that IContainerRegistry specifically has the name Registry in it to imply we don't want you resolving types here. This is why you don't see the Resolve method on it but rather the IContainerProvider instance.
By design, Prism no longer works directly with the Xamarin.Forms DependencyService as this is a complete anti-pattern. That said if you follow the guidance for registering Platform Specific types you can see how to use the IPlatformInitializer to register platform specific types. It is important to realize here that the IPlatformInitializer is called before RegisterTypes is called in PrismApplication.
What I would suggest is to introduce a IParentWindowProvider like:
public interface IParentWindowProvider
{
object Parent { get; }
}
You can then implement this on Android like:
public class MainActivity : IPlatformInitializer, IParentWindowProvider
{
object IParentWindowProvider.Parent => this;
void IPlatformInitializer.RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterInstance<IParentWindowProvider>(this);
}
}
Then in your Application you might do something like:
protected override void OnInitialized()
{
if(Container.IsRegistered<IParentWindowProvider>())
{
var provider = Container.Resolve<IParentWindowProvider>();
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(provider.Parent);
}
}
For more info be sure to check out the relevant docs and sample
https://prismlibrary.com/docs/xamarin-forms/dependency-injection/platform-specific-services.html
https://github.com/PrismLibrary/Prism-Samples-Forms/tree/master/03-PlatformSpecificServices
I am using appium java-client 4.1.2 and selenium 3.1.0
So I have this method that returns a RegisterSelectionPage object when a button is clicked on the main screen. The code snippet below belongs to the MainScreen Page Object where there is a function to click the register button.
public RegisterSelectionPage clickRegister(){
registerButton = driver.findElement(By.id("com.test.app:id/btn_register"));
registerButton.click();
return PageFactory.initElements(new AppiumFieldDecorator(driver), RegisterSelectionPage.class);
}
The return line is basically underlined as red in IntelliJ and a warning says that the types are incompatible.
Required: com.example.app.screens.RegisterSelectionPage Found: void
This seems to be only happening when PageFactory.initElements() is the 'return' object.
To give more context, the RegisterSelectionPage looks like:
public class RegisterSelectionPage {
private WebDriver driver;
#AndroidFindBy(id = "")//will add the later
WebElement registerWithEmailLink;
public RegisterSelectionPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
}
Using NuGet I added Unity to my Xamarin.Forms Application.
In my App class constructor I want to newup a UnityContainer instance.
using Xamarin.Forms;
public class App : Application
{
public App ()
{
unityContainer = new UnityContainer();
// The root page of your application
this.MainPage = new NavigationPage(new HomePage());
}
private static IUnityContainer unityContainer;
}
Unfortunately a System.Reflection.TargetInvocationException. Is thrown on the line unityContainer = new UnityContainer(); as I start to run my app in the android emulator.
What could be the reason to this?
I'm currently trying to develop an application under Android using Mono.
I'd like to add support for plugins to my application so additional features could be brought to it.
I was able to load simple .dll at runtime in my program, however whenever I try creating a dll implementing both my interface and a custom activity, an exception of type Java.Lang.NoClassDefFoundError is thrown.
There is the class inside the dll code:
[Activity (Label = "Vestiaire")]
public class Vestiaire : Activity, IModule
{
public string Name { get; set; }
public string Version { get; set; }
void OnClickVestiaireButton(object sender, System.EventArgs e)
{
;
}
public void InitVestiaireModule()
{
Run();
}
public Type LaunchActivity ()
{
return typeof(Vestiaire);
}
public void Init()
{
Name = "Vestiaire Module";
Version = "0.1";
}
public void Run()
{
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
}
The line responsible for the exception: (from the program core)
LoadedPlugin.Add((IModule)(Activator.CreateInstance(Plugin)));
Things I'm actually wonderring are:
- Is it possible to actually achieve what i'm trying to ?
If yes, help would be apreciated on that problem :P
Otherwise what would be the best alternative ?
Global point is to be able to load a custom menu at runtime loaded from a dll.
Thanks.
i think the key to your problem is that the Activity needs to be registered in you Manifest.xml file.
For Activities in you main app, MonoDroid does this for you - but I don't think this will work for your plugin.
Things you could try are:
putting the Activity in the Manifest yourself (MonoDroid does seem very capable at merging these files)
if that doesn't work, then you could try using a Fragment instead - and loading the Fragment into a custom FragmentActivity in your main app.