Xamarin Forms: WebView loading time is very high - xamarin.forms

I am using WebView for loading websites in my project. It is loading websites but very slow. It takes around 10 to 15 seconds to load this site.
I try a solution from this thread. I have added android:hardwareAccelerated="true" on the manifest under application level, but no luck.
For iOS and Windows the solution is below: But I don't know how to create the custom render.
In iOS, try to use WKWebView instead of UIWebView.
For the UWP, use Windows.UI.Xaml.Controls.WebViewcontrol instead of using the built-in Xamarin WebView control.
Can I get the sample custom renderer for iOS and Windows-like above?

It is loading websites but very slow
The speed of loading website will up to lots of causes . For example, it will consume a lot of time if the web contains many remote css/js file . And it will also up to network performance .
The link that you provided loads slow even if on browser on my side . It contains lots of remote css if we check the source code.
For Android , We can create an custom renderer webview to accelerate it.
Set Render Priority to hight.
Enable the dom storeage.
When Loading the html, we can disable the image showing, when
loading finished, load the image by
Control.Settings.BlockNetworkImage.
Enable the Cache, if you load it at the nexttime, you can load it
quickly.
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyWebviewRender))]
namespace MyWebviewDemo.Droid
{
public class MyWebviewRender : WebViewRenderer
{
public MyWebviewRender(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.Settings.JavaScriptEnabled = true;
Control.Settings.SetAppCacheEnabled(true);
Control.Settings.CacheMode = Android.Webkit.CacheModes.Normal;
Control.Settings.SetRenderPriority(RenderPriority.High);
Control.Settings.DomStorageEnabled = true;
Control.Settings.BlockNetworkImage = true;
Control.SetWebChromeClient(new MyWebChromeClient());
}
}
internal class MyWebChromeClient : WebChromeClient
{
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
base.OnProgressChanged(view, newProgress);
if (newProgress == 100)
{
// webview load success
// // loadDialog.dismiss();
view.Settings.BlockNetworkImage=false;
}
else
{
// webview loading
// loadDialog.show();
}
}
}
}
In iOS, try to use WKWebView instead of UIWebView. For the UWP, use Windows.UI.Xaml.Controls.WebViewcontrol instead of using the built-in Xamarin WebView control.
In your case it will only have less improve even if using above solution . You could add an ActivityIndicator during the loading . If you can access the website , it would be better to download the css file to local and loading them in ContentPage .

Related

Xamarin Forms AppShell How return to previous page

I see a lot of threads on this sort of subject but none seem to apply to my question. I don't have a navigation page, I have a hamburger menu -- so Push/PopAsync() would not appear to be the answer. And I don't want to go to a specific page, I want to go back to the previous page (whatever it was) so GoToAsync() would not appear to be the answer.
Xamarin app for Android and UWP with iOS somewhere in the future. The description of the problem below is specific to Android; it works a little differently on UWP.
I want to put a Help entry in the hamburger menu that will take the user to a help page in the default browser. Hamburger menu seems to only go to an app page, so I defined a "dummy" View page that displays "Loading ..." and issues Browser.OpenAsync() in its OnAppearing() method, and that pretty much works. The problem is that the user would expect that the Back button would take him or her to the page they were on before clicking Help. I tried a couple of things. I have gotten close with the following but it does not quite work correctly:
In each of my other Views' OnAppearing() I call a method that saves the value of Current.MainPage.CurrentItem in a static. Then in the Help page after the OpenAsync() I set Current.MainPage.CurrentItem to its setting from the last page before the Help page.
Console.WriteLine("#### HelpPage loading Web Help");
_ = State.DisplayHelpPage(this, "MainHelp"); // _ = await Browser.OpenAsync(uri, blo);
Console.WriteLine("#### HelpPage returning to previous page");
State.ReloadPreviousPage(); // Current.MainPage).CurrentItem = lastFlyoutItem;
It almost works. The first time I click Help in the hamburger menu I get
#### HelpPage loading Web Help
#### HelpPage returning to previous page
#### HelpPage loading Web Help
#### HelpPage returning to previous page
The Web page loads perfectly. But when I click the Back button it displays again. Obviously my OnAppearing() method has been driven twice, which I do not understand.
If I click the Back button again I come back to the previous page in the application just as I wanted. The next time I click Help in the Hamburger menu it takes me to my dummy View page with no Web page. Obviously, my OnAppearing() is not being driven at all. But after that it works perfectly. I can go to any app page, and click Help in the menu. I get the Web page, and the Back button takes me back to the app and the page. In UWP of course the browser does not load on top of the app Views, and I seem to see it being loaded twice every time.
So ... what should I be doing differently? And why is my OnAppearing() being driven twice and then not at all ... and thereafter as I would expect?
There are several parts to this answer:
Get the previous page on to the Navigation stack. This is done by intercepting the Route "//HelpPage", and replacing it with a route that ISN'T a child of Shell.
Remember "FakePageVisible", so we know to do "PopAsync" in OnResume, when app returns from browser.
(Optional) "Entering" flag prevents going to browser twice.
App.xaml.cs:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
protected override void OnResume()
{
if (HelpPage.FakePageVisible) {
HelpPage.FakePageVisible = false;
var shell = MainPage as AppShell;
if (shell != null) {
shell.Navigation.PopAsync();
}
}
}
}
AppShell.xaml.cs:
public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
// Define a route that isn't a child of Shell.
Routing.RegisterRoute("Help2", typeof(HelpPage));
}
protected override void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (args.Current != null) {
if (args.Source == ShellNavigationSource.ShellItemChanged) {
if (args.Target.Location.OriginalString == "//HelpPage") {
// Cancel the original route.
args.Cancel();
Device.BeginInvokeOnMainThread(() => {
// Used by the next OnAppearing.
HelpPage.Entering = true;
// Go there by a route that isn't a child of Shell.
// Doing so, pushes our previous location on to Navigation stack.
Shell.Current.GoToAsync("Help2");
});
}
}
}
}
}
HelpPage.xaml.cs:
public partial class HelpPage : ContentPage
{
public static bool Entering;
public static bool FakePageVisible;
protected override void OnAppearing
{
// Make sure this only happens once (just in case).
if (Entering) {
Entering = false;
FakePageVisible = true;
Xamarin.Essentials.Browser.OpenAsync("https://aka.ms/xamarin-quickstart");
}
}
}
For a simple demo, this code communicates via static variables in HelpPage. Re-factor as appropriate for your situation.

How to enable OS AppTheme Dark/Light in Run time in Xamarin Forms

I am following Respond to system theme change to respond to OS theme in xamarin form app. The app supports both Dark and Light themes with AppThemeBinding. I am not using any custom themes. I am following OS themes only. So I have a Switch which the user would prefer to enable Dark Mode (same as OS). The link suggests the following code to enable specified Mode (e.g Dark Mode).
Application.Current.UserAppTheme = OSAppTheme.Dark;
The above code does nothing, but if I write the above code in App.cs after InitializeComponent() The app changes to Dark Mode.
I Then realized to restart the MainActivity in Android which I did with the help of Dependency.
[assembly: Dependency(typeof(AndroidThemeChanged))]
public class AndroidThemeChanged : ITheme
{
public void OnThemeChanged()
{
var activity = CrossCurrentActivity.Current.Activity;
var intent = GetLauncherActivity();
activity.Finish();
activity.StartActivity(intent);
}
public static Intent GetLauncherActivity()
{
var packageName = AndroidApp.Context.PackageName;
return AndroidApp.Context.PackageManager.GetLaunchIntentForPackage(packageName);
}
}
and Calling it
if (Device.RuntimePlatform == Device.Android)
DependencyService.Get<ITheme>().OnThemeChanged();
Is there any way to update application theme irrespective of OS theme (Dark/Light) without restarting the MainActivity?
My bad, I guess I was wrong. The code in my question works as expected. I don't need to have that Android Service to restart activity.
Calling below from any where changes the theme to Dark irrespective of OS theme.
Application.Current.UserAppTheme = OSAppTheme.Dark;
I guess you don't have to restart the MainActivity. As per the documentation here we can react to the theme changes using the Application.Current.RequestedThemeChanged event.
Please make sure to follow the AppThemeBinding markup extension as per the documentation here.
Try the below code.
Application.Current.RequestedThemeChanged += Current_RequestedThemeChanged;
private void Current_RequestedThemeChanged(object sender, AppThemeChangedEventArgs e)
{
if (e.RequestedTheme == OSAppTheme.Dark)
Application.Current.UserAppTheme = OSAppTheme.Dark;
else
Application.Current.UserAppTheme = OSAppTheme.Light;
}
I hope that helps.

CefSharp WpfControl and rendering to image

We want to show a webpage in a chromium based browser within a wpf application.
The website that is displayed within the browser should also be shown on another screen but without interaction.
I want to combine the cefsharp wpf browser control and the cefsharp offscreen rendering.
Can I use one chromium instance for displaying the page with interactions in wpf and export the current visible website as an image?
Thank you and best regards,
Simon
Thank you amatiland, it indeed works with the OnPaint Method or Event.
public MainWindow()
{
InitializeComponent();
Browser.Paint += Browser_Paint;
}
void Browser_Paint(object sender, CefSharp.Wpf.PaintEventArgs e)
{
Bitmap newBitmap = new Bitmap(e.Width, e.Height, 4 * e.Width, System.Drawing.Imaging.PixelFormat.Format32bppRgb, e.Buffer);
var aPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "TestImageCefSharpQuant.png");
newBitmap.Save(aPath);
}
XAML
<wpf:ChromiumWebBrowser x:Name="Browser" Address="www.google.com"></wpf:ChromiumWebBrowser>

How to execute a platform (Android) specific method within a ButtonOnClick() using a Xamarin.Forms custom renderer.

Introduction:
I am starting with code from:
https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/Entry/Android
to study custom renderers. I am doing this because there is code that only executes on the android platform. Lets call this "androidMethod()" and belongs in the Android codebase (not the shared library). I have noticed that most of the examples I have found have utilized customRenderers for making platform specific UI modifications (like the example in the link) but I intend to make no changes to the UI, rather I am trying to place a platform specific method in a Xamarin.Forms ButtonOnClick() method as the code below indicates.
The code below is similar to the code you will find in the MyEntryRenderer.cs from the link but you will see that it was modified to apply to a button instead of an entry.
MyButtonRenderer.cs:
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using CustomRenderer;
using CustomRenderer.Android;
using Android.Content;
[assembly: ExportRenderer(typeof(MyButton), typeof(MyButtonRenderer))]
namespace CustomRenderer.Android
{
class MyButtonRenderer : ButtonRenderer
{
private Button androidButton;
public MyButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
//I want to be able to do something like this:
ButtonOnClick(androidMethod());
}
}
}
}
How do I get androidMethod(); to execute in this context. The samples I find are limited so please try to limit your response to something that would be compatible with the example. Thankyou!
if you want to execute a platform specific method, I would use DepenencyService instead of a Custom Renderer

Disable aspnet.friendlyurl's mobile redirect for tablets

My Website is responsive with Twitter Bootstrap and the desktop pages are designed for tablets and desktop. aspnet.friendlyUrls considers tablet devices as mobile and sends them to the ".Mobile.aspx" equivalent. How can I disable this behavior and keep tablets on the desktop pages?
2 Weeks later and still no awnser or even a comment? Am i the only one who actually uses aspnet.FriendlyUrls even if it's distributed in new VS2013 Asp.Net projects by default?
There is no setting to turn this off, but you can disable this by deleting the Site.Mobile.Master and ViewSwitcher files
The following files are no longer needed:
Site.Mobile.Master
- Site.Mobile.Master.cs
- Site.Mobile.Master.designer.cs
ViewSwitcher
- ViewSwitcher.cs
- ViewSwitcher.ascx.cs
Thanks to #fortboise for simplifying my answer
Remove the won't solve the problem, the way is override the TrySetMobileMasterPage.
step one: Create a Class
public class MyWebFormsFriendlyUrlResolver : Microsoft.AspNet.FriendlyUrls.Resolvers.WebFormsFriendlyUrlResolver
{
protected override bool TrySetMobileMasterPage(HttpContextBase httpContext, Page page, String mobileSuffix)
{
if (mobileSuffix == "Mobile")
{
return false;
}
else
{
return base.TrySetMobileMasterPage(httpContext, page, mobileSuffix);
}
}
}
After go in App_Start/RouteConfig and set:
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings, new MyWebFormsFriendlyUrlResolver());
}

Resources