Поделиться через


Ten Things You Need to Know About WebView

 

Hi - I am Matt Small, a Sr. Escalation Engineer on the Microsoft Windows Store Developer Solutions team.  I have been working on Windows 8 since before the Release Preview, and I have spent many hours working in the Store forums, primarily in the C# forum.  I’ve seen a *lot* of posts on the C# forum regarding the WebView control and thought it would be good to compile the information we’ve collected regarding Webview. Since this article is rather long, I've indexed it for you:

 

  1. WebView is not a general-purpose browser
  2. WebView always renders on top of XAML
  3. WebView doesn’t do Flash. Or Silverlight. Or PDF. Or any other ActiveX control or plugin.
  4. How to invoke Javascript inside the displayed webpage of a Webview
  5. How to receive information from the WebView
  6. How to inject javascript into a WebView page
  7. How to clear the WebView cache
  8. How to embed a font into your app to be used by WebView
  9. Launching other apps from a link inside WebView
  10. How to get rid of those annoying JavaScript exceptions when debugging

  

  1. WebView is not a general-purpose browser

    The WebView control is intended to allow a Store app developer to embed some part of the web inside the application, but should not be added to an application to allow browsing to any site on the Internet - it should be used to link specifically to pages hosted on your own website for the purposes of being displayed within your Store application.

    For example:  if you have content that you think may change quite often, it could be easier to place this information in a WebView control rather than update your application via the store. 

    However, what it is not intended to be is a portal from a Store app into a Web app.  In fact, your Store app will be rejected from listing in the Store if this is your primary use of the WebView control.

    Aside from that, you are going to find that some things simply don’t work the way that they do in the full Internet Explorer browser. It’s not that these changes are intentional; it’s that this is a different (but similar) codebase – it is not IE.  In fact, the documentation is clear about the limitations of this control:

    WebView always uses Internet Explorer 10 in document mode. Additionally, WebView does not currently support HTML5, AppCache, IndexedDB, programmatic access to the Clipboard, or geo location, and supports only the Document Object Model (DOM) properties that are supported in Windows Store apps using JavaScript.

    As a part of your overall application, the content displayed inside the WebView control should conform to the Webview’s limitations.

  2. WebView always renders on top of XAML

    Again, the documentation is clear on this, but it bears repeating since many (including me) have been caught by this particular aspect of the WebView:  Any element that would normally overlap the space occupied by the WebView and thus cover or partially cover that area, will find that the WebView will always be on top of the XAML - this is called an "Airspace" issue.  This is because the WebView is not subclassed from the Control object, and it is drawn separately from the rest of the XAML space. Using this code, if WebView were a regular control, we would see it behind the TextBox:

     <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
     <StackPanel>
     <Grid>
     <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/>
     <TextBox Width="800" Height="30" Text="This control would be in front of the WebView if WebView were a normal control."/>
     </Grid>
     <Button x:Name="MyButton" Margin="10" Content="Invoke the WebViewBrush control" Click="MyButton_Click_1" HorizontalAlignment="Center"/>
     </StackPanel>
     </Grid>
    

    You can see the problem in this image:

    There is a workaround to this this issue, and that is to use the WebViewBrush control.  In a nutshell, the WebViewBrush copies the content of an existing WebView control, and displays it inside a Rectangle object – thus allowing other XAML content to render over it.  Here's how we can show the contents of the Webview on top of the TextBox:

    Add a Rectangle object to the XAML:

     <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
     <StackPanel>
     <Grid>
     <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/>
     <Rectangle x:Name="MyRectangle"/>
     <TextBox Width="800" Height="30" Text="This control would be in front of the WebView if WebView were a normal control."/>
     </Grid>
     <Button x:Name="MyButton" Margin="10" Content="Invoke the WebViewBrush control" Click="MyButton_Click_1" HorizontalAlignment="Center"/>
     </StackPanel>
     </Grid>
    

    Inside the Click event handler of the button:

     private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     WebViewBrush MyWebViewBrush = new WebViewBrush();
     MyWebViewBrush.SourceName = "MyWebview";
     MyWebViewBrush.Redraw();
     MyRectangle.Fill = MyWebViewBrush;
     MyWebview.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
     }
    

    Now when we click the button, we will see the TextBox over what was over the WebView.  Only thing, is, the WebView itself is Collapsed, while the Rectangle containing the WebViewBrush is displayed.

  3. WebView doesn’t do Flash. Or Silverlight. Or PDF. Or any other ActiveX control or plugin.

    ActiveX controls have made Internet Explorer an incredibly useful tool for applications that need to be widely distributed.  However, it has also been an attack vector used by malware developers.  In the development of the WinRT APIs, it was decided that the WebView control – like the Immersive Internet Explorer – would not host any ActiveX controls, which is how older versions of IE hosted Flash and Silverlight, for safety and performance reasons. Additionally, although the RTM version of IE10 includes Flash as a built-in feature, this did not make it into the WebView control.

  4. How to invoke Javascript inside the displayed webpage of a Webview

    Now that we understand that the content of the WebView should be a part of the app experience, we ought to know how to manipulate the HTML so it is useful to the greater application.  Let’s try this out:

    We create an HTML page that contains a Javascript function:

     <!DOCTYPE html>
    <html lang="en" xmlns="https://www.w3.org/1999/xhtml">
    <head>
     <meta charset="utf-8" />
     <title>Matt's Webview Content Page</title>
     <script lang="en-us" type="text/javascript">
     function TimeUpdate() {
     var TimeTextbox = document.getElementById("TheTime");
     TimeTextbox.value = new Date().toTimeString();
     }
    
     </script>
    </head>
    <body>
     <h2>Matt's Webview Content Page</h2>
     <h5>The current time is: <input type="text" Id="TheTime" /> </h5>
     <button onclick="TimeUpdate()">Update the time!</button>
    </body>
    </html>
    
    

    Now we create a XAML page that contains a WebView which loads the HTML page:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/> <Button x:Name="MyButton" Margin="10" Content="Invoke the TimeUpdate Javascript function from C# using this button" Click="MyButton_Click_1" HorizontalAlignment="Center"/> </StackPanel> </Grid>`` 

    Notice that the source of the WebView uses the “ms-appx-web:///” protocol and that there are *three* forward slashes used for this.

    Finally, create the code that calls into the Javascript from the C# page:

     private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     MyWebview.InvokeScript("TimeUpdate", null);
     }
    
    

    The Button in the XAML page invokes it’s Click event handler, which calls the InvokeScript method on the WebView control.  The InvokeScript method has two parameters: the name of the Javascript function to call, and an array of strings to be used as parameters to be passed to the function.

    This is what you’ll see when we run this code:

     

  5. How to receive information from the WebView

    Just as important as being able to invoke operations in the webpage is the ability to retrieve information from the webpage for use in your C# code.  Here is how it’s done:

    First, we need to way for the webpage to tell our Store app what it needs to know.  This is done using the window.external.notify(string) function.  I modified the TimeUpdate function to look like this:

     

      function TimeUpdate() {
     var TimeTextbox = document.getElementById("TheTime");
     TimeTextbox.value = new Date().toTimeString();
     window.external.notify(TimeTextbox.value);
     }
    
    

    Next, I added the event declaration to the XAML, and also added a new textbox by which I can see the information passed to the C# code:

     <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html" ScriptNotify="MyWebview_ScriptNotify_1"/>
     …
     <TextBox x:Name="MyTextBox" Width="200"/>
    
    

    Finally, I added the ScriptNotify event handler method:

    private void MyWebview_ScriptNotify_1(object sender, NotifyEventArgs e) { MyTextBox.Text = e.Value; }When I execute the code and click the “Update the Time!” HTML button, I receive the information as though my code were executing as part of the webpage:

  6. How to inject javascript into a WebView page
    Now that it’s possible to send and receive information into a webpage hosted by WebView, we need to consider the fact that there may be situations where we want to retrieve information from a webpage where we don’t own the content.  What we need to do in this situation is inject some code into the webpage for our own use.

    First, in order to inject the content, I can’t simply set the source of the WebView to that page – I won’t have a way to modify the page’s HTML source.  I need to download the content of the page into a string.  For simplicity’s sake, I will continue to use the same code that I have been using, although in a different way. Here’s the psuedocode:

    1. Download/obtain the HTML source of the page into a string.
    2. Find an insertion point for your new script to be put into the page.
    3. Insert your new script into that page.
    4. Set the WebView source to that string using the NavigateToString method.

    Here it is in action:

    Remove the source attribute from the WebView object in the XAML page.  This is what I have left:

    <WebView x:Name="MyWebview" Width="500" Height="500" ScriptNotify="MyWebview_ScriptNotify_1"/>

    Now perform the magic of obtaining the string of the webpage and modifying it:

     async protected override void OnNavigatedTo(NavigationEventArgs e)
     {
     Windows.Storage.StorageFile MyWebPageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///HTMLPage1.html"));
     string MyWebPageString = await FileIO.ReadTextAsync(MyWebPageFile);
     string ScriptTagString = "<script lang=\"en-us\" type=\"text/javascript\">";
     int IndexOfScriptTag = MyWebPageString.IndexOf(ScriptTagString);
     int LengthOfScriptTag = ScriptTagString.Length;
     string InsertionScriptString = "function SayHelloWorld() { window.external.notify(\"Hello World!\");} ";
     MyWebPageString = MyWebPageString.Insert(IndexOfScriptTag + LengthOfScriptTag + 1, InsertionScriptString);
     MyWebview.NavigateToString(MyWebPageString);
     }
    
    

    Lastly, I changed the InvokeScript method to call my new Javascript function:

     private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     MyWebview.InvokeScript("SayHelloWorld", null);
     }
    
    

    Now, when I run this code, I have two functions:

    1. The original HTML “Update the time!” button, which will update the time in the textbox on the webpage as well as the XAML textbox.

    2. The XAML “Invoke the TimeUpdate Javascript function…” button, which invokes the “HelloWorld” function, and updates only the XAML textbox.

      You can download all three complete projects in the WebviewJavascript.zip file at the bottom of this post.

  7. How to clear the WebView cache

    Unfortunately, there is no programmatic way to clear the WebView cache from a Store app, and neither is there a nice UI-style way (i.e. a button).  However, it can be achieved by going to this path at a command prompt:

    C:\Users\<username>\AppData\Local\Packages\<PackageName>\

    Now run the following command:

    Attrib –H –S /S /D

    This removes the hidden and system attributes from files and folders in that location.  If successful, you may see the following folder structure:

    You can then delete the Cache, Cookies and History for the embedded WebView control in this app.

  8. How to embed a font into your app to be used by WebView

    This works for ttf fonts. Use it inside your CSS file or <style> tag.

    @import url(ms-appx:///<fontname>.ttf)

    (10/24/12) OK, you got me.  It turns out I was wrong about how this works, so I've written a new post describing how to actually get fonts embedded in your webview.  I hope this helps.

     

  9. Launching other apps from a link inside WebView
    As with all Store applications, there is no way to directly open a specific application.  However, the concepts of default Protocol Handlers and default Extension handlers work just as well for Webview content. Links inside an application will open up using the default protocol handler or extension handler for that type. For example, when I click on a file with the extension .PDF, it automatically opens the built-in document viewer. 

  10. How to get rid of those annoying JavaScript exceptions when debugging

    When you are debugging your WebView-enhanced application, and the webpage hosted inside the WebView has a JavaScript exeception, it will throw up a horrible Debugger dialog like this one:

    It's not really a helpful dialog in the context of your C#/XAML application. You can get rid of this annoying box by disabling Script Debugging in Visual Studio:

    Debug > Options and Settings > Debugging > Just-In-Time > Uncheck "Script":

    You will no longer be bothered by that again.

I hope that this information is useful to you while you are developing your Windows Store XAML/C# application.  Comments are encouraged, and feel free to tweet to me at WinDevMatt.  Also, this blog's hashtag is #WSDevSol.

WebviewJavascript.zip

Comments

  • Anonymous
    October 21, 2012
    Hello, Matt, Can't you provide us a buildable sample of font embedding? I've never succeeded to embed my fonts into my WebView till now.

  • Anonymous
    October 23, 2012
    Hi Nagata - I've written a new post which correctly describes the methods to use to embed fonts inside your Store app.  blogs.msdn.com/.../about-webview-and-embedded-fonts.aspx

  • Anonymous
    November 01, 2012
    There has to be some means of clearing (or disabling) cookies programatically, or this thing is near useless. I am using Facebook oAuth login from my app, which works well, but once logged in there is no way to log out (Facebook does not provide logout as part of its non-javascript API). Help! ps I hate first versions of MS APIs/frameworks, always half baked, rushed with important stuff missing :(

  • Anonymous
    November 24, 2012
    I've spent a couple of days trying to use it to simply display a thumbnail of a website in my application.   I'd rather do this than to retrieve the thumbnail from any thumbnailing services around... My problem is that it is too functional.  I cannot find a way tu put something on top of it so it doesn't react. I.e.: Scroll, capture mouse, navigate, etc... About to give up  :/

  • Anonymous
    November 25, 2012
    Why not use a WebViewBrush for your thumbnails?

  • Anonymous
    December 29, 2012
    Hi Matt, Very disappointing to see the limitations of WebView control. The windows phone WebBrowserControl is way better than WebView. It actually supports events like Navigating. It also supports navigator.geolocation. I think Microsoft is making a mistake by restricting WebView in this way. I believe that an app that uses push notifications and access to devices like camera, accelerometer on top of a WebBrowser control gives US the developers an extremely attractive way of building our apps/webapps once and use them in both windows phone and windows 8. We wouldn't even have to stop at the Microsoft stack, we can use this type of shell applications to deploy to iOS. We build our web apps that work in any browser and wrap them with a nice shell native app that provides extra features ( Push Notifications ). Extremely powerful and cost effective. My suggestion is for Microsoft to reconsider and give US the developers a fully functional IE10 experience within the WebView control... or bring the WebBrowser control to Windows 8... Namaste, Hector

  • Anonymous
    January 07, 2013
    Hi Matt,                  Right now i am working with WebView control, can you explain how to change my font present in WebView control by accessing a button,     means when i fire a button it should be change according to event either Increase or Decrease, Thank u...

  • Anonymous
    January 10, 2013
    Is there a way to get the selected content in the webview?

  • Anonymous
    January 14, 2013
    It possible to embed Internet Explorer inside the winrt application and use its capabilities? I mean there is possible to have on windows store app a functionality similar with the in-app browser that exists on ios.

  • Anonymous
    January 22, 2013
    The comment has been removed

  • Anonymous
    February 05, 2013
    Excellent  blog post Matt solved almost every issue in my windows store app The only issue left is that I am unable to alter the dimensions of an iframe in the web view control

  • Anonymous
    March 10, 2013
    Does the same thing go for Windows Phone 8?

  • Anonymous
    March 13, 2013
    Johnson - I think anything you can do in javascript can be done in the Webview.  Something I learned recently is that you can invokescript ("Eval",new string()["function..."]); and it will run as though it were a part of the javascript downloaded from the server. Oskar - this post is specific to Windows Store applications, but I believe most of it will be the same for the WebBrowser control

  • Anonymous
    May 10, 2013
    Nice tutorial and very useful

  • Anonymous
    July 22, 2013
    I want to use the stop method of webview and I did like this " webview.stop()" but it says error( some reference missing). what should I do?

  • Anonymous
    July 28, 2013
    @Ronish: WebView.Stop is only supported after Windows 8.1, could you be compiling for 8? See msdn.microsoft.com/.../windows.ui.xaml.controls.webview.stop.aspx.

  • Anonymous
    October 28, 2013
    Very nice one... Is it possible to Code the x-ms-webview in HTML/JS also like with XAML? I have problems with the changes of the Control with Windows 8.1 stackoverflow.com/.../disable-zoom-in-x-ms-webview-html-control-win-8-1-with-javascript-not-by-css social.msdn.microsoft.com/.../disable-zoom-in-xmswebview-html-control-win-81-with-javascript-not-by-css-content

  • Anonymous
    December 08, 2013
    Hi matt I wanted to ask something about the error .......whenever i am trying to navigate to any page on webview control I am getting this error..... "An unhandled exception ("navCancelInit" is undefined) occured in WebView.exe [3732]. " Although when I assign the page source directly in a string (for ex: respString) and use navigatetostring(respString) in webview, it displays the content.... but if i navifgate to the same page after login, it gives the above mentioned exception... please suggest what to do ?

  • Anonymous
    December 19, 2013
    Very nice lecture. Now I can solve my problem.

  • Anonymous
    December 29, 2013
    How to get click event in HTML element.. I have only HTML page which is downloaded into my application APPX folder and now I am accessing those offline HTML page in inside the page I have a button once I click on button I am not able to get any event handler for that.. I have tried with script.nofification but this event is not working again I don't have any control for HTML what ever I have to do with Native App and inject the script.. let me know the good solution for that..?

  • Anonymous
    February 27, 2014
    We're launching an API that will act as a URL lookup service so developers can automatically protect users from malware and phishing sites inside the WebView. Be delighted to share more with you paul@metacert.com thanks.

  • Anonymous
    March 31, 2014
    Hi All, I need a little help. i am opening google map in my webview by providing the source lat long and destination lat long and the mid poin lat long alos. this is giving me the directions in webview. At the top one map button is there in webview. when i am clicking on that button , all ht location with the route drawn is coming, i want to fetch this url which is being loaded now itself when i have clicked on the map icon.

  • Anonymous
    April 27, 2014
    Webview can't view PDF files.... what a joke. PDF files can be opened INSIDE iOS apps because PDF is built into the OS. What can't I do this in Windows Phone?

  • Anonymous
    July 21, 2014
    This is really helpful.Can you please update this blog in context of Windows 8.1 changes or post a new one?

  • Anonymous
    October 09, 2014
    Hi I have found one good example here <a href="androidexample.com/.../index.php >Open File Chooser With Camera Option In Webview File Option</a>

  • Anonymous
    December 16, 2014
    Hi Matt, Thanks for your article. I am developing a mobile Windows 8.1 app and Am using Webview to render HTML. How can I access touch events in the Webview as Webview doesn't provide support for these events. Any suggestion/alternative way for this will be a great help.

  • Anonymous
    December 28, 2014
    Hi, Can we show sharepoint sites inside webview?

  • Anonymous
    September 13, 2015
    i have simple step for Open File Chooser With Camera Option In Webview File Option in this link http://androidexample.com/

  • Anonymous
    October 05, 2015
    The comment has been removed

  • Anonymous
    January 17, 2016
    Hi, I have a problem here and i need your help. I loaded a html start page. It include some javascript files. The page can load these external js files properly. The start page navigate to another page ( still in same local stream uri), i call it is secondary page. The secondary page include some javascript files too. But it can not load any js file. I dont know why, maybe it blocked by the browser because main page is the start page. Do you have any ideas about this ?

  • Anonymous
    March 06, 2016
    How to set the web view content horizontally centered?