VueJS in Android WebView (Xamarin)
Answer a question
I am trying to bundle a small hybrid C#/single page app, developed using VueJS, as an android app. We have some classes, that create and image and are sending it to an ESC printer. Everything works if we load the application from a server:
theView.LoadUrl( "https://our-app.our-server.com" );
However when we load it from file:///android_asset/index.html it sort of starts, but the page is empty.
I see in chrome debugger, that VueJS successfully created some elements:
<div data-app="true" class="application app theme--light">
<div class="application--wrap">
<main class="v-content" data-booted="true" style="padding: 0px;">
<div class="v-content__wrap"></div>
</main>
</div>
</div>
There are no errors in the console, just an empty screen.
What am I missing?
Answers
After struggling a bit more it seems, that the root of my problem was in the build, producing absolute paths for the JS files and assets. I changed the two settings in vue.config.js to get it working correctly.
Please note, that previous solution also works, but it's hiding the real problem instead of solving it. Also this workaround works only for android (I didn't find how to do the same on iOS)
Here is what I did: I changed the assetsDir and publicPath to empty string to force the build to produce relative paths.
module.exports = {
assetsDir: '',
publicPath: '',
.....
}
Additionally I had to turn off the history mode of the router and define one additional route:
{
path: '/index.html',
name: 'index',
component: ..........,
}
This way there are no issues serving from the file system on iOS as well.
------------------- alternative workaround ---------------------
The solution below works only on android:
I figured it out. It's the file:// urls! Change to http://localhost and it works (+ a few lines of code)
The same reason, why some pages just don't work when you open them directly from the file system. I rememberd, that in order to view some web pages, I had to create a local webserver or otherwise I can't see nearly anything, because the browser is way more restrictive when you open a page this way. Once I changed it to http://localhost and fixed my ShouldInterceptRequest to serve any requests to "http://localhost" from android Assets and everything worked.
Not sure why (yet) - I had to load the index this way:
wv.LoadDataWithBaseURL( "http://localhost", new StreamReader( Assets.Open( "index.html" ) ).ReadToEnd(), "text/html", "UTF-8", null );
instead of
wv.LoadUrl( "http://localhost/index.html" );
Also I had to override WebViewClient to serve content from assets when http://localhost is requested:
// view client to serve the web from assets folder correctly
public class MyWebViewClient : WebViewClient {
private AssetManager m_Assets;
public MyWebViewClient( AssetManager assets ) {
m_Assets = assets;
}
public static string GetMimeType( String url ) {
String type = null;
String extension = url.Split( '.' ).Last();
if ( extension != null ) {
if ( extension == "css" ) {
return "text/css";
} else if ( extension == "js" ) {
return "text/javascript";
} else if ( extension == "png" ) {
return "image/png";
} else if ( extension == "gif" ) {
return "image/gif";
} else if ( extension == "jpg" ) {
return "image/jpeg";
} else if ( extension == "jpeg" ) {
return "image/jpeg";
} else if ( extension == "woff" ) {
return "application/font-woff";
} else if ( extension == "woff2" ) {
return "application/font-woff2";
} else if ( extension == "ttf" ) {
return "application/x-font-ttf";
} else if ( extension == "eot" ) {
return "application/vnd.ms-fontobject";
} else if ( extension == "svg" ) {
return "image/svg+xml";
}
type = "text/html";
}
return type;
}
public override WebResourceResponse ShouldInterceptRequest( WebView view, IWebResourceRequest request ) {
if ( request.Url != null && request.Url.Path != null && request.Url.Host == "localhost" ) {
var mimeType = GetMimeType( request.Url.Path );
var fileUrl = request.Url.Path
.Replace( "file://", "" )
.Replace( "android_asset/", "" )
.Trim( '/' );
string extension = request.Url.Path.Split( '.' ).Last();;
string fileEncoding = "application/octet-stream";
if ( extension.EndsWith( "html" ) || extension.EndsWith( "js" ) || extension.EndsWith( "css" ) )
fileEncoding = "UTF-8";
try {
return new WebResourceResponse( mimeType, fileEncoding, m_Assets.Open( fileUrl ) );
} catch {
// ignore
}
}
return base.ShouldInterceptRequest( view, request );
}
}
更多推荐
所有评论(0)