Hi all,
I have a custom renderer for my webview with a custom webview delegate in ios.
My Problem is, that I often got the NSError "0" - "The operation couldn’t be completed. (Invalid .ctor used error 0.)"
I spend a lot of time in debugging, but I'am not able to solve it.
I know, I got the error if there are much HTML and Javascript.
In my Example: Article Lists up to 60 articles per page -> Error
Articles up to 10 per page -> Success.
Problem is: Not all javascript will execute, if I got the error. All HTML is available. So it should be a javascript problem? Any Javascript limitation?
I got the error via: UIWebViewDelegate -> LoadFailed(UIWebView webView, NSError error)
Does anybody have a solution or idea?
public class ExtendedWebViewDelegate : UIWebViewDelegate
{
protected ExtendedWebViewRenderer extendedWebViewRenderer;
protected ExtendedWebView extendedWebView;
public ExtendedWebViewDelegate(ExtendedWebViewRenderer renderer, ExtendedWebView extendedWebView) {
this.extendedWebViewRenderer = renderer;
this.extendedWebView = extendedWebView;
}
/// <summary>
/// Shoulds the start load and send headers to shop and check for custom requests
/// </summary>
/// <returns><c>true</c>, if start load was shoulded, <c>false</c> otherwise.</returns>
/// <param name="webView">Web view.</param>
/// <param name="request">Request.</param>
/// <param name="navigationType">Navigation type.</param>
public override bool ShouldStartLoad(UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType)
{
//return false to cancle the request, if custom request execute successfull
if (this.HandleCustomWebRequests(request, navigationType) == true) {
return false;
}
//fire tc custom event fpr load start
this.extendedWebView.OnStartLoading(this, new System.EventArgs());
// Set cookies here
var cookieJar = NSHttpCookieStorage.SharedStorage;
cookieJar.AcceptPolicy = NSHttpCookieAcceptPolicy.Always;
//set up the new cookies
var jCookies = extendedWebView.Cookies.GetCookies(request.Url);
IList<NSHttpCookie> eCookies =
(from object jCookie in jCookies
where jCookie != null
select (Cookie)jCookie
into netCookie
select new NSHttpCookie(netCookie)).ToList();
//sets the new cookies to the storage
NSHttpCookieStorage.SharedStorage.SetCookies(eCookies.ToArray(), request.Url, request.Url);
//adds the needed headers for a app call, if not set
if (request.Headers.ContainsKey(new NSString("TC-APP-Request")) == false)
{
var copy = request.MutableCopy() as NSMutableUrlRequest;
copy.TimeoutInterval = 50;
if (copy.Headers == null)
{
copy.Headers = new NSMutableDictionary();
}
NSMutableDictionary dic = new NSMutableDictionary();
//var geoLocator = new GeoLocation();
//string position = geoLocator.GetPositionString();
int SystemVersion = Convert.ToInt16(UIDevice.CurrentDevice.SystemVersion.Split('.')[0]);
dic.Add(new NSString("TC-APP-Request"), new NSString("true"));
//dic.Add(new NSString("TC-APP-GeoData"), new NSString(position));
dic.Add(new NSString("TC-APP-OS-Name"), new NSString("iOS"));
dic.Add(new NSString("TC-APP-OS-Version"), new NSString(SystemVersion.ToString()));
copy.Headers = dic;
copy.CachePolicy = NSUrlRequestCachePolicy.UseProtocolCachePolicy;
request = copy;
webView.LoadRequest(request);
return false;
}
return true;
}
/// <summary>
/// gives header to event if load finished
/// </summary>
/// <param name="webView">Web view.</param>
public override void LoadingFinished(UIWebView webView)
{
//fire tc custom event
var responseHeaders = GetResponseHeader(webView);
this.extendedWebView.OnFinishedLoading(this, new TC.Events.EventArgs.WebViewFinishedLoadingEventArgs(responseHeaders));
return;
}
/// <summary>
/// Gets the response header.
/// </summary>
/// <returns>The response header.</returns>
/// <param name="webView">Web view.</param>
protected Dictionary<string, String> GetResponseHeader(UIWebView webView) {
var headers = new NSDictionary();
try
{
var cache = NSUrlCache.SharedCache.CachedResponseForRequest(webView.Request);
var response = (NSHttpUrlResponse)cache.Response;
headers = response.AllHeaderFields;
} catch (NullReferenceException exception) {
var nsError = new NSError();
this.LoadFailed(webView, nsError);
Console.WriteLine(exception.ToString());
return new Dictionary<string, String>();
} catch (System.Exception e) {
Console.WriteLine(e.ToString());
return new Dictionary<string, String>();
}
Dictionary<string, String> convertedHeaders = new Dictionary<string, String>();
foreach (KeyValuePair<NSObject, NSObject> header in headers)
{
convertedHeaders.Add(header.Key.ToString(), header.Value.ToString());
}
return convertedHeaders;
}
/// <summary>
/// Loads the failed.
/// </summary>
/// <param name="webView">Web view.</param>
/// <param name="error">Error.</param>
public override void LoadFailed(UIWebView webView, NSError error)
{
if (error.Code == -999) {
return;
}
if (error.Code == 0) {
return;
}
//fire tc custom event
this.extendedWebView.OnFailedLoading(this, new System.EventArgs());
}
/// <summary>
/// Handles the custom web requests (like: app://myFunction?test=test&test1=test). Return false, if request is no custom request or true, if the custom request executeded successfull
/// </summary>
/// <returns><c>true</c>, if custom web requests was handled, <c>false</c> otherwise.</returns>
/// <param name="request">Request.</param>
/// <param name="navigationType">Navigation type.</param>
protected bool HandleCustomWebRequests(NSUrlRequest request, UIWebViewNavigationType navigationType) {
//check for other navigation types
if (navigationType == UIWebViewNavigationType.Other)
{
string scheme = request.Url.Scheme; //like app
//if scheme is app, handle the request!
if (scheme == "app")
{
string webParams = request.Url.Query; //like test=tst&test2=232
string javascriptFunction = request.Url.Host; //like myFunction
string[] paramPairs = webParams.Split('&');
Dictionary<string, string> convertedParams = new Dictionary<string, string>();
foreach (string pair in paramPairs)
{
string[] elements = pair.Split('=');
if (elements.Length == 2)
{
if (convertedParams.ContainsKey(elements[0]))
{
convertedParams[elements[0]] = elements[1];
}
else
{
convertedParams.Add(elements[0], elements[1]);
}
}
}
var executeableObject = (TC.Core.JavascriptInvoker)TC.Core.Base.GetInstance("TC.Custom.iOS.JavascriptInvokers." + javascriptFunction);
if (executeableObject == null) {
throw new TC.Exception.JavascriptInvokeException("JAVASCRIPT_FUNCTION_INVALID", javascriptFunction, convertedParams);
}
executeableObject.Initialize(javascriptFunction, convertedParams);
executeableObject.RunAsync();
return true;
}
}
return false;
}
}
Error Object: