I am trying to open an Excel document that is located on a server. I wrote the following code but it always returns false for UIApplication.shared.canOpenURL(url as URL)
I think I am missing some requirement for deep linking to Excel. Why is iOS not able to understand ms-excel:ofe|u| format?
#objc static func openExcel() {
let originalString = "http://s000.tinyupload.com/download.php?file_id=23290165129849240725&t=2329016512984924072514118"
let encodedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
let encodedURLString = "ms-excel:ofe|u|" + encodedString! + "|n|TestDoc.xlsx|a|App"
if let url = NSURL(string: encodedURLString),
UIApplication.shared.canOpenURL(url as URL) {
UIApplication.shared.openURL(url as URL)
} else if let itunesUrl = NSURL(string: "https://itunes.apple.com/us/app/microsoft-excel/id586683407?mt=8&uo=4"), UIApplication.shared.canOpenURL(itunesUrl as URL) {
UIApplication.shared.openURL(itunesUrl as URL)
}
}
I have analyzed your code and found some mistakes. First, your URL was redirecting to somewhere, as per Microsoft documentation it can't handle redirecting URL's
The URL has to be encoded and must be a direct link to the file (not a
redirect). If the URL is in a format that Office cannot handle, or the
download simply fails, Office will not return the user to the invoking
application.
Here is Microsoft Documentation Link
The second mistake was you are only encoding the URL string containing site URL, you should consider the part after the scheme ms-excel: as a URL and should be encoded.
Because of improper encoding the let url = URL(string: encodedURLString) results nil that's why it is not working as expected.
Here is an example working code:
#objc static func openExcel() {
//replace the below url with yours. may be this one dosen't work
let originalString = "ofe|u|https://pgcconline.blackboard.com/webapps/dur-browserCheck-bb_bb60/samples/sample.xlsx"
let encodedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let encodedURLString = "ms-excel:" + encodedString!
if let url = URL(string: encodedURLString),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
} else if let itunesUrl = NSURL(string: "https://itunes.apple.com/us/app/microsoft-excel/id586683407?mt=8&uo=4"), UIApplication.shared.canOpenURL(itunesUrl as URL) {
UIApplication.shared.openURL(itunesUrl as URL)
}
}
Note: From iOS 9 you must whitelist any URL schemes your App wants to query in Info.plist under the LSApplicationQueriesSchemes key (an array of strings):
For example in our case:
When i try to open the URL in the question above I get redirected to this URL, so my guess would be that your code is fine, it just might be that your excel file you're trying to open is really an HTML page since tinyupload apparently blocks direct links to the files.
Maybe try opening a direct excel file download link, https://pgcconline.blackboard.com/webapps/dur-browserCheck-bb_bb60/samples/sample.xlsx (it was the first google result for 'xlsx file sample download')
Related
In order to make HTTP request call using URLSession,I need to convert string to URL first so I have tried everything but just can’t convert this piece of string to URL(string: ).
This is the string:
“http://api-aws-eu-qa-1.abc-cde.com/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99”
I can’t share the exact Url but format is all same.
The actual url with same format works fine in browser but no way in Swift, also that works fine in POSTMAN
I have also tried URLComponents which hepls me create the URL from components to URL but that fails with 400 status code response error.
I really appreciate the help, I am completely bogged down with this isuue and can’t proceed with my assignment.
Update: Tested with fiddler and request was not going through with this URL - "“http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99”"
But when removed this %E2%80%8B in fiddler and resend it worked.
Any thoughts ..?
String to URL
let url = URL(string: "the url string goes here")
URL to String
let url = URL(string: "the url string goes here")
let urlString = url.absoluteString
Creating URL from URLComponents
var url: URL? {
var components = URLComponents()
components.scheme = "https"
components.host = "domain goes here" //example: twitter.com
components.path = "/path/goes/here"
components.queryItems = [
URLQueryItem(name: "item1", value: string1),
URLQueryItem(name: "item2", value: string2)
]
return components.url
}
try to add HEADER to you request:
let url = URL(string : urlString)
var request = URLRequest(url : url)
request.setValue("Application/json", forHTTPHeaderField : "Content-Type")
Your URL is:
http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99`
The "host" portion is:
api-aws-eu-qa-1.abc-cde.com%E2%80%8B
%E2%80%8B encodes a ZERO WIDTH SPACE. This is a perfectly valid URL:
URL(string: "http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99")
=> Optional(http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99)
However, there is no such host as api-aws-eu-qa-1.abc-cde.com%E2%80%8B, so you should expect the actual connection to fail.
I expect that whatever is generating your URL strings has a bug.
If you are having trouble creating the URL itself (if URL(string:) return nil, then I expect this is not your actual URL string.
If you construct an URLComponents, the results are correct but may be slightly misleading:
URLComponents(string: "http://api-aws-eu-qa-1.abc-cde.com%E2%80%8B/v1/car-types/manufacturer?page=0&pageSize=10&wa_key=abc-cde-efg-44ccd99")?.host
Optional("api-aws-eu-qa-1.abc-cde.com")
While this looks like "api-aws-eu-qa-1.abc-cde.com", the string actually has a ZERO WIDTH SPACE at the end, which is invisible (but still part of the host field, which will correctly fail if you try to connect to it).
I use the code to load URL path hash fragment (such as: index.html#/some-hash-path; but WKWebview not load url.
let path = "www/index.html"
let page = "#/some-hash-path"
let url = Bundle.main.bundleURL.appendingPathComponent(path + page)
self.webView.loadFileURL(url, allowingReadAccessTo: Bundle.main.bundleURL)
It seem that it convert # -> %23 which make invalid path
I got stuck too trying to build the url in an apparently correct way for local files.
The url must be created with URL(string:) initializer, prefixing it manually with file://, and loaded with loadFileURL().
let url = URL(string: "file://\(indexPath)#\(section)")
webView.loadFileURL(url, allowingReadAccessTo: Bundle.main.bundleURL)
Construct URL from string work as expected:
let path = "www/index.html"
let page = "#/some-hash-path"
guard let parsedUrl = URL(string: Bundle.main.bundleURL.absoluteString + path + page) else {
return
}
self.webView.loadFileURL(parsedUrl, allowingReadAccessTo: Bundle.main.bundleURL)
I have link as below,
https://payood.test/loofpay/XUYZGlobal/WebForms/checkoutservice%20.aspx?paymentchannel=ddd&isysid=37268474138868&amount=25&description=Transaction From XXX&description2=dsdsd&tunnel=&original=ZXz4kfH9fiVIZ1jWBaGjww3hgwX84CGAahlCcsKWXvs%3d&responseUrl=http://localhost:55766/dsss/Response.aspx&hash=BE0481E5F9AA1C9F5B26A8E93A6ACAAD5888EDE9
When I try to open, its crashing saying below error.
fatal error: unexpectedly found nil while unwrapping an Optional value
Below is the code I am using
link = above link....
webView.loadRequest(URLRequest(url: URL(string: link)!))
Note:
If I use simple link as http://www.google.com, it works.
The link you've posted isn't a valid URL. It includes spaces in your description. You didn't encode this correctly.
As others mentioned, the problem is the link you provide to URL initializer is not a valid url and because of the !, your code can not initial a URL from the string in the following code and it will crash:
URL(string: link)!
So you have to change the string to some valid url before initializing a URL from it. Like this:
guard let escapedURLString = link.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else {
fatalError("Unknown URL string:\(link)")
}
guard let finalURL = URL(string: escapedURLString) else {
fatalError("Can not create a url from:\(escapedURLString)")
}
print(finalURL) //to check if it works
webView.loadRequest(URLRequest(url: finalURL))
I found that url is already encoded but API have issues that they are sending spaces in url.
So I replace spaces with %20
link = link.replacingOccurrences(of: " ", with: "%20")
This way all is working fine now.
Currently I have an iOS app that pulls prices and data from websites. So far its been working well, but I want to make it more accurate. To do so, I need to set the cookies for the URL request that I'm currently using String(contentsOf: _) for.
Current Process
let requestUrl: URL = URL(string: "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple")!
var content: String?
do {
content = try String(contentsOf: requestUrl)
} catch {
print("Error while converting an NSURL to String: \(error)")
}
if content != "" {
// I do things with the content of the requestUrl...
}
Could Use?
I thought that maybe I should use Alamofire instead to pull those website, and then parse the data.
I need to set the cookie that changes the store number to search, but have been unable to find a way to do so. Bellow is the code I have for pulling the websites data without setting a cookie.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Alamofire.request(requestUrl, method: .post).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the requestUrl...
}
}
Other Claims
I have found many different ways to set cookies through Alamofire that don't work, but if Alamofire isn't the way to do it, please inform me. I really need this to work, and I'm open to any and every suggestion.
It took four weeks to the day, but I figured it out! URLRequest and Alamofire were my glorious answers!
Create the URL to call.
let requestUrl: String = "http://www.samsclub.com/sams/search/searchResults.jsp?searchTerm=Apple"
Next make the URLRequest with the URL string, and set its http method.
var urlRequest = URLRequest(url: requestUrl)
urlRequest.httpMethod = "POST"
Then set the cookies for the URLRequest.
urlRequest.setValue("myPreferredClub=4969", forHTTPHeaderField: "Cookie")
urlRequest.httpShouldHandleCookies = true
Finally send the URLRequest with Alamofire, and use the response data in whatever way I wish.
Alamofire.request(urlRequest).responseString { response in
if let content: String = response.result.value {
// I do things with the content of the urlRequest...
}
}
I am developing iOS app in swift. We need to fetch images from amazon cloud front . I am able to fetch private content from cloud front in Objective C using openssl library in Xcode 6.4 using this reference link.
But I am using same library in swift , so getting importing error.
Please suggest it , How to create signed url for amazon cloud front to access private content in iOS.
If any other library to create signed url for amazon cloud front, please suggest it.
There is a great lib for that :) And this is a full code in Swift 2:
lazy var signedURL: String = {
let epochTime = NSDate().dateByAddingTimeInterval(60*5).timeIntervalSince1970
let resourceURL = "resource url"
let keyPairId = "your pair id"
let keyPairPrivateKeyName = "name of pem file"
let myurl = String(format: "%#?Expires=%.0f&Signature=%#&Key-Pair-Id=%#",
resourceURL,
epochTime,self.getSignature(resourceURL, expiresOn: epochTime, privateKey: keyPairPrivateKeyName), keyPairId)
return myurl
}()
func encodeStringForCloudFront(signature aSignature: String) -> String {
var signature = aSignature
signature = signature.stringByReplacingOccurrencesOfString("+", withString: "-")
signature = signature.stringByReplacingOccurrencesOfString("=", withString: "_")
signature = signature.stringByReplacingOccurrencesOfString("/", withString: "~")
return signature;
}
func getSignature(resourceURL: String, expiresOn: NSTimeInterval, privateKey keyPairPrivateKeyName: String) -> String {
let signString = String(format: "{\"Statement\":[{\"Resource\":\"%#\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":%.0f}}}]}", resourceURL, expiresOn)
guard let filePath = NSBundle.mainBundle().pathForResource(keyPairPrivateKeyName, ofType: "pem"),
let privateKeyData = NSData(contentsOfURL: NSURL(fileURLWithPath: filePath)) else {
return "Error loading pem file."
}
guard let str = String(data: privateKeyData, encoding: NSUTF8StringEncoding) else {
return "Private Key Data is not valid"
}
do {
let signatureString = try SwiftyRSA.signString(signString, privateKeyPEM: str)
return self.encodeStringForCloudFront(signature: signatureString)
} catch {
return "Something goes wrong URL NotValid"
}
}
As the linked thread states, it is extremely insecure to embed the Amazon CloudFront certificates on mobile devices.
Instead of generating the pre-signed URL on iOS, you should have a server and generate the pre-signed URL on your server. See Serving Private Content through CloudFront for more details on how to do this.
How to create signed url for amazon cloud front to access private content in iOS.
Its not clear to me what this has to do with OpenSSL. I also don't know what a signed URL is. Perhaps its a Amazon or Cloud Front marketing term.
With that said, I believe Python uses self authenticating URLs. A user agent can check authenticity of a package by visiting a URL based on a digest of the package. If the server responds with a 200, then its valid; otherwise its invalid. There's no page backing the URL.
Its not clear to me what you are trying to do, so I should probably stop there. For more reading, see:
Peter Gutmann's Engineering Security, around page 384
Python self authenticating URLs
You can use OpenSSL to create a self authenticating URL. You will have to modify the Base64 encoder, however. The default Base64 encoder uses the the standard Base64 alphabet from the old days (dating back to the 1980s and email). For web gear, you usually need to use the Base64 with the web safe alphabet.