Search code examples
xamarin.formswebviewxamarin.ioswkwebview

Xamarin Forms: Exactly how specify local filename for iOS WebView WebViewSource


I have a Xamarin Forms Webview that is successfully displaying a local "hard-coded" file on Android and UWP, but I can't get it to work on iOS. I have done the usual searches: there is help out there for Web URL's and for HTML embedded in the C# code, but I cannot find anything that solves my problem: exactly how do I specify the filename and where do I put the HTML files?

I have pasted the XAML below. I have the GettingStartedWizardWebPage folder both (temporarily, until I figure out what works) in the main iOS project folder and also under iOS Resources. I have tried specifying the file name both with and without a preceding ///. Is there some other prefix I should be using, like file: for Android or ms-appx-web: for UWP? I have the HTML files with BuildAction BundleResource and I have tried all of the Copy variations (but there are a lot of combinations of name prefix, Copy options and file location and I have probably not tried every combination).

Specifically, I have read https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/webview?tabs=windows#local-html-content and followed the directions there to the best of my ability. For Android I coded Value="file:///folder/page" and it works. For UWP I coded Value="ms-appx-web:///folder/page" and it works. What do I code for Value= for iOS? What is the "base URL"? Is the tutorial trying to say that I need code to determine the Base URL?

It doesn't crash or give any errors; it just displays a blank window. The second row of the grid shows up and displays where I would expect it to be.

I have read the discussions of UIWebView and WKWebView but I don't get what exactly I should be doing. AFAIK I would be willing to use either.

VS 2022 Community 17.4.0 Preview on Windows 64 Pro, with both Cloud iPhone 13 Simulator and real iPhone 5.

<Grid RowDefinitions="*,AUTO" Margin="6, 6, 6, 6" x:Name="MainContent">
    <WebView  WidthRequest="1000" HeightRequest="1000" Grid.Row="0" >
        <WebView.Source>
            <OnPlatform x:TypeArguments="WebViewSource">
                <OnPlatform.Platforms>
                    <On Platform="Android" Value="file:///android_asset/GettingStartedWizardWebPage/WebPage.html" />
                    <On Platform="UWP" Value="ms-appx-web:///GettingStartedWizardWebPage/WebPage.html" />
                    <On Platform="iOS" Value="///GettingStartedWizardWebPage/WebPage.html" />
                </OnPlatform.Platforms>
            </OnPlatform>
        </WebView.Source>
    </WebView>
    ...

Solution

  • Okay. I solved this. The linked tutorial is less than forthcoming on one point, and wrong on the details of others.

    I. You just cannot do this for iOS in XAML. For UWP and Android there is a fixed, short "prefix" (base URL) that goes on the front of the filename as discussed in the article and as shown in my XAML above. For iOS it is a 100-or-so character string that is very application and device dependent, so you can't hard-code it in the XAML. You have to use C# code with a dependency routine -- as shown in the tutorial, but not emphasized as explicitly as I just did.

    II. The prefixes shown in the tutorial are wrong, or at least won't work correctly in device-independent code. NSBundle.MainBundle.BundlePath on iOS returns a pathname without a terminating slash, so (a.) you want a leading slash on the hard-coded "low-order" part of your filename; and (b.) therefore the Android routine wants to return "file:///android_asset" (without the trailing slash shown in the tutorial) and the UWP routine wants to return "ms-appx-web://" with two trailing slashes, not the three shown in the tutorial -- which seems odd, but your hard-coded slash will make for three total.

    III. Contrary to what the tutorial says, you do NOT have to read the file yourself and then deal with special considerations so that the HTML page can access linked objects. Just put BaseUrl + "Your hard-coded filename starting with a slash" into WebView.Source and WebView will read the file (on all three platforms) including any linked images and so forth.

    IV. Put the HTML pages in the main iOS application folder, not under Resources. That is the path that NSBundle.MainBundle.BundlePath returns.