0

I am trying run a local server for a Xamarin.Forms WebView. This is to get around CORS, and so the html can be structured like a normal page. This works for UWP and iOS, but Android always comes up with an ERR_CONNECTION_REFUSED. Some further details/things I have tried:

  • The App is running it's own server, so it is not the case of trying to access a server on a separate device.
  • Internet permission is enabled.
  • The path to the files do exist, otherwise the Webserver would fail to start.
  • Link to the local server nuget package: https://github.com/unosquare/embedio

Below is an outline of the code I'm using. In practise, I'm using a custom renderer, injecting Javascript to access platform features, etc. but this should simplify it:

The class that creates and starts the WebServer with EmbedIO:

public class LocalWebServer: IDisposable
{
    public static string Url = "http://localhost:8787/";

    private readonly string _filePath;
    private WebServer _server;

    public LocalWebServer(string filePath)
    {
        _filePath = filePath;
    }

    public void StartWebServer()
    {
        _server = new WebServer(Url);

        _server.RegisterModule(new LocalSessionModule());
        _server.RegisterModule(new StaticFilesModule(_filePath));
        _server.Module<StaticFilesModule>().UseRamCache = true;
        _server.Module<StaticFilesModule>().DefaultExtension = ".html";
        _server.Module<StaticFilesModule>().DefaultDocument = "index.html";
        _server.Module<StaticFilesModule>().UseGzip = false;



        Task.Factory.StartNew(async ()=>
        {
            Debug.WriteLine("Starting Server");
            await _server.RunAsync();
        });
    }

    public void Dispose()
    {
        _server?.Dispose();
    }
}

Code which starts the server and displays the webview:

    public App()
    {
        InitializeComponent();

        //Create and display a Webview
        _webView = new WebView();
        MainPage = new ContentPage()
        {
            Content = _webView,
        };
    }

    protected override async void OnStart()
    {
        //Service which can initialize app for first time use, and stores
        //the folder location for the html page on each platform
        var htmlService = DependencyService.Get<IHandleHtmlContentService>();

        //Local webserver
        var localWebServer = new LocalWebServer(htmlService.DirectoryPath);

        //This is just a function that loads the html content from the
        //bundle resource or assets into a folder. Will only really
        //matter during the first time the App boots up.
        await htmlService.InitializeHtmlContent();

        //Start the Webserver
        localWebServer.StartWebServer();

        //Navigate to the webserver
        _webView.Source = LocalWebServer.Url;
    }

I'v been bashing my head on this for a while, so any help would be appreciated. If you need any more details, let me know.

Sonic1015
  • 55
  • 1
  • 16

1 Answers1

4

Turns out, Android has no concept of "localhost" (at least from what I can read). Instead, I need to find the IP Address of my device. I have done this with the following code:

public class LocalWebServer: IDisposable
{
    public readonly string Url;

    ...

    public LocalWebServer(string filePath)
    {
        _filePath = filePath;

        Url = "http://" + GetLocalIpAddress() + ":8787/";
    }

    ...

    private static string GetLocalIpAddress()
    {
        var listener = new TcpListener(IPAddress.Loopback, 0);
        try
        {
            listener.Start();
            return ((IPEndPoint)listener.LocalEndpoint).Address.ToString();
        }
        finally
        {
            listener.Stop();
        }
    }
}

Code was found on this Xamarin Forums post: https://forums.xamarin.com/discussion/42345/simple-android-http-listener-not-working

Sonic1015
  • 55
  • 1
  • 16