Xamarin android webview open dialog for choosing camera or file manager - xamarin.android

I want to open a dialog for chosing files or take a photo in a webview when clicking on a input on the website. When clicking on the input now it opens the filemanager.
I used this page for testing it https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/capture
my input looks like this <input type="file" multiple="multiple" style="display: none;">
it works when using chrome in android.

You can set settings.JavaScriptEnabled = true in android webview renderer to enable js like:
public class Mywebview : WebViewRenderer
{
public Mywebview(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Android.Webkit.WebView webview = (Android.Webkit.WebView)Control;
WebSettings settings = webview.Settings;
settings.JavaScriptEnabled = true;
settings.SetAppCacheEnabled(true);
}
}
}

Related

Get JSON values from Webview

How can I find Json response value from WebView
Example: There is a one Login URL and we are opening this in Webview use of this we will get token and I want to add this token in user default.
Store your JSON data in a hidden field as a string in your html file.
<input id="TokenInfo" type="hidden" value="YOUR_JSON_DATA"/>
Add following javaScript Code into your html page.
<script>
$(function() {
var tokenInfo = $("#TokenInfo").val();
try {
window.webkit.messageHandlers.scriptHandler.postMessage(tokenInfo); // For iOS
} catch (e) {
//
}
try {
Android.login(tokenInfo); // For Android
} catch (e) {
//
}
})
</script>
From android end you need to add a JavaScriptInterface interface into to web view
final JavaScriptInterface myJavaScriptInterface = new JavaScriptInterface(getContext());
webview.addJavascriptInterface(myJavaScriptInterface, "Android");
public class JavaScriptInterface {
Context mContext;
JavaScriptInterface(Context c) {
mContext = c;
}
#JavascriptInterface
public void login(String tokenInfo) {
// deserialize your json here.
}
}

Xamarin forms: Device.OpenUri is not working for opening pdf in iPhone

I am using Device.OpenUri for opening pdf files in my application. This is working fine on android devices but on iPhone, this is not working. Following is my code:
Device.OpenUri(new Uri("mypdfurl"));
Following is the screenshot on iPhone when opening pdf.
For opening pdf on iPhone should I add any permissions? Are there any free NuGet packages for showing the pdf in the app?
You can directly open the pdf file on the WebView . In this way you need to use Custom Renderer on Android because Webview in Android doesn't support open remote pdf in default .
in code behind
using Xamarin.Forms;
namespace PdfLoader
{
public class PdfWebView:WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(PdfWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
}
in Android
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using PdfLoader.Droid;
using PdfLoader;
[assembly: ExportRenderer(typeof(PdfWebView), typeof(MyWebViewRenderer))]
namespace PdfLoader.Droid
{
public class MyWebViewRenderer : WebViewRenderer
{
public MyWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var customWebView = Element as PdfWebView;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.JavaScriptEnabled = true;
Control.LoadUrl(string.Format("https://drive.google.com/viewerng/viewer?url={0}", customWebView.Uri.ToString()));
}
}
}
}
in xaml
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<local:PdfWebView
Uri="{Binding xxx}"
Source="{Binding xxx}" //set them as same value
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="300"
WidthRequest="300"
x:Name="pdf_Webview"/>
</StackLayout>

How can i get notification from DatePicker and Timepicker only user presses Done button in Xamarin forms IOS

i want to know how to get notification from Datepicker and timepicker only when user presses done button in Xamarin forms IOS. currently when TimePicker property changed and DatePicker DateSelected is raised when ever picker selected index is changed.
Help me to resolve this problem.
When user press the done button of DatePicker and TimerPicker, the unfocused event will be fired.
For example:
<StackLayout>
<!-- Place new controls here -->
<app71:myPicker Unfocused="DatePicker_Unfocused"/>
<TimePicker Unfocused="TimePicker_Unfocused" />
</StackLayout>
And in .cs:
private void DatePicker_Unfocused(object sender, FocusEventArgs e)
{
Console.WriteLine("DatePicker_Unfocused");
}
private void TimePicker_Unfocused(object sender, FocusEventArgs e)
{
Console.WriteLine("TimePicker_Unfocused");
}
You can also handle the click event in the native Xamarin.iOS project using custom renderer, here is an example of DatePicker:
[assembly: ExportRenderer(typeof(myPicker), typeof(MyPickerRenderer))]
namespace App71.iOS
{
public class MyPickerRenderer : DatePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
var toolbar = (UIToolbar)Control.InputAccessoryView;
var doneBtn = toolbar.Items[1];
doneBtn.Clicked -= DoneBtn_Clicked;
}
if (e.NewElement != null)
{
var toolbar = (UIToolbar)Control.InputAccessoryView;
var doneBtn = toolbar.Items[1];
doneBtn.Clicked += DoneBtn_Clicked;
}
}
void DoneBtn_Clicked(object sender, EventArgs e)
{
Console.WriteLine("DoneBtn_Clicked");
}
}
}
Refer:
how-can-we-handle-the-done-button-click-event-for-a-xamarin-forms-picker
custom-renderer

Webview on IOS does not allow Navigating=“WebView_Navigating”

I am using a webview to display html. The html contains external links so I have added Navigating="WebView_Navigating" to my webview and it is working perfectly on an Android but IOS shows nothing where the converted html should be. Whenever I remove Navigating="WebView_Navigating" from the webview, everything is correct in IOS but I need to be able to use external links.
What am I missing?
I have already added [assembly: ExportRenderer(typeof(WebView), typeof(Xamarin.Forms.Platform.iOS.WkWebViewRenderer))] to my AssemblyInfo.cs file in the IOS project. I have also added NSAppTransportSecurity NSAllowsArbitraryLoads to my info.plist file.
Page:
<ContentPage.Resources>
<local1:HtmlConverter x:Key="HtmlConverter"/>
</ContentPage.Resources>
<ScrollView>
<StackLayout Padding="20" VerticalOptions="FillAndExpand">
<Image Source="/images/guests_henry_1080x1080.jpeg"
HorizontalOptions="StartAndExpand"
VerticalOptions="StartAndExpand" />
<WebView Navigating="WebView_Navigating" Source="{Binding Item.Text, Converter={StaticResource HtmlConverter}}" WidthRequest="1000" HeightRequest="1000" />
</StackLayout>
</ScrollView>
Code:
public partial class BioHenryPage : ContentPage
{
public BioHenryPage()
{
InitializeComponent();
BioHenryViewModel viewModel = new BioHenryViewModel();
BindingContext = viewModel;
}
public void WebView_Navigating(object sender, WebNavigatingEventArgs args)
{
if (args.Url.StartsWith("http"))
{
Device.OpenUri(new Uri(args.Url));
}
args.Cancel = true;
}
}
I expect the converted html to show in both Android and IOS.
If you want to get the URL of web in iOS, you can use CustomRenderer .
in your iOS project
using xxx.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(WebView), typeof(myWebRender))]
namespace xxx.iOS
{
class myWebRender : WebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{ // perform initial setup
UIWebView myWebView = (UIWebView)this.NativeView;
myWebView.Delegate = new CustomWebViewDelegate();
}
}
public class CustomWebViewDelegate : UIWebViewDelegate
{
public CustomWebViewDelegate()
{
}
public override bool ShouldStartLoad(UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType)
{
string url = request.Url.AbsoluteString;
if(url.StartsWith("http"))
{
if(UIApplication.SharedApplication.CanOpenUrl(request.Url))
{
UIApplication.SharedApplication.OpenUrl(request.Url);
}
}
webView.EvaluateJavascript("window.stop();");
return true;
}
}
}
}
Lucas, thank you so much for your answer! My solution was to move the webview navigating to the end of the constructor after binding. It was a timing issue with iOS. This is where I found the solution. Webview always return blank screen in ios Xamarin.Forms
"If you are responding to the WebView.Navigating event, be sure to not set its args.Cancel to true if the page loaded is the WevView.Source. The iOS implementation of WebView.Navigating fires when the WebView.Source is loaded but the Android implementation does not. If you set args.Cancel to true when the page in question is the WebView.Source, the WebView will be blank."

How to get the progress of WebView while loading the data, Xamarin.Forms

I am developing an App using Xamarin.Forms for listing the news from different sources. I use a webView to open the link corresponding to the news. But I want to show the progress while loading the webpage into web view, like the progress bar on Safari App. For this I have used the ProgressBar element like this:
<StackLayout>
<!-- WebView needs to be given height and width request within layouts to render. -->
<ProgressBar Progress ="" HorizontalOptions="FillAndExpand" x:Name="progress"/>
<WebView x:Name="webView"
HeightRequest="1000"
WidthRequest="1000"
VerticalOptions= "FillAndExpand"
Navigating="webOnNavigating"
Navigated="webOnEndNavigating"/>
</StackLayout>
and in the code I have used
void webOnNavigating (object sender, WebNavigatingEventArgs e)
{
progress.IsVisible = true;
}
void webOnEndNavigating (object sender, WebNavigatedEventArgs e)
{
progress.IsVisible = false;
}
But I want to show also the progress of loading the data, not just an indication that is loading and load. I want the user to know that the data are loading. Is there a way to achieve this.
The implementations should be platform specific via custom renders. Luckily this topics has been discussed already for different platforms here on SO.
The Android version based on this thread:
[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.Droid
{
public class GenericWebViewRenderer : WebViewRenderer
{
Context ctx;
public GenericWebViewRenderer(Context context) : base(context)
{
ctx = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
var progressBar = new Android.Widget.ProgressBar(ctx, null, Android.Resource.Attribute.ProgressBarStyleHorizontal);
Control.SetWebChromeClient(new MyWebChromeClient(progressBar));
Control.AddView(progressBar);
}
class MyWebChromeClient : Android.Webkit.WebChromeClient
{
Android.Widget.ProgressBar progressBar;
public MyWebChromeClient(Android.Widget.ProgressBar progressBar)
{
this.progressBar = progressBar;
}
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
progressBar.SetProgress(newProgress, true);
}
}
}
}
On iOS it is a bit trickier, here is a very simple mock that does it job pretty well:
[assembly: ExportRenderer(typeof(WebView), typeof(GenericWebViewRenderer))]
namespace WebViewWithProgressBar.iOS
{
public class GenericWebViewRenderer : ViewRenderer<WebView, UIWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var progressBar = new UIProgressView(UIProgressViewStyle.Bar);
progressBar.TintColor = UIColor.Green;
progressBar.TrackTintColor = UIColor.Black;
progressBar.ProgressTintColor = UIColor.Red;
var webView = new UIWebView(Frame);
webView.AddSubview(progressBar);
SetNativeControl(webView);
Control.Delegate = new MyUIWebViewDelegate(progressBar);
webView.LoadRequest(new NSUrlRequest(new NSUrl("https://google.com")));
}
}
class MyUIWebViewDelegate : UIWebViewDelegate
{
UIProgressView progressBar { get; }
public MyUIWebViewDelegate(UIProgressView progressBar)
{
this.progressBar = progressBar;
}
public override void LoadStarted(UIWebView webView)
{
progressBar.SetProgress(0.1f, false);
}
public override void LoadingFinished(UIWebView webView)
{
progressBar.SetProgress(1.0f, true);
}
public override void LoadFailed(UIWebView webView, NSError error)
{
// TODO:
}
}
}
}
For more details please check here.
P.S.: This code examples are available on github.

Resources