Everytime I try to load another URL on a UIWebView i get the same error:
SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds.
My code about the webView is like:
#IBAction func changeUrl(sender: UIButton) {
if LEDON {
let urlStr = NSString(format: "%#/?Led=0", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
while(webView.isLoading) {
sender.isEnabled = false
}
sender.isEnabled = true
LEDON = false;
} else {
let urlStr = NSString(format: "%#/?Led=1", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
while(webView.isLoading) {
sender.isEnabled = false
}
sender.isEnabled = true
LEDON = true;
}
}
If I press the UIButton the first time the code works perfectly, but when I tap it again I get that error.
Where am I doing wrong?
"url" variable in the code is a global var and I already check that is correct.
Problem in
while(webView.isLoading) {
sender.isEnabled = false
}
You have frozen main thread and webView:decidePolicyForNavigationAction:request:frame:decisionListener: can't be invoke.
Try to use this:
func viewDidLoad()
{
...
webView.delegate = self;//UIWebView
//webView. navigationDelegate = self;//WKWebView
}
#IBAction func changeUrl(sender: UIButton) {
if LEDON {
let urlStr = NSString(format: "%#/?Led=0", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
sender.isEnabled = false
LEDON = false;
} else {
let urlStr = NSString(format: "%#/?Led=1", self.url)
let req = URLRequest(url: URL(string: urlStr as String)!)
webView.loadRequest(req)
sender.isEnabled = false
LEDON = true;
}
}
For UIWebView you need to use
func webViewDidFinishLoad(UIWebView)
{
yourButton.isEnabled = true
}
For WKWebView
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!)
{
yourButton.isEnabled = true
}
======================================
If you want use while loop try to change it for this:
while(webView.isLoading) {
sender.isEnabled = false
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.5))
}
You need to allow http and https on your app :
In your info.plist :
In Info.plist file add a dictionary with key 'NSAppTransportSecurity'
Add another element inside dictionary with key 'Allow Arbitrary Loads'
Related
I am integrating sharing options from my app to Snapchat.
I have a dynamic URL obtained in an object and clicking the Snapchat's share button directly opens the app if Snapchat is there on the device and show the text with the link. I am using the below code to share which gives an error on Snapchat. Below is my Code.
func shareTextOnSnapchat(obj:VideoData) {
let shaUrl = URL(string: obj.share_url ?? "")
if let myURL:URL = shaUrl{
let promoText = "Check out this great new video from \(obj.name ?? ""), I found on talent app"
let shareString = "snapchat://text=\(promoText)&url=\(myURL)"
let escapedShareString = shareString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let url = URL(string: escapedShareString)
UIApplication.shared.openURL(url!)
}
}
I have used this to post video to snapchat. You have option to either post text or a video.
Pod used
pod 'SnapSDK', :subspecs => ['SCSDKCreativeKit']
import SCSDKCreativeKit
var scInstalled = false
override func viewDidLoad() {
super.viewDidLoad()
scInstalled = schemeAvailable(scheme: "snapchat://")
}
func ShowSnapchat(){
if scInstalled {
//shareTextOnSnapchat(obj:videoObj ?? VideoData())
shareFileOnSnapchat(obj:videoObj ?? VideoData())
}else{
downloadSharingAppAlert(appName:"Snapchat")
}
}
func shareTextOnSnapchat(obj:VideoData) {
let shaUrl = URL(string: obj.share_url ?? "")
if let myURL:URL = shaUrl{
let originalString = "\(myURL)"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed)
//let url = URL(string: "snapchat://snap?text=\(escapedString!)")
let url = URL(string: "https://www.snapchat.com/send?text=\(escapedString!)")
if UIApplication.shared.canOpenURL(url! as URL)
{
UIApplication.shared.open(url! as URL, options: [:], completionHandler: nil)
}
}
}
func shareFileOnSnapchat(obj:VideoData){
//// SHARE VIDEO
LoadingOverlay.shared.showLoaderView(view: self.view)
let shaUrl = URL(string: obj.output_vid ?? "")
if let myURL:URL = shaUrl{
let snapVideo = SCSDKSnapVideo(videoUrl: myURL)
let snapContent = SCSDKVideoSnapContent(snapVideo: snapVideo)
// Send it over to Snapchat
snapAPI.startSending(snapContent) { (error) in
if let error = error {
print(error.localizedDescription)
LoadingOverlay.shared.hideLoaderView()
MyCustomAlert.sharedInstance.ShowAlert(vc: self, myTitle: "", myMessage: StringClass.sharedInstance.lcStr_oopsSomethingWentwrong)
} else {
// success
print("Posted to snapchat")
LoadingOverlay.shared.hideLoaderView()
MyCustomAlert.sharedInstance.ShowAlert(vc: self, myTitle: "", myMessage: StringClass.sharedInstance.lcStr_postedToSnapchat)
}
}
}
}
}
func downloadSharingAppAlert(appName:String){
var appStoreURL = "https://apps.apple.com/in/app/snapchat/id447188370"
//Open Appstore for Download
}
I have a question about WKWebview.
First, I have a UITabbarViewController(tab1, tab2), and two ViewControllers.
In ViewController1 have two button (button1, button2) which action is click the tabbar tab2 to present the ViewController2 and bring different url string.
In ViewController2 have a WKWebView, and load the request of url string.
I work fine in simulator, but build in device and work fine at first time and the then I tap the tabbar tab1 and back to ViewController1.
I click the button2 and present the ViewController2.
And I also set breakpoint, the WKWebview have run the load request function.
But the WKWebview also show me the button1 url content, not button2 url content. When I back and click button2 again, it's work. Why the WKWebView don't refresh at first time?
Thanks.
Xcode 9.4.1, device iOS 12.0.1(16A404)
class ViewController1: UIViewController {
#objc func btnTapped(sender: UIButton) {
if let vc = self.navigationController?.parent as? ViewController {
if let number = item?.number {
let domainPath = “\(customURL!.absoluteString)"
let extPath = "detail/\(number)/&topPageBack=list"
let encodestr = extPath.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let finalPath = domainPath.appending("/").appending(encodestr!)
if let url = URL(string: finalPath) {
vc.loadSpecificURL = url
}
vc.tabBarView.buttonClick(tag: 1)
}
}
}
}
class ViewController2: UIViewController {
lazy var webViewController: CustomWKWebViewController = {
let controller = CustomWKWebViewController()
controller.wKWebViewPage = .searchPage
return controller
}()
var loadURL: URL?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let url = loadURL {
webViewController.reloadWebView(url: url)
loadURL = nil
}
}
}
class CustomWKWebViewController: UIViewController {
private func settingWebView() -> WKWebView {
let userScript = WKUserScript(source: source, injectionTime: .atDocumentStart, forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.add(self, name: "Login")
userContentController.add(self, name: "Other")
userContentController.add(self, name: “LD”)
userContentController.addUserScript(userScript)
let config = WKWebViewConfiguration()
config.userContentController = userContentController
webView = WKWebView(frame: .zero, configuration: config)
webView!.navigationDelegate = self
webView!.uiDelegate = self
webView!.scrollView.bounces = false
webView!.allowsBackForwardNavigationGestures = true
webView!.backgroundColor = .clear
webView!.scrollView.backgroundColor = .clear
if let request = getRequest() {
webView!.load(request)
}
return webView!
}
func reloadWebView(url: URL?) {
if let url = url, let webView = self.webView {
var requestForBlank = URLRequest(url: URL(string: "about:blank")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3)
requestForBlank.httpMethod = "POST"
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3)
request.httpMethod = "POST"
webView.load(requestForBlank)
webView.load(request)//breakpoint always break here, but the view don't load request.
}
}
}
First you check if web url not nil, then also call the else part of if.
if let url = webview.url {
webview.reload()
} else {
webview.load(URLRequest(url: originalURL))
}
I am using Subsonic so mp3 files are served to me via a webservice.
When I test using files that have a .mp3 extension this code works. When I use it with the link I have below it does not.
var player: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://192.168.1.74:4040/rest/download?u=admin&p=admin&v=1.12.0&c=myapp&id=114&format=mp3")!
let playerItem = CachingPlayerItem(url: url)
playerItem.delegate = self
player = AVPlayer(playerItem: playerItem)
player.automaticallyWaitsToMinimizeStalling = false
player.play()
}
}
Browsing the link in 'url' provides me with the file I'd expect. I have also successfully downloaded the file saved it as MP3 and played it from my documents container, this is not how I want the application to work though.
TL:DR how can I get my application to play audio from a rest API without an extension
You can use AVAssetResourceLoader to play audio without extension.
Here is an example.
First, configure the delegate of resourceloader
var playerAsset: AVAsset!
if fileURL.pathExtension.count == 0 {
var components = URLComponents(url: fileURL, resolvingAgainstBaseURL: false)!
components.scheme = "fake" // make custom URL scheme
components.path += ".mp3"
playerAsset = AVURLAsset(url: components.url!)
(playerAsset as! AVURLAsset).resourceLoader.setDelegate(self, queue: DispatchQueue.global())
} else {
playerAsset = AVAsset(url: fileURL)
}
let playerItem = AVPlayerItem(asset: playerAsset)
then, read audio's data and responds to the resource loader
// MARK: - AVAssetResourceLoaderDelegate methods
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
if let url = loadingRequest.request.url {
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!
components.scheme = NSURLFileScheme // replace with the real URL scheme
components.path = String(components.path.dropLast(4))
if let attributes = try? FileManager.default.attributesOfItem(atPath: components.url!.path),
let fileSize = attributes[FileAttributeKey.size] as? Int64 {
loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
loadingRequest.contentInformationRequest?.contentType = "audio/mpeg3"
loadingRequest.contentInformationRequest?.contentLength = fileSize
let requestedOffset = loadingRequest.dataRequest!.requestedOffset
let requestedLength = loadingRequest.dataRequest!.requestedLength
if let handle = try? FileHandle(forReadingFrom: components.url!) {
handle.seek(toFileOffset: UInt64(requestedOffset))
let data = handle.readData(ofLength: requestedLength)
loadingRequest.dataRequest?.respond(with: data)
loadingRequest.finishLoading()
return true
} else {
return false
}
} else {
return false
}
} else {
return false
}
}
#IBAction func download(_ sender: Any) {
if let url = URL(string: "\(imgURL)") {
UIApplication.shared.openURL(url as URL)
}
print(imgURL)
}
The url wont open if i press the button. The consol says the right url: https://scontent-ams3-1.cdninstagram.com/t51.2885-19/18514045_212505245924563_1350282415863496704_a.jpg but the url wont open. Please help! Thanks
let urlstr = "\(profile_pic_url_hd)"
if var comps = URLComponents(string: urlstr) {
var path = comps.path
var pathComps = path.components(separatedBy: "/")
pathComps.remove(at: 2) // this removes the s320x320
path = pathComps.joined(separator: "/")
comps.path = path
if let newStr = comps.string {
print(newStr)
self.imgURL = "\(newStr)"
}
}
I have a download function working perfectly, on click of my button, the file is being download correctly.
What I am trying to achieve, If I put the App in the background or change screen while it's downloading the file, I'd like the download to be continued. Currently if the App is in the background ,the download stop and user need to restart it from zero.
How is this possible to make ?? Below is my download function, I tried to add a background download without success.
func createDownloadTask() {
let downloadRequest = URLRequest(url: URL(string: "\(posts[selectedIndexPath].link)")!)
let session = Foundation.URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)
downloadTask = session.downloadTask(with: downloadRequest)
downloadTask!.resume()
}
and
#IBAction func startDownload(_ sender: UIButton) {
let urlString = "\(posts[selectedIndexPath].link)"
DispatchQueue.global(qos: .default).async(execute: {
print("downloadVideo");
let url=NSURL(string: urlString);
let urlData=NSData(contentsOf: url! as URL);
if((urlData) != nil)
{
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileName = urlString as NSString;
let filePath="\(documentsPath)/\(fileName.lastPathComponent)";
DispatchQueue.main.async(execute: { () -> Void in
print(filePath)
urlData?.write(toFile: filePath, atomically: true);
print("video Saved to document directory of app");
self.downloadButton.alpha = 0;
self.progressView.alpha = 0;
self.cardboardButton.alpha = 1;
self.videoButton.alpha = 1;
self.removefile.alpha = 1;
})
}
})
}
You need to use UIBackgroundTaskIdentifier. You can start some task in background with beginBackgroundTask see:
https://developer.apple.com/reference/uikit/uiapplication/1623031-beginbackgroundtask.
System will give you some time and you can finish your task. If the time expire you will receive handler.See example that I use to upload a image
static var backgroundUpload:UIBackgroundTaskIdentifier?
static func praiseCollegue(praiseCollegueId:Int,image:UIImageView,praisedBy:Int,praiseText:String,praiseCategory:Int,successBlock: (()->())?,errorBlock: (()->())?){
backgroundUpload = UIApplication.shared.beginBackgroundTask(expirationHandler: {
if let task = self.backgroundUpload{
UIApplication.shared.endBackgroundTask(task)
}
})
let url = NSURL(string: "someUrl")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
request.setValue(InfoManager.sharedInstance.tokenInfo?.accessToken, forHTTPHeaderField: "AccessToken")
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
if let responseData = data{
do {
if let dict = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: AnyObject]{
if let errorCode = dict["errorCode"] as? Int{
if(errorCode == 1){
successBlock?()
if let task = self.backgroundUpload{
UIApplication.shared.endBackgroundTask(task)
}
}
else{
errorBlock?()
if let task = self.backgroundUpload{
UIApplication.shared.endBackgroundTask(task)
}
}
}
}
}
}
}
task.resume()
}