We're trying to create a custom renderer for a WebView. The only issue is that Xamarin can't find Android.Webkit.WebView.
using [AppName];
using [AppName].Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Mono;
using Android.Webkit;
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace [AppName].Droid
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
const string JavaScriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new Android.Webkit.WebView(Forms.Context);
webView.Settings.JavaScriptEnabled = true;
SetNativeControl(webView);
}
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
}
if (e.NewElement != null)
{
Control.LoadUrl(string.Format("file:///android_asset/Content/{0}", Element.Source));
InjectJS(JavaScriptFunction);
}
}
void InjectJS(string script)
{
if (Control != null)
{
Control.LoadUrl(string.Format("javascript: {0}", script));
}
}
}
We have 'using Android.Webkit' but are met with the error 'the type or namespace name 'Webkit' does not exist in the namespace `[AppName].Android'. Are you missing an assembly reference?'
It seems like it's looking for it inside of our app namespace, which seems it could be the issue. But we have no idea how to resolve it.
Any help would be greatly appreciated.
It sounds like it is getting confused with another Android namespace in your project. Try using the global namespace
global::Android.Webkit.WebView
you could also define an alias
using web = global::Android.Webkit.WebView;
Related
I am making a cross-platform hybrid app, basically rescuing a website in IOS, with Xamarin. The problem is that within this website there is a "Login with Facebook" section and this is an API, it is NOT a JavaScript "window.open" method.
I would like to know if I am doing this correctly, since I have tried different methods, and none have worked for me. I have already tried implementing the following:
WKWebViewRenderer with the CreateWebView () function and class (Actual code)
WebViewRenderer <CustomWebView, WKWebView> with the DecidePolicy () function and class
Basic WebView enabling JavaScriptEnable and JavaScriptCanOpenWindow
The combinations between these
Thank you very much in advance, I leave my CustomWebView.
Note: I can't use UIWebView, it's banned from AppStore
using Foundation;
using MobileApp.iOS.Name;
using MobileApp.Models;
using System;
using UIKit;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(CustomWebViewIOS), typeof(CustomWebViewRenderer))]
namespace MobileApp.iOS.Name
{
public class CustomWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
WKWebView wKWebView = this;
WKPreferences pref = new WKPreferences() { JavaScriptCanOpenWindowsAutomatically = true, JavaScriptEnabled = true, };
var config = new WKWebViewConfiguration();
config.Preferences = pref;
if (NativeView != null)
{
((WKWebView)NativeView).UIDelegate = new MyWKUIDelegate();
}
}
}
public class MyWKUIDelegate : WKUIDelegate
{
public override WKWebView CreateWebView(WKWebView webView, WKWebViewConfiguration configuration, WKNavigationAction navigationAction, WKWindowFeatures windowFeatures)
{
var url = navigationAction.Request.Url;
if (navigationAction.TargetFrame == null)
{
webView.LoadRequest(navigationAction.Request);
}
return null;
}
}
}
For Android i was able to do it this way
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null && e.NewElement == null) return;
Control.TextSize = 14f;
Control.SetTextColor(Color.FromHex(Constants.Color.SLATE_GRAY).ToAndroid());
}
Is there any way for ios using Xamarin.Forms.Platform.ios.PickerRenderer?
I could see an example in ios. link. But now sure how to convert it into Xamarin.
By clicking 'Go to Definition' ,you can find PickerRenderer inherit ViewRenderer<Picker, UITextField>
so we just set Font on Control , refer to the following code
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if(Control != null)
{
Control.TextColor = UIColor.Red;
Control.Font = UIFont.SystemFontOfSize(30);
}
}
I wanted to hide 'cancel' button in my iOS search bar. I have implemented the following custom renderer code but it seems not to to work. If anyone knows solution , please share.
public class iOSSearchBar : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> args)
{
base.OnElementChanged(args);
UISearchBar bar = (UISearchBar)this.Control;
bar.AutocapitalizationType = UITextAutocapitalizationType.None;
bar.AutocorrectionType = UITextAutocorrectionType.No;
//bar.BarStyle = UIBarStyle.Default;
//bar.BarTintColor = UIColor.LightGray;
//bar.KeyboardType = UIKeyboardType.ASCIICapable;
bar.SearchBarStyle = UISearchBarStyle.Minimal;
bar.SetShowsCancelButton(false, false);
bar.ShowsCancelButton = false;
}
}
Thanks in advance
This worked for me.
https://gist.github.com/xleon/9f94a8482162460ceaf9
using System;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using UIKit;
using System.Diagnostics;
[assembly: ExportRenderer(typeof(SearchBar), typeof(Namespace.iOS.Renderers.ExtendedSearchBarRenderer))]
namespace Namespace.iOS.Renderers
{
public class ExtendedSearchBarRenderer : SearchBarRenderer
{
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "Text")
{
Control.ShowsCancelButton = false;
}
}
}
}
Write code to hide cancel button in layoutsubviews method.
public override void LayoutSubviews()
{
base.LayoutSubviews();
UISearchBar bar = (UISearchBar)this.Control;
bar.ShowsCancelButton = false;
}
Following is also working or me, no need to subclass searcher:
SearchBar.TextChanged += delegate
{
SearchBar.ShowsCancelButton = false;
};
I think i managed to remove it manually with:
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.Subviews[0].Subviews[0].RemoveFromSuperview();
}
}
I spend some more time searching for this, so adding here in case someone else wants to do both.
In case you also need to remove the X button as well, I found the solution in this comment
I have created a custom renderer for a WebView in my Xamarin.Forms project. The WebView works great on Android. Unfortunately, on iOS, when the device is rotated, the webpage (any webpage) does not correctly adjust to the new dimensions of the WebView. If I use the built in WebView for Forms, the pages correctly resize on rotate.
What am I doing wrong with my custom renderer?
Below is a stripped down version of my custom renderer (the issue still occurs):
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using UIKit;
using Foundation;
[assembly: ExportRenderer(typeof(WebView), typeof(MyProject.iOS.WebViewRenderer))]
namespace MyProject.iOS {
public class WebViewRenderer : ViewRenderer<WebView, UIWebView> {
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e) {
if (Control == null) {
var webView = new UIWebView(Frame);
webView.AutoresizingMask = UIViewAutoresizing.All;
SetNativeControl(webView);
webView.LoadRequest(new NSUrlRequest(new NSUrl("http://cnn.com")));
}
}
}
}
To fix the issue, add the following to the custom renderer:
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) {
return new SizeRequest(Size.Zero, Size.Zero);
}
To fix the rotate problem you need to use the NativeView.Bounds when you create the UIWebView.
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespaceMobile.App.iOS
{
public class CustomWebViewRenderer : ViewRenderer<CustomWebView, UIWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new UIWebView(NativeView.Bounds);
webView.ShouldStartLoad += HandleShouldStartLoad;
webView.AutoresizingMask = UIViewAutoresizing.All;
webView.ScalesPageToFit = true;
SetNativeControl(webView);
webView.LoadRequest(new NSUrlRequest(new NSUrl(Element.Url)));
}
}
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
return new SizeRequest(Size.Zero, Size.Zero);
}
}
}
I'm trying from hours/days to get a file which is placed into the PCL part
I saw some examples which using BaseURL but I want to make something cross platform and I can't found how to implement it onto UWP..
So I'm trying to get my local file's URL. For Images, I'm using ImageSource.FromResource("Gif.example.gif") but it doesn't work..
I also tried GifSource = new Uri(ImageSource.FromResource("Gif.example.gif").ToString()); but.. Nothing !
There is my custom control:
public class Gif : WebView
{
public static readonly BindableProperty GifSourceProperty =
BindableProperty.Create(nameof(Uri), typeof(string), typeof(Gif), null);
public string GifSource
{
get { return (string)GetValue(GifSourceProperty); }
set { SetValue(GifSourceProperty, value); }
}
Action<string> action;
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void Cleanup()
{
action = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
}
Thank for help !
To get the image from the PCL-project you must use the full path (with the namespace) to the image.
In your case: var src = ImageSource.FromResource("GifProject.Gif.example.gif");
And be sure that the "Build Action" of your file is set to "Embedded Resource".
You can extend this with reflection, when you don't want to provide the namespace directly.
You can find more infos on how to deal with embedded images on the xamarin developer page.