WKWebViews (multiple) - sharing cookies, localStorage in Swift - ios

I'm having such an irritating issue. I have a UITabBar application with 5 tab bar buttons. Each hooked up to a viewController: FirstViewController, SecondViewController etc.
In each of the 5 ViewControllers I have a WKWebView. The 5 WKWebViews display sections of an eCommerce website. For example, tab 1 shows home, tab 2 shows cart etc.
In order for the app to work, I need all 5 WKWebViews to share all cookies, localStorage, IndexDB.
Right now, I'm doing this:
FirstViewController
class FirstViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
let uniqueProcessPool = WKProcessPool()
let websiteDataStoreA = WKWebsiteDataStore.nonPersistent()
..
class YourModelObject {
static let sharedInstance = YourModelObject()
let configA = WKWebViewConfiguration()
}
override func loadView() {
let model = YourModelObject.sharedInstance
//so I believe I'm doing the right thing here setting this
model.configA.processPool = uniqueProcessPool
model.configA.websiteDataStore = websiteDataStoreA
webView = WKWebView(frame: .zero, configuration: model.configA)
webView.navigationDelegate = self
self.webView.scrollView.delegate = self
view = webView
}
Now in SecondViewController, I simply do this:
override func loadView() {
//am I doing something wrong here - like creating another instance of configA, instead of re-using - and if so, how do I re-use what was created in FirstViewController?
let model = FirstViewController.YourModelObject.sharedInstance
webView = WKWebView(frame: .zero, configuration: model.configA)
webView.navigationDelegate = self
self.webView.scrollView.delegate = self
view = webView
}
When I run the project, the cookies, localStorage, IndexDB information from WKWebView in FirstViewController is not shared with SecondViewController - even though according to me, I'm re-using the same configA for both.

I think it is best if you use SFSafariViewController for your needs.
As the documentation states:
In iOS 9 and 10, it shares cookies and other website data with Safari.
It means, that it is going to use the same cookies and data from the Safari browser, which is even better. If I am not mistaken, the user can be logged in through Safari, and when he comes to your app, he will not have to log in again.
Here is the full documentation for it:
SFSafariViewController
Update:
If you still want to do what you already started, according to this answer here in Objective-C, this is the solution in Swift:
You need a place where you would store the persistent 'process pool'. In your case, it is YourModelObject singleton
class YourModelObject {
static let sharedInstance = YourModelObject()
let processPool = WKProcessPool()
}
Use the shared processPool before initializing the webView. This is the initialization function which you would call in the loadView() for every viewController:
override func loadView() {
super.loadView() //don't forget this line
setupWebView()
}
private func setupWebView() {
let config = WKWebViewConfiguration()
config.processPool = YourModelObject.sharedInstance.processPool
self.webView = WKWebView(frame: .zero, configuration: config)
self.webView.navigationDelegate = self
self.webView.scrollView.delegate = self
self.view = self.webView
}

Related

Swift 5 Disable redirection to other apps inside WKWebView

First of all... My other question got marked as a duplicate even though the question suggested was the exact opposite, so:
Inside my webView I do not want to be redirected to other apps. WKWebView should never redirect to other Apps. Instead it should just open the url.
This is my webView:
lazy var webView: WKWebView = {
let webConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.translatesAutoresizingMaskIntoConstraints = false
return webView
}()

video will not load inline

I want my video to stream in the view not takeover the screen, ive specified that every way, toggled the option in storyboards and still nothing. any thoughts or ideas, maybe something im missing, please feel free to test the code your self and see the result (fills the entire screen, and still unable to play inline.)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.mediaTypesRequiringUserActionForPlayback = []
LiveStream = WKWebView(frame: CGRect(x: 0, y: 0, width: 375, height: 300), configuration: webConfiguration)
self.view.addSubview(LiveStream)
if let videoURL:URL = URL(string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8?playsinline=1") {
let request:URLRequest = URLRequest(url: videoURL)
LiveStream.load(request)
}
Edited the link to a 24/7 uptime (https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8?playsinline=1)
I am seeing some mistakes here.
First of all you have already added WKWebView in your storyboard and I am guessing that from your
#IBOutlet var LiveStream: WKWebView!
and you are also adding it into your view again with
self.view.addSubview(LiveStream)
Which is not correct way to add it.
You can use UIView for that.
For that add a UIView in your storyboard and create IBOutlet for that
#IBOutlet weak var viewForEmbeddingWebView: UIView!
then declare an instance var LiveStream: WKWebView!
Now you can configure LiveStream as shown below:
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.mediaTypesRequiringUserActionForPlayback = []
LiveStream = WKWebView(frame: viewForEmbeddingWebView.frame, configuration: webConfiguration)
self.viewForEmbeddingWebView.addSubview(LiveStream)
if let videoURL:URL = URL(string: "https://www.youtube.com/embed/9n1e1N0Sa9k?playsinline=1") {
let request:URLRequest = URLRequest(url: videoURL)
LiveStream.load(request)
}
And your result will be:
As you have noticed video is playing inside the WKWebView not in full screen.
Note:
Your URL wasn't working for me so I have used another URL for demonstrate.

WKWebView stays blank on simulator (allowing arbitrary loads)

I'm trying to load a WKWebView but my simulator (iPhone 6 - iOS 10.2) keeps displaying a blank screen. I can only see horizontal and vertical scrollers as if the webview was quite wide but empty.
App Transport Security Settings > Allow Arbitrary Loads is set to YES in the info.plist file.
Here is my code
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: "https://www.google.co.uk")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
}
I tried several pieces of code found online or even downloaded working simple WKWebView xcodeproj, but I always have the same problem.
I can load the website (https://www.google.co.uk) in my browser. Also tried with general .com extension, or local .co.uk extension.
EDIT: works perfectly fine on the device but not on the simulator
I know it's an old post but it might be helpful for others.
So it most have something to do with override loadView() This method loads or creates a view and assigns it to the view property, but somehow in Simulator it doesn't do what it should!
Try removing loadView and Add the method body inside viewDidLoad() and it should be fine.
Check if you have a proxy running. I've had Charles Proxy running in the background and that caused this issue.

IOS Swift what am I messing up on in my UIView adding a subview

I have a UIView and set constraints on it as the image below shows . When I open it in the simulator it works correctly . The problem comes when I try and add a WKWEBview to display a video and add the subview . I want the video to take the dimensions of the UIView but the video looks extra small and the UIView looks like it shrinks . How can I fix that so that the video takes the full dimensions of the UIView . As you can see from the constraints it set to trail and leading and the video is not taking up that width even though it is large enough . The only thing I can think of for fixing this is adding a
addChildViewController(ViewController)
however the WKWebview does not have a Controller any suggestions would be great .
class ExampleTable: UIViewController, WKUIDelegate {
#IBOutlet weak var newView: UIView!
var myWKWEBVIEW: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
myWKWEBVIEW?.uiDelegate = self
guard let movieURL = URL(string: "my video url")
else { return }
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.mediaTypesRequiringUserActionForPlayback = .audio
myWKWEBVIEW = WKWebView(frame: newView.frame,configuration: webConfiguration)
newView.addSubview(myWKWEBVIEW!)
DispatchQueue.main.async (execute: { () -> Void in
self.myWKWEBVIEW?.loadHTMLString("<video height=\"\(self.newView.frame.height)\" width=\"\(self.newView.frame.width)\" muted=\"muted\" autoplay=\"autoplay\" src=\"\(movieURL)\" playsinline/>", baseURL: nil)
})
}
}
My constraints
How it looks with no addsubview
How it looks when I add subview to display video
Can you please check the below code :
myWKWEBVIEW = WKWebView(frame: CGRect(origin: CGPoint(x:0,y:0), size: newView.frame.size),configuration: webConfiguration)

UIWebView webViewDidLoadFinish method not called

I've been playing around with web views in swift this evening, but have run into a bit of an issue.
For some reason I'm not able to get the webViewDidStartLoad or webViewDidFinishLoad methods to fire.
In my storyboard, I have an outlet called webView linked to my UIWebView element.
Is anyone able to help me with what I am doing wrong?
This is my viewController.swift file:
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView : UIWebView
var url = NSURL(string: "http://google.com")
override func viewDidLoad() {
super.viewDidLoad()
//load initial URL
var req = NSURLRequest(URL : url)
webView.loadRequest(req)
}
func webViewDidStartLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = true
println("AA")
}
func webViewDidFinishLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = false
println("BB")
}
}
Try this!
var req = NSURLRequest(URL: url)
webView.delegate = self
webView.loadRequest(req)
I experienced the same issue, even I did confirmed the UIWebViewDelete to self and implemented its methods.
//Document file url
var docUrl = NSURL(string: "https://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjjwPSnoKfNAhXFRo8KHf6ACGYQFggbMAA&url=http%3A%2F%2Fwww.snee.com%2Fxml%2Fxslt%2Fsample.doc&usg=AFQjCNGG4FxPqcT8RXiIRHcLTu0yYDErdQ&sig2=ejeAlBgIZG5B6W-tS1VrQA&bvm=bv.124272578,d.c2I&cad=rja")
let req = NSURLRequest(URL: docUrl!)
webView.delegate = self
//here is the sole part
webView.scalesPageToFit = true
webView.contentMode = .ScaleAspectFit
webView.loadRequest(req)
above logic worked perfectly with test URl I got from quick google search.
But I when I replaced with mine. webViewDidFinishLoad never get called.
then How we solved?
On backed side we had to define content-type as document in headers. and it works like charm.
So please make sure on your server back-end side as well.
Here's my 2 cents battling with the same problem in SWIFT 3:
class HintViewController: UIViewController, UIWebViewDelegate
Declare the delegate methods this way (note the declaration of the arguments):
func webViewDidStartLoad(_ webView: UIWebView)
func webViewDidFinishLoad(_ webView: UIWebView)
Remember to set self to the webview's delegate property either in Interface Builder (Select the webview, drag from the delegate outlet to the webview from the Connections Inspector OR programmatically: self.webview.delegate = self)
As others noted, setting the delegate of UIWebView and conforming to the UIWebViewDelegate protocol is the best possible solution out there.
For other's who might make it here. I had put my delegate methods in a private extension which couldn't be accessed by the delegate caller. Once I changed the extension to internal the delegates started to get called properly.
There is my detailed solution for Swift 3:
1) in class declaration write the UIWebViewDelegate. For example:
class MyViewController: UIViewController, UIWebViewDelegate {
2) of course in storyboard make link to your UIViewController like this:
#IBOutlet weak var webView: UIWebView!
3) in the func viewDidLoad add one line:
self.webView.delegate = self
Nothing more. Special thinks to LinusGeffarth and LLIAJLbHOu for idea.

Resources