How can I launch a Android Activity from Xamarin Forms Page? - xamarin

I know that i can launch a Xamarin Forms page from an Native Android Activity, but how do i start a Native Android Activity from Xamarin Forms ContentPage. I tried with DependencyService but without success.

I figured it out.
First i needed to create a Interface like this in Xamarin Project
public interface IRecordVideoPage
{
void StartNativeIntentOrActivity();
}
then i launched the Native Android Activity from my Xamarin Forms Content Page using Dependency Service like this:
DependencyService.Register<IRecordVideoPage>();
DependencyService.Get<IRecordVideoPage>().StartNativeIntentOrActivity();
next I created a RecordActivity class in my Android Project that loads the Test Activity
[assembly: Xamarin.Forms.Dependency(typeof(RecordActivity))]
namespace StreamTest.Droid
{
[Activity(Label = "RecordActivity")]
public class RecordActivity : IRecordVideoPage
{
public void StartNativeIntentOrActivity()
{
var intent = new Intent(Forms.Context, typeof(Test));
Forms.Context.StartActivity(intent);
}
}
finally I set the content view in the Test class:
public class Test : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public Test() { }
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Record);
}
}
}

DependencyService is your best option. The concept behind PCL (Portable Class Library) is exactly to be platform independet.
Maybe we can help if you show the error you are getting with Dependency Service

Related

xamarin - Android change theme programmatically

I have a multi-tenant app, and have to switch the theme after the user logs in.
What I have so far is that when the User is already logged in and starts the app, I call setTheme() on the MainActivity OnCreate Method.
This works fine and the app is shown in the correct theme.
But when the user is not logged in, the app will start with the default theme. After login i can recognize the user and have to change the theme. But how can I do this. The login process is not in the android project, and from there I have no access to the MainActivity.
How can I set the new theme and recreate the app?
I am very grateful for help.
UPDATE
The log in method is at the moment in the MC.Core (Shared) (.NET Standard 2.0) library and the MainActivity is in the MC.Android library. So there is an Plugin which you can access the actual activity over projects, but I can't use it, becouse it does support .Net Standard.
And I'm not shure, if I can subscribe an event over two project. If this would be possible, how can I to this?
My very last solution is to move the login method form my core project to the Android project. But in this case I have to implement this for every platform.
To call a method in your MainActivity from the net standard project, you need to pass a reference to your MainActivity to the standard project. The best way to do this is to pass a reference to the shared net standard project App constructor, which is invoked from MainActivity. Of course, you cannot declare a parameter in your App constructor of type MainActivity, because your net standard project cannot reference the Android project, and because, if you will in the future implement iOS and / or UWP version of your app, you need a common type between all these different project.
So, you have to define an interface in your net standard project:
public interface IThemeChanger
{
void ApplyTheme(string newTheme);
}
Then, in the Android project, make your MainActivity implement this interface:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IThemeChanger
{
public void ApplyTheme(string newTheme)
{
if (newTheme?.ToLower() == "dark")
{
SetTheme(Resource.Style.Base_Theme_AppCompat);
}
else
{
SetTheme(Resource.Style.Base_Theme_AppCompat_Light);
}
}
and make it pass a reference to itself in the constructor of the app class:
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App(this));
}
Then, in the net standard App class, change the constructor so that it accepts an argument of type IThemeChanger, and store a reference to it in a private or public field (depending if you need or not to access it from outside App class):
public readonly IThemeChanger ThemeChanger;
public App(IThemeChanger themeChanger)
{
InitializeComponent();
this.ThemeChanger = themeChanger;
MainPage = new MainPage();
}
Then, in your login page, after the user login successfully, change the theme accordingly, for example:
((App.Current) as App).ThemeChanger.ApplyTheme("Dark");
If you do not instantiate your App class directly but use a dependency injection container, then register the current instance of MainActivity as an implementer of the IThemeChanger interface with your container, and simply request an IThemeChanger instance in the constructor of your ViewModel. Of course syntax vary depending on which DI Container you use, here is an example with Caliburn.Micro SimpleContainer:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IThemeChanger
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
var container = IoC.Get<SimpleContainer>();
if (container.HasHandler<IThemeChanger>())
{
container.UnregisterHandler<IThemeChanger>();
}
container.Instance<IThemeChanger>(this);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(container.GetInstance<App>());
}
In this case, please note that a new instance of MainActivity can be created during app resume, so you need to check for a potential previous registration of the interface and unregister it.
In your ViewModel:
public class LoginViewmModel{
private readonly IThemeChanger themeChanger;
public LoginViewModel(IThemeChanger themeChanger){
this.themeChanger = themChanger;
}
private void ApplyTheme{
themeChanger.ApplyTheme("Dark");
}
}

Xamarin WebViewRenderer.OnElementChanged gets called with null native controll on Xamarin Forms 2.5

I am using my own customrenderer for Webviews it has always worked but since I upgraded Xamarin Forms nuget package to version 2.5 it crashes because it seems like the member method OnElementChanged is called with null Native control and null thisActivity. any idea how to fix it?
this is the error I get:
Unhandled Exception:
System.ArgumentNullException: Value cannot be null.
Parameter name: thisActivity
I fixed this crash by adding a constructor which takes a Androd.Content.Context and passes it down to the base class in my custom PageRenderer which contains my custom WebViewRenderer. Adding the new constructor to the webview itself wasn't helpful.
public class BaseControllerRenderer : Xamarin.Forms.Platform.Android.PageRenderer
{
public BaseControllerRenderer(Context context) : base(context)
{
}
...
From the Xamarin.Forms 2.5 release notes:
WebViewRenderer: This constructor is obsolete as of version 2.5. Please use WebViewRenderer(Context) instead.
Example constructor for the WebView custom renderer and OnElementChanged:
public CustomWebViewRenderer(Context context) : base(context)
{
Activity activity = (Activity)context;
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Android.Webkit.WebView webView = Control;
}
}
See also WebViewRenderer
Edit: Please note that the constructor change applies to any Android custom renderers as described in the Xamarin.Forms 2.5 release notes:
Supporting Forms Embedding required a significant number of deprecations in the Android backend. Please update any custom renderers.

Xamarin WebView - Call C# Method

Is there a way in Xamarin's WebView that allows me to attach javascript events to my html elements and call C# method.
I could easily do this in Android by using JavaScriptInterface
<video width="320" height="240" controls="controls" poster='poster.gif'
onclick="window.JSInterface.startVideo('file:///sdcard/test.3gp');"
How would I manage to this in Xamarin
Create a JavaScript Interface Class
Create a C# class that contains methods to be called from JavaScript.
If you are targeting Android API level 17 or later, this
JavaScript-to-C# interface class must annotate each
JavaScript-callable method with [JavascriptInterface] and [Export]
as shown in the following example. If you are targeting Android API
Level 16 or earlier, this interface class must implement
Java.Lang.IRunnable as explained in Android API Level 16 and
Earlier (later in this recipe):
Create a C# class that is derived from Java.Lang.Object. In the following example, we name our class MyJSInterface and implement a
method to display a toast when it is called from JavaScript:
public class MyJSInterface : Java.Lang.Object
{
Context context;
public MyJSInterface (Context context)
{
this.context = context;
}
public void ShowToast ()
{
Toast.MakeText (context, "Hello from C#", ToastLength.Short).Show ();
}
}
Annotate each method that is to be exposed to JavaScript with [Export] and [JavascriptInterface] (see IJavascriptInterface
for more information about the JavascriptInterface annotation). In
the following example, the ShowToast method is annotated so that it
can be called from JavaScript. Note that you must include the
Java.Interop and Android.Webkit using statements as shown in this
example:
using Java.Interop;
using Android.Webkit;
...
[Export]
[JavascriptInterface]
public void ShowToast ()
{
Toast.MakeText(context, "Hello from C#", ToastLength.Short).Show();
}
Add a project reference to Mono.Android.Export (so you can use the [Export] annotation):
1.In Visual Studio, right-click References in the Solution Explorer and select Add Reference.... In Xamarin Studio,
right-click References in the Solution Pad and select Edit
References....
2.In the search field, enter Mono.Android.Export. When you have located it, enable the check mark next to it and click OK.
Refer :
http://dotnetthoughts.net/how-to-invoke-c-from-javascript-in-android/
https://developer.xamarin.com/recipes/android/controls/webview/call_csharp_from_javascript/
https://developer.xamarin.com/samples/monodroid/WebViewJavaScriptInterface/
https://developer.xamarin.com/api/type/Android.Webkit.JavascriptInterface/

Xamarin Cross Platform Application Package Name in C#

Is there a way to programmatically access the application package name/namespace/version information in Xamarin portable C# code?
Like this (link is how to access for Android, I want to know if there is a pre-existing C# cross platform way to access this in the portable class code.)
Not this.
i got answer to your problem, but it is using dependency service to work. There is no other way if there is no Xamarin plugin.
Here is the code:
Interface in pcl project:
public interface IPackageName
{
string PackageName { get; }
}
Android implementation:
public class PackageNameDroid : IPackageName
{
public PackageNameDroid()
{
}
public string PackageName
{
get { return Application.Context.PackageName; }
}
}
iOS implementation:
public class PackageNameIOS : IPackageName
{
public PackageNameIOS()
{
}
public string PackageName
{
get { return NSBundle.MainBundle.BundleIdentifier; }
}
}
Don't forget to mark platform files for dependency service in Android file:
[assembly: Xamarin.Forms.Dependency(typeof(PackageNameDroid))]
and iOS file:
[assembly: Xamarin.Forms.Dependency(typeof(PackageNameIOS))]
Now you're good to go and can use it in PCLs just like that:
string packageName = DependencyService.Get<IPackageName>().PackageName;
Hope it helps others.

Custom PageRenderer or NavigationRenderer not working (virtual missing?)

Currently I'm working on a Win Phone 8.1 project and need some Custom Renderer for ContentPage and NavigationPages.
But when I tried to implement it i saw there is no possibility for overwrite the OnElementChanged Method. After some minutes with DotPeek I saw that those methods not are virtual like on other plattforms. So does anybody have an idea or a workaround for implementing custom rederers on Windows RT?
Tried on Xamarin.Forms: 2.0.0.6490 & 2.1.0.6529
Sincerely
You can use the Event ElementChanged.
public class MyRender: NavigationPageRenderer
{
public MyRender()
{
ElementChanged += OnElementChanged;
}
private void OnElementChanged(object sender, VisualElementChangedEventArgs visualElementChangedEventArgs)
{
// do some stuff here
}
}

Resources