Using custom font in WKWebView without setting baseURL to bundleURL - ios

I'm trying to use local custom font without setting WKWebView baseURL to bundleURL. Is there a way to use something like an absolute URL to the file in the bundle?
I tried this (getting an URL of the file, using it in a string and appending local CSS with that string):
let fontURL = Bundle.main.url(forResource: "MaterialIcons-Regular", withExtension: "ttf")!
let fontFace = """
#font-face {
font-family: 'Material Icons';
src: url(\(fontURL.absoluteString)) format('truetype');
}
"""
(And other ways to get the file URL) And it didn't work.
If I use an URL like https://raw.githubusercontent.com/google/material-design-icons/master/iconfont/MaterialIcons-Regular.ttf instead of the fontURL.absoluteString in my code, it works.

You should be able to use fonts which are installed by your app (using section "Fonts provided by application") in info plist file. Then you can use following way font-family: 'FrutigerLTPro-Roman' in CSS

Related

How can I use a bundled font in a WebView with React Native on iOS?

In my React Native app I have some information I have stored in a local bundled folder and that I display in a WebView. I want this to work consistently with the rest of the app, so I need to use the same fonts as I use through the rest of the app.
I have this working correctly in Android, but in iOS I can't make it show the fonts at all.
My Webview Screen looks like this:
export class InstructionView extends React.Component<InstructionScreenRouteProp> {
render(): JSX.Element {
let filePath = (Platform.OS === 'android') ? 'file:///android_asset/' : './html/';
filePath += this.props.route.params.file.file + '.html';
return (
<WebView
originWhitelist={['*']}
source={{ baseUrl:'',
uri: filePath }}
startInLoadingState = { true }
/>
);
}
}
My bundle is structured like this:
/html/instructions.html
/html/styles.css
/Resources/MyFont-Regular.ttf
And then the css file font declaration looks like this:
#font-face {
font-family: 'myFont';
src: local('MyFont-Regular'), url('MyFont-Regular.ttf'), format('truetype');
}
h1 {
font-family: 'myFont';
font-size: 2em;
background-color: #622a53;
color: #fffcdc;
padding: 0.5em;
}
I don't think the font would currently work on Android because I've been trying to figure out the iOS version of it, but I have had it working on Android previously by using the explicit path, much like the file path in the render function.
The html is loaded and rendered correctly, the other styles from the stylesheet are applied, it is only the font that is missing.
I have seen various suggestions around this in different places, but none of them satisfy me because they seem to rely on placing the font in the same folder as the html content or even encoding it in the stylesheet, which seems redundant when I already have it included in the app bundle elsewhere. I have tried a lot of different paths in the font-face url and none of them seemed to work, but because of the way React silently caches assets it can be hard to know if I actually saw all the things I tried.
What do I need to do to be able to use an existing font in a WebView on an iOS device?

WKWebView load files from both Bundle and Document directory

I am running a webapp using WKWebView which load content and assets (html, js, img, css...) from a Bundle directory called Web_Assets.
I proceed like this to load index.html, and set Web_assets as baseURL:
if let filePath = Bundle.main.path(forResource:"index", ofType:"html", inDirectory: "Web_Assets") {
let html = try String(contentsOfFile: filePath, encoding: .utf8)
webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL?.appendingPathComponent("Web_Assets"))
}
This works perfectly: index.html is loaded and Web_Assets serve as base path for other ressources without any problem.
I could also use the loadFileURL method which is equivalent (to my understanding).
BUT, now i'd like to use other ressources (video in my case) inside my WKWebView from the Document directory which is static and manageable via iTunes File Sharing, while of course keeping the present architecture as it is (Web assets inside Bundle directory).
For example my page index.html would load his style.css and other assets from Web_Assets and display an HTML5 video located in Document
Is it possible to do this ?
Ideas (which i don't know how to achieve):
Symlink of Document in Web_assets ?
Different baseURL for different file types in WKWebView ?
(route all requests to Web_Assets except for mp4 files requests which are routed to Document)
Thanks for your help !
EDIT 1:
Idea 1 is not possible since Bundle directories are read-only.
Document can't be symlinked in Web_assets.
I can't manage to symlink Web_assets into Document either (weird error).
So i decided for now to copy Web_assets inside Document on each boot, so my Document folder can act as baseURL with my videos and web assets altogether.
It's a bit dirty since all my web assets are now visible in my Document folder (but not modifiable since the folder is erased and copied from Bundle uppon App restart)
I finally end up as EDIT 1 and #ngbaanh suggested:
on viewDidLoad:
let filemgr = FileManager.default
docURL = filemgr.urls(for: .documentDirectory, in: .userDomainMask)[0]
destPath = docURL.path+"/www/"
sourcePath = Bundle.main.resourceURL!.appendingPathComponent("Web_Assets").path
//COPY Web_Assets content from Bundle to Documents/www
do {
try filemgr.removeItem(atPath: destPath)
} catch {
print("Error: \(error.localizedDescription)")
}
do {
try filemgr.copyItem(atPath: sourcePath, toPath: destPath)
} catch {
print("Error: \(error.localizedDescription)")
}
// Configure Webview
webView.navigationDelegate = self
webView.configuration.userContentController.add(self, name: "teleco")
do {
let baseURL = try filemgr.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = baseURL.appendingPathComponent("www/index.html")
self.loadFileURL(fileURL, allowingReadAccessTo: baseURL)
} catch {
print(error)
}
This way my baseURL is Documents/www/
So in my index.html i can include ressources like style.css
AND i can also access files in Documents/ by using relative path like ../video.mp4
So index.html and style.css are distributed via the Bundle, copied to Documents at runtime, which allows me to access Documents files too.
A bit twisted, but works great.
Downside: it exposes Web_assets files in user accessible Documents folder.
But they can't be altered since they are replaced on App start.

WKWebView - Can't load page and set custom font/css with loadHTMLString

I am trying to download a online page and override css with my custom css. However I couldn't have success.
I did the following steps:
Download Html string from an online page
Added "<link rel="stylesheet" type="text/css" href="styles.css">" to the page Html head. This styles.css contains a custom font and anothers css rules.
Loaded this new Html string to WKWebView with webView.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
Another option would be just download the page and override the css with a style tag between the head tag, however I need to add a custom #font-face from a font in my project resources.
Any ideas how can I accomplish this? If I set Bundle.main.bundleURL as my baseURL resources from the online page don't download. If I set nil as my baseURL I can't access my custom font...
I think you should use bundlePath instead of bundleURL like this.
let url = URL(fileURLWithPath: Bundle.main.bundlePath)
webView.loadHTMLString(html, baseURL: url)

Grails Asset Pipeline : Recalculating of url references in css fails

Let me give a bit of background. Our grails-app/assets folder looks as follows
grails-app
-- assets
----stylesheets
------parent.css
------somefolder
---------child.css
----fonts
------HelveticaNeue-Light.otf
I have created a FontAssetFile.groovy
package app.asset
import java.util.regex.Pattern
class FontAssetFile extends asset.pipeline.AbstractAssetFile {
static final List<String> contentType = ['font/opentype']
static List<String> extensions = ['otf']
static String compiledExtension = 'otf'
static processors = []
Pattern directivePattern = null
public String directiveForLine (String line) { line }
}
The contents of parents.css are
/*
*= require somefolder/child
*= require_self
*/
The contents of child.css are
#font-face {
font-family: "Helvetica Neue Light";
src: url('../HelveticaNeue-Light.otf');
}
When I run the app in the development environment, the code can reference the font file since the browser makes a request for 127.0.0.1:8080/app/assets/somefolder/child.css
But when I run the app in production environment the code can't reference the font file since the browser now makes a request for 127.0.0.1:8080/app/assets/parent.css
The child.css file had been compiled into one file and the contents of the file are not in parent.css
This means that the browser thinks the font file is outside the assets folder since parent.css contents are
#font-face {
font-family: "Helvetica Neue Light";
src: url('../HelveticaNeue-Light.otf');
}
From the docs http://bertramdev.github.io/asset-pipeline/guide/usage.html#linking
I can see that "....if we use a relative path, the asset-pipeline understands this path and can recalculate a new relative path based on whatever root file may have required the CSS"
But this doesn't seem to be the case when the code references url inside a child.css file.
I need to be able to reference the font file in development and production environments.
I have considered disabling compiling in production but then the server would be serving individual files for every asset. I believe this is not optimal.
Please upgrade to the latest series of the plugin where this recalculated url is fixed (1.9.9) is rather old nowadays

HTML does not respect .CSS file in UIWebView

I am trying to load html page in WKWebView which is linked to external javascript and css files. My web view shows me the html page but it does not seem like that its respecting css file values. Can anyone please suggest me as to what am I doing wrong here. Following my code to add html page in WKWebView:
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html");
let htmlString = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil);
self.webView.loadHTMLString(htmlString, baseURL: NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath));
}
Also, here is the project structure where .css, .js and .html files re added.
Any help would be appreciated.
The problem is that the WKWebView renders page content inside a sandbox process that cannot access files in your application bundle. This effectively means that file:// URLs do not work.
I ended up including a small web server in my application to make it easier to serve content to the WKWebView.

Resources