How to inject javascript file to html string coming from api? - ios

I have a html string which comes from the api.
I need to inject a static javascript file present in my code.
Thanks

You can use WKUserScript and append the javascript to webview using the WKWebViewConfiguration.
let contentController = WKUserContentController()
guard let scriptPath = Bundle.main.path(forResource: "script", ofType: "js"),
let scriptSource = try? String(contentsOfFile: scriptPath) else { return }
let script = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
contentController.addUserScript(script)
let config = WKWebViewConfiguration()
config.userContentController = contentController
let webView = WKWebView(frame: .zero, configuration: config)
self.view.addSubview(webView)
webView.loadHTMLString(htmlString, baseURL: nil)

Related

Swift allowsInlineMediaPlayback with SFSafariViewController

Problem:
I would like to implement a similar solution that WKWebView has but with SFSafariViewController.
allowsInlineMediaPlayback = false
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = false
How can I implement a similar functionality with Safari Services?
import SafariServices
let bookmark = NSURL(string: youtubeVideoURL)
let config = SFSafariViewController.Configuration()
let safari = SFSafariViewController(url: bookmark as! URL)
if(UIDevice.current.userInterfaceIdiom == .pad) {
safari.modalPresentationStyle = .fullScreen
}else{
safari.modalPresentationStyle = .fullScreen
}
self.present(safari, animated: true, completion: nil)
Exactly what I want accomplished is in the code below. However, I am wondering if it can be done with a SFSafariViewController by somehow implementing
allowsInlineMediaPlayback
let youtubeVideoURL = posts[sender.view?.tag ?? 0].youtube_video_url + "?playsinline=1?autoplay=1"
var myPlayer: WKWebView!
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = false
webConfiguration.mediaTypesRequiringUserActionForPlayback = []
myPlayer = WKWebView(frame: UIScreen.main.bounds, configuration: webConfiguration)
self.view.addSubview(myPlayer)
if let mediaURL:URL = URL(string: youtubeVideoURL) {
let request:URLRequest = URLRequest(url: mediaURL);
myPlayer.load(request)
}
Pseudocode:
let config = SFSafariViewController.Configuration()
config.allowsInlineMediaPlayback = false

Read local storage data using WKWebView

I need to read value stored in the local storage of WKWbview.
I tried using the below code but getting nil.
I am able to write values in local storage but facing difficulty in reading values from it.
let script = "localStorage.getItem('token')"
wkWebView.evaluateJavaScript(script) { (token, error) in
print("token = \(token)")
}
WKWebView init code:
// 1
let accessToken = UserDefaults.standard.value(forKey: "token") as? String
// 2
let refreshToken = UserDefaults.standard.value(forKey: "RefreshToken") as? String
// 3
let configuration = WKWebViewConfiguration()
// 4
let contentController = WKUserContentController()
let accessTokenScript = "javascript: localStorage.setItem('token', '\(accessToken!)')"
// 5
let userAccessTokenScript = WKUserScript(source: accessTokenScript, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
// 6
contentController.addUserScript(userAccessTokenScript)
configuration.userContentController = contentController
self.wkWebView = WKWebView(frame: controller.view.bounds, configuration: configuration)
You need to inject this script when the website has already loaded:
your WKWebView needs to assign the navigationDelegate
webView.navigationDelegate = self
inject the script when the website was loaded completely
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
//you might want to edit the script, with the escape characters
let script = "localStorage.getItem(\"token\")"
wkWebView.evaluateJavaScript(script) { (token, error) in
if let error = error {
print ("localStorage.getitem('token') failed due to \(error)")
assertionFailure()
}
print("token = \(token)")
}
}

Creating a custom webview from scratch

I am in a situation where I want more flexibility for webview than the offered by UIWebview and not at all by WKWebview. Things like customizing web request before start eg sending headers and redirections. Also as we know UIWebview officially deprecated now in iOS 12.
I'm looking forward to a generic webview now, I know its possible as open source examples say Firefox for iOS.
If you've been using any of your projects or know please tell me. Or if you can give me some information how can this be achieved or any tutorails links would be helpful.
Declare the WebView object
var webView: WKWebView!
//Load the data in webView
func loadUrl() {
var webView : WKWebView!
let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let userContentController: WKUserContentController = WKUserContentController()
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
userContentController.addUserScript(script)
webView = WKWebView(frame: CGRect.zero, configuration: configuration)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsLinkPreview = true
//Load the Data from URL
let url = URL(string: "Your URL")
var urlRequest = URLRequest(url: url! as URL)
urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")
urlRequest.setValue("user-agent", forHTTPHeaderField: "User-Agent")
webView.load(urlRequest)
//Load the Data from local HTML
do {
guard let filePath = Bundle.main.path(forResource: "Your-HTML-File", ofType: "html")
else {
print ("FILE READING ERROR")
return
}
//get the content of HTML File
let contents = try String(contentsOfFile: filePath , encoding: .utf8)
webView.loadHTMLString(contents, baseURL:URL(fileURLWithPath: Bundle.main.bundlePath))
}
catch {
print ("FILE HTML ERROR")
}
}
//Delegate Method that called when webView finish Loading.
//You can apply css or style here
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
///Local CSS File
guard let path = Bundle.main.path(forResource: "Local-CSS-File", ofType: "css") else { return }
let script = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link');link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(script) {(result, error) in
if let error = error {
print(error)
}
}
//External CSS File
let externalCSSLink = "your-css-file-url"
let script2 = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link');link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(externalCSSLink)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(jsString1) {(result, error) in
if let error = error {
print(error)
}
}
}

Load UIImage into a WebView Swift 4

Rather than loading a WebView from a URL like this
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: imageUrl.urlString)
let request = URLRequest(url: url!)
webView.load(request)
}
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
How can I load a UIImage onto the WebView in Swift 4?
Try Something like this.
let html = "<html><img src=\"datadb/DestinationGuide/Images/YourImage.png\"/> </html>"
//Save this html in `DocumentDirectory`
let saveHTML = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("temp.html")
try? html.data(using: .utf8)!.write(to: saveHTML)
//Now load this `temp.html` file in webView
webView.loadRequest(URLRequest(url: saveHTML))

WKWebView Loading is Too Slow

I am using MarkDonwView Library : https://github.com/keitaoouchi/MarkdownView
Which is converting MD String to show as a webview. Rendering is taking too long as it loads everything and then shows the view. Is it possible to make image loading async while showing text body ASAP so it will not look like its too slow ?
This is how it is loading the html file.
if bundle.bundleIdentifier?.hasPrefix("org.cocoapods") == true {
htmlURL = bundle.url(forResource: "index",
withExtension: "html",
subdirectory: "MarkdownView.bundle")
} else {
htmlURL = bundle.url(forResource: "index",
withExtension: "html")
}
if let url = htmlURL {
let templateRequest = URLRequest.init(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 60) //URLRequest(url: url)
let escapedMarkdown = self.escape(markdown: markdown) ?? ""
let imageOption = enableImage ? "true" : "false"
let script = "window.showMarkdown('\(escapedMarkdown)', \(imageOption));"
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
let controller = WKUserContentController()
controller.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
let wv = WKWebView(frame: self.bounds, configuration: configuration)
wv.scrollView.isScrollEnabled = self.isScrollEnabled
wv.translatesAutoresizingMaskIntoConstraints = false
wv.navigationDelegate = self
addSubview(wv)
wv.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
wv.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
wv.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
wv.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
wv.backgroundColor = self.backgroundColor
self.webView = wv
wv.load(templateRequest)
} else {
// TODO: raise error
}

Resources