Open new tab from WKWebView html content in safari app extension popover - swift

I'm developing a browser extension that share code between chrome and safari, basically it's an html page that I load up in a WKWebView on safari app extension (and an iframe on chrome extension).
Everything works fine apart from links that won't open in the safari app extension popover if they have target="_blank" or are popups like facebook login.
Anyone know if it is possible to have safari open them up as if clicked on in an ordinary safari tab?
I've tried to see if the WKWebView sets a global safari object in my html content, but it seems not, so this Safari Extension Popover Links does not work (results in ReferenceError: Can't find variable: safari).
This is how I load the web view in my SafariExtensionViewController:
override func viewDidLoad() {
super.viewDidLoad()
...
self.view.addSubview(webView)
webView.navigationDelegate = self
...
webView.load("\(baseUrl)?url=\(currentUrl)")
}
and an extension to make the load part work:
extension WKWebView {
func load(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
load(request)
}
}
}

Safari Technology Preview 77 (6March 2019) and likely 12.1.x of regular Safari.
Made the window.safari object available in frames opened to safari-extension:// resources
https://webkit.org/blog/8658/release-notes-for-safari-technology-preview-77/
So if you go by that method you should be OK.

Related

WKWebView Dark and Light Mode with dynamic URL in Swift 5

I created WKWebView that doesn't have one url. User use this WKWebView as Safari means user can search anything on WKWebView. I am facing one issue when I change dark and light mode my web view will show me only white(Light) mode. My app is working on both mode all things working fine except WKWebView.
Already search on SO not find any related question on this.
how to use iOS 13 darkmode for wkwebview
I refer this blog but it's static url so it will not help me out
https://useyourloaf.com/blog/using-dynamic-type-with-web-views/
Also checked opaque and background property but not working for me!
IMPORTANT
User can search anything like google.com, photos or any surfing etc.
class DownloadViewController: UIViewController {
#IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.uiDelegate = self
webView.navigationDelegate = self
webView.load(URLRequest(url: URL(string: "https://www.google.com")!))
webView.allowsBackForwardNavigationGestures = true
webView.allowsLinkPreview = true
}
}
First I am loading Google site then depend on user(Totally dynamic not one url here).
Please suggest me! Thank you.
You can use injecting CSS technic to add Light/Dark feature to your loaded web pages e.g:
// Load a web page
webView?.load(URLRequest(url: URL(string: "https://google.com")!))
// Inject Light/Dark CSS
let lightDarkCSS = ":root { color-scheme: light dark; }"
let base64 = lightDarkCSS.data(using: .utf8)!.base64EncodedString()
let script = """
javascript:(function() {
var parent = document.getElementsByTagName('head').item(0);
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = window.atob('\(base64)');
parent.appendChild(style);
})()
"""
let cssScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
webView?.configuration.userContentController.addUserScript(cssScript)
Result:
To support page changing you can move insertion code to didCommitNavigation notification:
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
...
// Inject CSS here
}
NOTE: It doesn't work with any web page in general because some of web sites can hardcode colors of background, fonts etc. but you can tune specific pages as well by overriding its CSS.
Already search on SO not find any related question on this.
Interesting that you mention this, as this has been a question addressed quite a few times already. A quick search will show many good answers and threads, for example: this one.
That being said, the quick answer is:
WKWebView can adopt light and dark mode, like any other UIView/NSView. You can manually set the interfaceStyle on the appearance, or it will inherit it. More details here overrideUserInterfaceStyle.
But
Probably the problem you are facing is that even though the WKWebView is using the dark interfaceStyle, websites still show on light mode. That is because those websites (google and any other website/URL) are independent and handle their style on their own. Some of them adjust to match your device's interface style, but not all. In short, even if WKWebView is on dark mode, Google will load a white background if they want to do it.
As mentioned by others, you can change this behaviour by manually injecting CSS, please check those answers if that is what you want to do, check also the link I posted at the beginning of this answer where they discuss that approach.
As in android web views(force_darkmode), Apple has not provided support for dark mode web-views yet. you can explore safari with a few reputed websites, even though they don't convert to dark mode.
so we should wait for Webkit dark mode support till then. These CSS injections are not the best practice or robust solution.

SwiftUI Universal Links not working for NFC

Our app uses universal links and the AASA file seems to be working fine because hyperlinks in emails, as well as QR coded URLs both launch the app. They both also cause the SwiftUI .onOpenURL(perform:) function to be called.
Things are a bit more confusing with NFC. The URL is recognised and the app launches, suggesting the issue is not related to AASA. However, the onOpenURL function is not called. Can anyone tell me how to handle universal links from NFC? Ideally I'd like to keep it pure SwiftUI but if I need to use the AppDelegate so be it.
The code in the main SwiftUI file is:
import SwiftUI
#main
struct MyApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL(perform: { url in
print("url opened:\(url)")
// prints when opened from URL in email,
// Notes or QR code, but not when opened
// from URL embedded in NFC NDEF
})
}
}
}
I have also tried defining the application(_:continue:restorationHandler:) function in the AppDelegate, but that doesn't get called either.
Thanks for any help.
The solution is to add a continue user activity handler on a suitable view:
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
print("Continue activity \(userActivity)")
guard let url = userActivity.webpageURL else {
return
}
print("User wants to open URL: \(url)")
// TODO same handling as done in onOpenURL()
}
It's not obvious why the same Universal Link received through a click on a link in Safari should be handled differently than the same link read from a tag, but apparently it's not the same thing.
In case it helps anyone with the same issue, I solved the issue by registering a URL schema for the app and then using .onOpenURL(perform:).
Seems a strange way to have to do it but it works as required, so happy days!

WKWebview is not showing proper font from remote URL

I am loading a remote url in WKWebview where only content is text. Text is loading properly but there in site they used 'Nunito' font, which is not showing here in my side. When i open url in browser text are showing properly with font even in safari borowser.
Here is my Code
let urlStr = "http://islamintel.com/cms/about-us"
if let url = URL(string: urlStr) {
let request = URLRequest(url: url)
wkWebView.load(request)
}
You need to add custom font (i.e Nunito) in the app. Here is the reference link on how to load custom font in WKWebView.

Instagram embed not working on some mobile devices

It loads the placeholder "View this post on Instagram" instead embedded media. Standard Instagram embed code is used, and this happens both in Chrome and Firefox browsers on the same device. Interesting, it is happening on Android and iOS, but only on small number of devices I test.
Any idea?
I ran into the same issue using a WKWebView in iOS 12. The solution that worked for me was to use an iframe with the standard link with "/embed" as the last path element, rather than the embed code provided by Instagram. Example from a viewDidLoad():
let embed = "<iframe src=\"https://www.instagram.com/p/BwdGxDGAOcP/embed\" width=\"100%\" height=\"100%\" frameborder=\"0\" scrolling=\"no\" allowtransparency=\"true\"></iframe>"
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
let webview = WKWebView(frame: view.frame, configuration: config)
webview.uiDelegate = self
view = webview
webview.loadHTMLString(embed, baseURL: nil)

Safari app extension how to capture beforeNavigate event?

With older safari extension, we had global javascript to handle beforeNavigate event but with new safari app extension concept is there any way to capture the same event in the app code ?
i tried overiding beginRequest but not sure how to capture the url information here
override func beginRequest(with context: NSExtensionContext) {
//TODO:
}
You can use script file in the safari app extension, that script automatically injected before page load in the safari.
The script get the navigate event from safari browser and then script would give the event to the app extension and the extension handle this event by following method :
override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : AnyObject]!) {
page.getPropertiesWithCompletionHandler { properties in
NSLog("The extension received a message (\(messageName)) from a script injected into (\(properties?.url)) with userInfo (\(userInfo))")
}
}
Note : The event had url information that you want.