Forum Xamarin.iOS

Displaying local content in WKWebView fails on physical device

MichaelMcCloyMichaelMcCloy USMember ✭✭

I'm using a HybridWebView that uses a WKWebView on iOS to render some HTML loaded from a string. Image references are downloaded locally and the references updated to that path. This used to work but after updating VS and xamarin forms, it has stopped working on physical devices - simulator works fine. I feel like it's either a permission thing or something changed with the paths. Maybe someone has some insight into this.

Here's the relevant code:
CacheImage() takes the source image and writes it to local storage, returning the local path. I then swap the img src tag to use this path.

public string CacheImage(string imgURl)
        {
            string newFilename = Guid.NewGuid().ToString() + Path.GetExtension(imgURl);
            string localPath = "";

            var webClient = new WebClient();

            var url = new Uri(imgURl);
            byte[] bytes = webClient.DownloadData(url);
            string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            string localFilename = newFilename;
            localPath = Path.Combine(documentsPath, localFilename);
            File.WriteAllBytes(localPath, bytes); // writes to local storage

            webClient.DownloadDataAsync(url);

            return localPath;
        }

I've tried pre-pending file:// and it works either way in simulator, but fails either way on device. I also tried setting up a simple anchor href to link to the file - it navigates there on simulator, but does nothing on the device.

The paths do vary for simulator and the device:
**Simulator sample path: **
/Users/mmccloy/Library/Developer/CoreSimulator/Devices/3FF36C05-D12F-4AF0-8980-F5ED8E11B521/data/Containers/Data/Application/1C073D1D-6635-4FEF-8A1C-1E1CDA02A161/Documents/filename.png

**Device sample path: **
/var/mobile/Containers/Data/Application/FD4933A1-C2B6-4695-B175-FF4737526730/Documents/filename.png

I also noticed when I download the package from the device, the phhysical path within the package is:
myapp.xcappdata/AppData/Documents/filename.png
The file is there, but I wasn't sure about the AppData part, so i tried forcing it in there, but no luck.

Many thanks in advance for any ideas!

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    I saw you downloaded the image from remote. Can you make sure this action has completed when returning the file path?
    A newer API called HttpClient is being used for rest API. You could try this approach:

    public async Task<string> CacheImage(string imgURl)
    {
        string newFilename = Guid.NewGuid().ToString() + Path.GetExtension(imgURl);
        string localPath = "";
    
        var client = new HttpClient();
        var response = await client.GetAsync(imgURl);
        var bytes = await response.Content.ReadAsByteArrayAsync();
    
        string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
        string localFilename = newFilename;
        localPath = Path.Combine(documentsPath, localFilename);
        File.WriteAllBytes(localPath, bytes); // writes to local storage
    
        return localPath;
    }
    

    This method is awaitable and the result will be returned after the request finished.

  • MichaelMcCloyMichaelMcCloy USMember ✭✭

    Thanks so much for the reply! I am trying this but unfortunately it's the same behavior. I do, however, like that this works in my shared library so I don't need to have separate code in iOS and Android. I checked in the debugger with File.Exists() and it's saving the file, it must be an issue with the web view. What's strange is that within the same web view I reference JS files and such, and those appear to work, but anything trying to reference this path seems to fail:

    /var/mobile/Containers/Data/Application/F14441B1-5E69-4E6B-B18C-BBC9C5343A5D/Documents/04aa3ab9-5947-4576-bbd2-2d8416317070.jpg

  • MichaelMcCloyMichaelMcCloy USMember ✭✭

    I may be onto something. So after further testing, it works fine on android, just not physical ios devices. I'm using a hybridwebview, modified so I can send JS messages to/from c#. When I load the path, I'm passing in a directory which I presume is like the working path. Perhaps on the device this is different now? I tried

     webView.LoadHtmlString = (val) =>
                        {
                            string contentDirectoryPath = Path.Combine(NSBundle.MainBundle.BundlePath, "Content/");
                            Control.LoadHtmlString(new NSString(val), new NSUrl(contentDirectoryPath, true));
                            return "";
                        };
    

    I also tried passing in different/multiple paths, but no change in result:

    string contentDirectoryPath = Path.Combine(NSBundle.MainBundle.BundlePath, "Content/");
                          string contentDirectoryPath2 = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                          Control.LoadHtmlString(new NSString(val), new NSUrl(contentDirectoryPath, true, new NSUrl(contentDirectoryPath2, true)));
    

    I must be missing something...

  • LandLuLandLu Member, Xamarin Team Xamurai

    I'm curious about the api you are using here.
    LoadHtmlString only contains two parameters here:
    https://docs.microsoft.com/en-us/dotnet/api/webkit.wkwebview.loadhtmlstring?view=xamarin-ios-sdk-12
    And you could set the second parameter like:

    var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
    string localPath = Path.Combine(documentsPath, "image.png");
    NSUrl fileUrl = new NSUrl(localPath, false);
    
    // You could get the URL from your request method
    Control.LoadHtmlString(new NSString(), fileUrl.RemoveLastPathComponent());
    
  • MichaelMcCloyMichaelMcCloy USMember ✭✭

    I'm actually on 13.18.2.1. The extra NSUrl is going into the second NSUrl's constructor as parameter relativeToUrl.

    The constructor is like this:
    NSUrl(String, Boolean, NSUrl)
    per:
    https://docs.microsoft.com/en-us/dotnet/api/foundation.nsurl.-ctor?view=xamarin-ios-sdk-12#Foundation_NSUrl__ctor_System_String_System_Boolean_Foundation_NSUrl_

    I'm not sure if using the relativeToUrl is the right way to do it, but I've actually tested with just passing one normal URL in and I tried both the BundlePath and the SpecialFolder.Personal individually and it didn't correct the problem.

  • LandLuLandLu Member, Xamarin Team Xamurai

    Could you please share a small sample here to specify your issues?

  • ronakshethiaronakshethia USMember ✭✭

    I am facing similar issue the documents,images,mp4 are rendering well on webview when I am testing it on emulator but fail to render on real device, does any one found solution for it ?

Sign In or Register to comment.