I'm learning how to make a webview from youtube, however i followed every step of their code, however my code got an error while their code did not. I can't run but they can. Error said "Cannot convert value of type 'WebView.Context' (aka 'UIViewRepresentableContext') to expected argument type 'URLRequest'"
Can someone point out the problem? Thank you.
import SwiftUI
import WebKit
import UIKit
import SwiftUI
struct ContentViewww: View {
var body: some View {
NavigationView {
NavigationLink {
WebView(url: URL(string: "https://www.youtube.com")!)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} label: {
Text("open website")
.padding(10)
.background(.black)
.foregroundColor(.white)
}
.navigationBarHidden(true)
}
}
}
struct WebView: UIViewRepresentable {
var url : URL
func makeUIView(context: Context) -> some UIView {
let web = WKWebView()
let request = URLRequest(url: url)
web.load(context)
return web
}
func updateUIView(_ uiView: UIViewType, context: Context) {
let web = WKWebView()
let request = URLRequest(url: url)
web.load(request)
}
}
You are supposed to load request not context.
func makeUIView(context: Context) -> some UIView {
let web = WKWebView()
let request = URLRequest(url: url)
web.load(request) //modified
return web
}
Related
While learning to use webview in my app I just added a webview and detected a memory leak.
I found a lot of demos on the Internet and tested them and all have this problem.
Here is my test code:
Instruments screenshot
import SwiftUI
import WebKit
struct SWKWebView: UIViewRepresentable {
#Binding var url: String?
func makeUIView(context: Context) -> WKWebView {
let webview = WKWebView()
webview.navigationDelegate = context.coordinator
return webview
}
func updateUIView(_ uiView: WKWebView, context: Context) {
if let url = url, let requetURL = URL(string: url) {
uiView.load(URLRequest(url: requetURL))
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject,WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.title") { (result, error) in
print("didFinish:\(String(describing: result ?? ""))")
}
}
}
}
struct TTTest: View {
#State var url: String? = "https://www.google.com"
var body: some View {
SWKWebView(url: $url)
}
}
When I updated the IOS system to version 15.5, this problem was solved
I have a problem where my webView doesn't load on build but in preview it works as it should. What I mean by not loading is that the webView is just white.
What I first thought was that the simulated iphones network settings made it so it didn't allow URLRequests for some reason but I disputed this quickly when I temporarily changed the url to "https://google.com" and it loaded as it should.
Here is my code:
//
// ContentView.swift
// spotifystats
//
// Created by bappo on 2021-08-15.
//
import SwiftUI
import WebKit
struct SpotifyConstants {
static let CLIENT_ID = "***************"
static let SESSION_KEY = "spotifySessionKey"
static let REDIRECT_URI = "spotifystats://"
static let SCOPE = "user-read-email"
}
struct WebView : UIViewRepresentable {
let request: URLRequest
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
}
struct ContentView: View {
#State var isLogginIn = false
let authURLFull = "https://accounts.spotify.com/authorize?response_type=token&client_id=" + SpotifyConstants.CLIENT_ID + "&scope=" + SpotifyConstants.SCOPE + "&redirect_uri=" + SpotifyConstants.REDIRECT_URI + "&show_dialog=false"
var body: some View {
Button("Spotify Login") {
isLogginIn = true
}
.padding()
.foregroundColor(.white)
.background(Color.green)
.clipShape(Capsule())
.sheet(isPresented: $isLogginIn) {
WebView(request: URLRequest(url: URL(string: authURLFull)! ))
}
}
}
extension ContentView {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
RequestForCallbackURL(request: navigationAction.request)
}
func RequestForCallbackURL(request: URLRequest) {
let requestURLString = (request.url?.absoluteString)! as String
print(requestURLString)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Hi i have the following code to load a webpage in SwiftUI Xcode 12, everything load nicely, but the tel links and WhatsApp link doesn't work, what can I do?
this is my browser.swift file:
import Foundation
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable{
var url: String
func makeUIView(context: Context) -> some WKWebView {
guard let url = URL(string: self.url) else {
return WKWebView()
}
let request = URLRequest(url: url)
let wkWebView = WKWebView()
wkWebView.load(request)
return wkWebView
}
func updateUIView(_ uiView: UIViewType, context: UIViewRepresentableContext<WebView>) {
}
}
this is my contentview.swift:
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color(UIColor(red: 0.89, green: 0.98, blue: 0.88, alpha: 1.00))
.ignoresSafeArea()
WebView(url: "https://dominio.com/app/ios/index.php?idE=17")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You need to implement the WKNavigationDelegate and WKUIDelegate
func makeUIView(context: Context) -> some WKWebView {
guard let url = URL(string: self.url) else {
return WKWebView()
}
let request = URLRequest(url: url)
let wkWebView = WKWebView()
wkWebView.navigationDelegate = context.coordinator //<<Add your delegates here
wkWebView.uiDelegate = context.coordinator //<<Add your delegates here
wkWebView.load(request)
return wkWebView
}
Add your coordinator function
func makeCoordinator() -> Coordinator {
Coordinator()
}
And at the Coordinator class
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
{
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
if navigationAction.request.url?.scheme == "tel" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
}
else if navigationAction.request.url?.scheme == "mailto" {
UIApplication.shared.openURL(navigationAction.request.url!)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}
Make sure to test it on real devices
I can't figure out a way to set the navigation bar to be opaque black...
All the related hacks don't seem to work if the navigation view is presented modally...
This is how I present my webView:
Button(action: { self.showFAQ.toggle() }) {
Text("Frequently Asked Questions").foregroundColor(.orange)
}.sheet(isPresented: $showFAQ) {
WebView(isPresented: self.$showFAQ, url: self.faqURL)
}
This is my webView wrapper:
struct WebView: View {
let url: URL
#Binding var isPresented: Bool
var body: some View {
NavigationView {
WebViewRepresentable(url: url)
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
self.isPresented.toggle()
}, label: { Text("Done") } ))
}
}
init(isPresented: Binding<Bool>, url: URL) {
self.url = url
self._isPresented = isPresented
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
}
struct WebViewRepresentable: UIViewRepresentable {
let url: URL
// Creates a UIKit view to be presented.
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.isOpaque = false
webView.backgroundColor = .systemBackground
return webView
}
// Updates the presented UIKit view (and its coordinator)
// to the latest configuration.
func updateUIView(_ uiView: WKWebView, context: Context) {
let req = URLRequest(url: url)
uiView.load(req)
}
}
}
UINavigationBarAppearance() is ignored... UINavigationBar.appearance() is also ignored...
A possible solution is to avoid using a NavigationView and simply add a Done button to achieve the same result:
struct WebView: View {
let url: URL
#Binding var isPresented: Bool
var body: some View {
VStack {
HStack {
Spacer()
Button(action: {
self.isPresented.toggle()
}) {
Text("Done").padding(.all, 20)
}
}
WebViewRepresentable(url: url)
}.background(Color.black.opacity(1.0))
.edgesIgnoringSafeArea(.all)
}
init(isPresented: Binding<Bool>, url: URL) {
self.url = url
self._isPresented = isPresented
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
}
struct WebViewRepresentable: UIViewRepresentable {
let url: URL
// Creates a UIKit view to be presented.
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.isOpaque = false
webView.backgroundColor = .systemBackground
return webView
}
// Updates the presented UIKit view (and its coordinator)
// to the latest configuration.
func updateUIView(_ uiView: WKWebView, context: Context) {
let req = URLRequest(url: url)
uiView.load(req)
}
}
}
No Public API in SwiftUI to response for the resizable modifier of View protocol. Only Image in SwiftUI could work with .resizable(). Custom UIView like UIView for GIF is not resizable now.
I use SDWebImageSwiftUI AnimatedImage, which is backing UIKit View SDAnimatedImageView. AnimatedImage is not response to .resizable(), .scaleToFit, .aspectRatio(contentMode: .fit), etc. WebImage is backing SwiftUI Image, so it's working fine.
import SwiftUI
import SDWebImageSwiftUI
struct ContentView: View {
let url = URL(string: "https://media.giphy.com/media/H62DGtBRwgbrxWXh6t/giphy.gif")!
var body: some View {
VStack {
AnimatedImage(url: url)
.scaledToFit()
.frame(width: 100, height: 100)
WebImage(url: url)
.scaledToFit()
.frame(width: 100, height: 100)
}
}
}
Not sure if it's an Apple bug. Expect custom view like SDWebImageSwiftUI AnimatedImage is responsive to SwiftUI size related modifiers like .scaledToFit().
Related issue: https://github.com/SDWebImage/SDWebImageSwiftUI/issues/3
SwiftUI uses the compression resistance priority and the content hugging priority to decide what resizing is possible.
If you want to resize a view below its intrinsic content size, you need to reduce the compression resistance priority.
Example:
func makeUIView(context: Context) -> UIView {
let imageView = UIImageView(image: UIImage(named: "yourImage")!)
imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
return imageView
}
This will allow you to set .frame(width:height:) to any size you want.
Finally found a solution.
Make a UIView wrapper outside of the SDAnimationImageView or UIImageView, then override layoutSubviews() set the frame of subview.
Here is full code by me.
And SDWebImageSwiftUI also release a new version which uses wrapper to solve this problem.
class ImageModel: ObservableObject {
#Published var url: URL?
#Published var contentMode: UIView.ContentMode = .scaleAspectFill
}
struct WebImage: UIViewRepresentable {
#ObservedObject var imageModel = ImageModel()
func makeUIView(context: UIViewRepresentableContext<WebImage>) -> ImageView {
let uiView = ImageView(imageModel: imageModel)
return uiView
}
func updateUIView(_ uiView: ImageView, context: UIViewRepresentableContext<WebImage>) {
uiView.imageView.sd_setImage(with: imageModel.url)
uiView.imageView.contentMode = imageModel.contentMode
}
func url(_ url: URL?) -> Self {
imageModel.url = url
return self
}
func scaledToFit() -> Self {
imageModel.contentMode = .scaleAspectFit
return self
}
func scaledToFill() -> Self {
imageModel.contentMode = .scaleAspectFill
return self
}
}
class ImageView: UIView {
let imageView = UIImageView()
init(imageModel: ImageModel) {
super.init(frame: .zero)
addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = bounds
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}