I found following libraries to start a server locally.
https://github.com/httpswift/swifter
https://github.com/swisspol/GCDWebServer
For instance, I'm using swifter. It does compile for iOS.
I also added code to start a local server as follows.
class ViewController: UIViewController {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let server = HttpServer()
server["/hello"] = { .ok(.htmlBody("You asked for \($0)")) }
let semaphore = DispatchSemaphore(value: 0)
do {
try server.start(9080, forceIPv4: true)
print("Server has started ( port = \(try server.port()) ). Try to connect now...")
let config = WKWebViewConfiguration()
webView = WKWebView(frame: self.view.bounds, configuration: config)
/////////////////////////////
// What should be url here to point to local server?
webView.load(URLRequest(url: URL(string: "http://192.168.31.70:9080/hello")!))
/////////////////////////////
view = webView
semaphore.wait()
} catch {
print("Server start error: \(error)")
semaphore.signal()
}
}
}
Also, If I submit it to apple, is there any possibility of rejection because of starting a local server?
Can you elaborate on what you are trying to achieve by starting an HTTP server in-process?
If you need control over the way that responses are made, I would recommend looking at registering a custom URL protocol handler with WKWebViewConfiguration.setURLSchemeHandler(_:forURLScheme:). Then, ask the WKWebView to load a resource from that custom URL scheme, and your handler (that conforms to WKURLSchemeHandler) will get called, and you can construct a URLResponse however you'd like.
I tried Telegraph
Step 1. Open Podfile & add a dependency - pod 'Telegraph'
Step 2. Open AppDelegate.swift & put code as follows.
// Serve the Server from Build folder
let demoBundleURL = Bundle.main.url(forResource: "webApp", withExtension: nil)!
// and handle those requests at Path
serverHTTP.serveDirectory(demoBundleURL, "/webApp")
// Setting Custom Router - OPTIONAL
serverHTTP.httpConfig.requestHandlers.insert(DRHTTPMiddleWare(), at: 0)
// Start Server
try? serverHTTP.start(port: 9000, interface: "localhost")
Step 3. In ViewController.swift, put code as follows.
func loadWebView() {
guard let url = URL(string: "http://localhost:9000/webApp") else { return }
webView = WKWebView(
frame: self.view.bounds,
configuration: WKWebViewConfiguration()
)
webView.load(URLRequest(url: url))
view = webView
}
Related
I'm trying to load local html5 files to Xcode to create an ios App. I tried using a template and it uses both local and web based paths to create a very nice ios app in Xcode.
I need to learn about how to create a a webview app that has normal features and can load my local html5 webapps into Xcode for compiling an ios app.
I tried the following code, and it works alright when loading a url based html5 page.
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
https://developer.apple.com/documentation/webkit/wkwebview
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.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}}
I need to change the URL to local file path. The above code page from apple documentation suggests that I use load(_: ) to load local html files. I'm not sure how to use this function. So, I tried code samples from alternate sources, and here's some part of the code I'm trying with for the Webview app.
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
#IBOutlet var webView: WKWebView!
//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()
guard let fileUrl = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "www-WebsiteContent") else { return; }
//let urlPath = Bundle.main.url(forResource: "input", withExtension: "txt")
if fileUrl != "" {
let url = URL(fileURLWithPath: fileUrl)
//let url = init(_: fileURLWithPath, path: "www-WebsiteContent/index.html")
webView.loadFileURL(url, allowingReadAccessTo : url)
let request = URLRequest(url: url)
webView.load(request)
}
//let myURL = URL(string:"file:///www-WebsiteContent/index.html")
//let myRequest = URLRequest(url: myURL!)
//webView.load(myRequest)
//webView.loadFileURL(URL: , webView.allowingReadAccessTo readAccessURL: URL)
}}
I'm using latest Xcode version on Macbook Air with latest Swift 5 version. There's a main storyboard with the webview object, and a viewcontroller.swift file.
The error is that when I run the project, it doesn't display the index.html file in the www-WebsiteContent folder. Maybe I wasn't able to connect the webview overlay to the viewcontroller.swift file properly.
Things I need to understand:
Can I run the above code and compile it as a complete ios app? Or would I need to edit AppDelegate or SceneDelegate files too? I've only edited the viewcontroller.swift file as a new project.
How can I resize the webview overlay to automatic width and height of the ios device? I have an html5 webapp files that I need to convert to an ios app. How can I create this webview so that it fits all the device types screen sizes? My html5 app fits perfectly when viewed in the device browser.
I am trying to figure out how to properly connect an iOS app to a MySQL database. I have the following code in my Model.
import Foundation
protocol HomeModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocol!
let urlPath = "http://hourofswift.com/service.php" //this will be changed to the path where service.php lives
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
}
I have the PHP Web Service set up. That file is on the web server and has the credentials to access the database. What I am confused about is what I do if I don't want my database to be public. The iOS app is hitting the PHP Web Service and requires no credentials from the iOS app. That means anyone with an internet connection could send requests to the PHP Web Service. What do I do if I don't want the database to be public?
I want to show a website in a WKWebView in my iOS app for which I need to set specific http cookies for the user's session. The cookies are already stored in the shared HttpCookieStorage of the app.
At the moment, I try to copy them from there to the WKWebsiteDataStore of the web view before loading the website with the following code:
class ViewerViewController: UIViewController {
// MARK: - Properties
var webView: WKWebView!
// MARK: - Life Cycle
override func loadView() {
webView = WKWebView()
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
addCookiesToWebView {
print("Load website")
if let url = Bundle.main.url(forResource: "MyWebsite", withExtension: "html"), let html = try? String(contentsOf: url) {
self.webView.loadHTMLString(html, baseURL: url)
}
}
}
// MARK: - Functions
func addCookiesToWebView(completionHandler: #escaping (() -> Void)) {
let sharedCookies = HTTPCookieStorage.shared.cookies!
let webViewCookieStore = webView.configuration.websiteDataStore.httpCookieStore
var count = 0
sharedCookies.forEach { cookie in
DispatchQueue.main.async {
webViewCookieStore.setCookie(cookie) {
count += 1
print("Added cookie \(cookie.name)")
if count == sharedCookies.count {
completionHandler()
}
}
}
}
}
}
Now, what is incomprehensible for me, is that this sometimes works and the user is authenticated in his user session, but sometimes it doesn't.
It seems like there might be a race condition that leads to the web view loading the website before all the cookies have been copied? When I researched this problem I noticed that other people have problems with cookies in WKWebView as well, but I didn't find any solution so far that actually solves my issue.
Is there a bug in my code or is there a better approach for copying multiple cookies from HttpCookieStorage to a WKWebView?
I already have the script for checking for an internet connection in the viewDidLoad like below which works great. If there is a connection is loads the url and if not it loads a local html page with a pretty picture telling the user that there internet is down.
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.viewController = self
webView.navigationDelegate = self
ref = Database.database().reference()
if CheckInternet.Connection() {
let url = URL(string: "https://www.example.com/")
let URLrequest = URLRequest(url: url!)
self.webView.load(URLrequest)
} else {
let htmlpath = Bundle.main.path(forResource: "nointernet", ofType: "html")
let url = URL(fileURLWithPath: htmlpath!)
let request = URLRequest(url: url)
self.webView.load(request)
}
}
Problem is that if the users device loses an internet connection while they are using my app then it just hangs. I want to be able to have the app switch to the local html page automatically as soon as the connection is lost and switch back to the html (example.com) when the connection comes back online.
I have tried several different functions but none of them work. Is there an event that is triggered when the network connectivity changes on the users device that I could use my existing code?
I suggest to use Reachability
1.Install it via Pod:
use_frameworks!
pod 'ReachabilitySwift'
2.Variable declaration in your UIViewController
let reachability = Reachability()
3.Add observers and start the observer
// connected observer
reachability?.whenReachable = { reachability in
// Connected to Internet
}
// disconnected observer
reachability?.whenUnreachable = { _ in
// Not Connected to Internet
}
// start reachability observer
do {
try reachability?.startNotifier()
} catch {
print("Unable to start notifier")
}
4.Before disappering your UIViewController, stop the observer:
reachability?.stopNotifier()
Tried to make first app in Xcode: took my Web App folder and tried to implement it to XCode project with WebView. But got no success - always blank screen in simulator...
I started new project, created WebView and implement a folder with my Web App through File -> Add files to "MyProject" with option set to copy files and set url to local index.html in view controller. What am I doing wrong?
Project Structure:
-dist
--index.html
--scriptsbundle.js
--img
---myimages.png
-MyProject
-MyProject.xcodeproj
-MyProjectTests
-MyProjectUITests
My ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet var Webview: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: Bundle.path(forResource: "index", ofType: "html", inDirectory:"../dist")!)
let request = NSURLRequest(url: url as! URL)
Webview.loadRequest(request as URLRequest)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
As in the comment, that Amod Gokhale wrote, another article saved my life, but after a bit refactor:
let path = Bundle.main.path(forResource: "index", ofType:"html")
let url = NSURL(string: path!)
let request = NSURLRequest(url: url as! URL)