Ive developing a webview app in Xamarin.Forms over the last few days and ive been testing it on an android and iOS emulator and it seems to work just fine in the emulators but when i went and tried to test it on my own Android device, it just showed the xamarin splashscreen(im using the trial version at the moment) and then just transitioned to a blank white screen instead of the webview.
Does anyone have any ideas why it is doing this?
I will attach my code below:
App.cs
using Xamarin.Forms;
namespace WebViewApp
{
public class App() : Application
{
public App()
{
// The root page of your application
MainPage = new WebPage();
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
WebPage.cs
using Xamarin.Forms;
namespace WebViewApp
{
public class WebPage : ContentPage
{
private const string URL = "https://www.google.com";
private const int PADDING_WIDTH = 0;
private int paddingHeight;
private WebView webView;
public WebPage()
{
webView = new WebView
{
Source = URL,
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
CheckDevice();
Content = new StackLayout
{
Padding = new Thickness(PADDING_WIDTH, GetPaddingHeight()),
Chrildren = { webView }
};
}
public int GetPaddingHeight()
{
return paddingHeight;
}
/// <summary>
/// This will set the padding height for the webview when displayed
/// <summary>
/// <param name="pHeight">Set integer value for the padding height.</param>
public void SetPaddingHeight(int pHeight)
{
paddingHeight = pHeight;
}
private void CheckDevice()
{
if(Device.OS == TargetPlatform.Android)
{
SetPaddingHeight(0);
}
else if(Device.OS == TargetPlatform.iOS)
{
SetPaddingHeight(20);
}
}
}
}
** UPDATE **
I am using a company website but I have been testing this app out with a number of different sites such as google, youtube, and amazon. It would seem that the only site that wont display on my device is my companies website(its a responsive website) but all of the others do.
Since version 9, iOS will only allow your application to communicate with servers that implement best-practice security by default. Values must be set in Info.plist to enable communication with insecure servers.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads </key>
<true/>
</dict>
You must set the two properties HeightRequest and WidthRequest.
WebView requires that HeightRequest and WidthRequest are specified
when contained in StackLayout or RelativeLayout. If you fail to
specify those properties, the WebView will not render.
Source: https://developer.xamarin.com/guides/xamarin-forms/user-interface/webview/
Here is my code to display a webview in a Xamarin.Forms App.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin;
using Xamarin.Forms;
namespace mynamespace
{
public class WebsitePage : ContentPage
{
public WebsitePage(string url)
{
Label lbl_header = new Label
{
Text = "WebView",
HorizontalOptions = LayoutOptions.Center
};
WebView webview = new WebView
{
Source = url,
VerticalOptions = LayoutOptions.FillAndExpand
};
this.Content = new StackLayout
{
Children = {
webview
}
};
}
}
}
Related
I've got a Xamarin.Forms WPF application running, but there is a huge title bar.
I have tried the solution of adding NavigationPage.SetHasNavigationBar(this, false); inside my MainPage class's constructor
Here is the code:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
}
Still I am getting huge title bar size in WPF application, on the other hand, while running on UWP, it is working fine.
You could try to add below codes in your MainWindow.xaml.cs in wpf project:
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (!topBarsRemoved) RemoveTopBars();
}
private bool topBarsRemoved = false;
private void RemoveTopBars()
{
var topAppBar = this.Template.FindName("PART_TopAppBar", this) as FormsAppBar;
if (topAppBar != null)
(topAppBar.Parent as System.Windows.Controls.Grid)?.Children.Remove(topAppBar);
topBarsRemoved = true;
}
I am working with Xamarin WebView and wanted to make my Xamarin app that will still load the Website when its offline.
Is there any Idea about Xamarin Webview load website when Offline?
I have been searching for this, I only see Java Android WebViews and nothing to see Xamarin forms
We could use Custom Renderer to set the CacheMode on iOS and Android .
in Forms
Create a custom WebView
public class MyWebView : WebView
{
public static readonly BindableProperty UrlProperty = BindableProperty.Create(
propertyName: "Url",
returnType: typeof(string),
declaringType: typeof(MyWebView),
defaultValue: default(string));
public string Url
{
get { return (string)GetValue(UrlProperty); }
set { SetValue(UrlProperty, value); }
}
}
in iOS
There is a ReturnCacheDataElseLoad Cache type of NSUrlRequestCachePolicy . You could set the value as NSURLRequestReturnCacheDataElseLoad .
Use existing cache data, regardless or age or expiration date, loading from originating source only if there is no cached data.
using System.ComponentModel;
using xxx;
using xxx.iOS;
using Foundation;
using UIKit;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly:ExportRenderer(typeof(MyWebView),typeof(MyWebViewRenderer))]
namespace xxx.iOS
{
public class MyWebViewRenderer : ViewRenderer<MyWebView, WKWebView>
{
WKWebView _wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<MyWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var config = new WKWebViewConfiguration();
_wkWebView = new WKWebView(Frame, config);
SetNativeControl(_wkWebView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "Url")
{
NSUrlRequest request = new NSUrlRequest(new NSUrl(Element.Url), NSUrlRequestCachePolicy.ReturnCacheDataElseLoad, 5);
Control.LoadRequest(request);
}
}
}
}
in Android
using Android.Content;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace xxx.Droid
{
public class MyWebViewRenderer : WebViewRenderer
{
public MyWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.Settings.CacheMode = Android.Webkit.CacheModes.CacheElseNetwork;
Control.Settings.JavaScriptEnabled = true;
}
}
}
}
Now you just need to define it in xaml like following
<local:MyWebView Url="xxx" />
I added Control.LoadUrl(((MyWebView)Element).Url); line in Android custom renderer otherwise url isn't displayed. Also OnElementPropertyChanged if(e.property==url) is never true I moved this block to OnElementChanged method in iOS renderer.
I'm really trying to work my way through a Xamarian.Form app an I'm finding it difficult because the template out of the box doesn't seem to work.
Basically on the menu I'm trying to nav to the Browse or About page.
however MainPage RootPage { get => Application.Current.MainPage as MainPage; } is returning null.
I've made no changes to this template but I do understand C# so I roughly understand the issue but I'm not aware as to why this is returning null, certainly from the starting template.
MenuPage.xaml.xs
using ProspectGator.Models;
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ProspectGator.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MenuPage : ContentPage
{
MainPage RootPage { get => Application.Current.MainPage as MainPage; }
List<HomeMenuItem> menuItems;
public MenuPage()
{
InitializeComponent();
menuItems = new List<HomeMenuItem>
{
new HomeMenuItem {Id = MenuItemType.Browse, Title="Browse" },
new HomeMenuItem {Id = MenuItemType.About, Title="About" }
};
ListViewMenu.ItemsSource = menuItems;
ListViewMenu.SelectedItem = menuItems[0];
ListViewMenu.ItemSelected += async (sender, e) =>
{
if (e.SelectedItem == null)
return;
var id = (int)((HomeMenuItem)e.SelectedItem).Id;
await RootPage.NavigateFromMenu(id);
};
}
}
}
App.xaml.cs
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using ProspectGator.Views;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace ProspectGator
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage( new MainPage());
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
Typically I would expect this property to be set or already set but I'm not sure. I do have a MainPage.xaml.
I am learning Xamarin and I know the basics of C#. One of the first codes I encounter is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace Hello
{
public class App : Application
{
public App()
{
// The root page of your application
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label {
HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}
}
};
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
The part where I have a problem is
Children = {
new Label {
HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
I don't understand what's happening here. What is Children? What is it getting assigned to?
Children is not assigned to, but Children is initialized. It is more confusing as property `Children' is not browsable, so it does not appear in intellisense.
Children is IList<View>.
You can initialize collection like this...
List<string> list = new List<string>{
"s1",
"s2",
"s3"
};
which is equivalent to
List<string> list = new List<string>();
list.Add("s1");
list.Add("s2");
list.Add("s3");
Similarly
Children = {
new Label{
}
}
is equivalent to
Children.Add(new Label{ });
However, there is no official document about how to initialize collection property like this, but it seems compiler converts expression cleverly. I tried to compile and it seems it did work correctly.
You can see an example here, https://dotnetfiddle.net/8jln93
I'm building a Xamarin.Forms application with a facebook login using Xamarin.Auth.
Entry point (app.cs):
public App()
{
MainPage = new WelcomePage();
}
WelcomePage:
using System;
using Xamarin.Forms;
namespace Project
{
public class WelcomePage : ContentPage
{
public WelcomePage()
{
var login = new Button { Text = "Login" };
login.Clicked += (sender, e) =>
{
Navigation.PushModalAsync(new LoginPage());
};
Content = new StackLayout
{
BackgroundColor = Color.FromHex("F0C640"),
Padding = new Thickness(10, 40, 10, 10),
Children = {
new Label { Text = "Please login" },
login
}
};
}
}
}
LoginPage:
using Xamarin.Forms;
namespace Project
{
public class LoginPage : ContentPage
{
}
}
This is empty as I use Xamarin.Auth to authenticate with facebook so I created 2 different renderers on iOS and Android to display the facebook login page. After the login success I call an action which is located in my app.cs file:
public Action SuccessfulLoginAction
{
get
{
return new Action(() => goToMainPage());
}
}
public void goToMainPage()
{
MainPage.Navigation.PopModalAsync();
//MainPage.Navigation.PopToRootAsync();
MainPage.Navigation.PushAsync(new DetailPage());
}
At the end of the authentication the page is white but I believe it's a white page from Facebook after the authentication is done.
The SuccessfulLoginAction is well called so I go through the goToMainPage() function.
I put some breakpoints and PopModalAsync() doesn't do anything, same for PopToRootAsync() and PushAsync()...
The DetailPage is just a page with a Label. If I try to display it at the beginning of the process (app(){}) it display it well.
Thanks.