Retrieving and Parsing Text From Specific Webpage Using Swift - ios

I need to retrieve the text from a specific website. However, I only need a few parts of it. How can I accomplish this using swift.
I have found the following in objective-c, but am not sure it provides how to reference it from a specific site:
NSString *webString = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerText"];
NSScanner *stringScanner = [NSScanner scannerWithString:webString];
NSString *content = [[NSString alloc] init];
while ([stringScanner isAtEnd] == NO) {
[stringScanner scanUpToString:#"Start of the text you want" intoString:null];
[stringScanner scanUpToString:#"End of the text you want" intoString:&content];
}`
I have put an example of what I mean below:
Again, I would like to accomplish this using Swift.

If your HTML was easily targetable with identifiers or class names, I would suggest using a library such as Kanna. But I've had a look at your page and the text you need is lost amidst an ocean of divs...
So I've quickly hacked a way to get your text with componentsSeparatedByString: I'm cutting the HTML in blocks until I get to the part we're interested in.
Note that it's far from being the most efficient way: instead of using componentsSeparatedByString you should come with a way of identifying the HTML block you want and search for it with NSScanner.
That being said, here's my example of a working hack, tested in a Playground:
enum CustomErrors : String, ErrorType {
case InvalidURL = "Invalid URL"
}
do {
let str = "http://www.golfwrx.com/328370/mizuno-to-offer-custom-grips-at-no-additional-charge/"
guard let url = NSURL(string: str) else { throw CustomErrors.InvalidURL }
let html = try String(contentsOfURL: url)
let separator1 = "<div class='mailmunch-forms-before-post' style='display: none !important;'></div><p>"
let temp = html.componentsSeparatedByString(separator1)
let separator2 = "</p>\n<p>"
let temp2 = temp[1].componentsSeparatedByString(separator2)
let separator3 = "</p><div class='mailmunch-forms-in-post-middle'"
let separated = temp2[1].componentsSeparatedByString(separator3)
let result = separated[0]
print(result)
} catch {
print(error)
}
Note: my example is in Swift 2 (Xcode 7).

Sorry about the specifics, I'm an Objective-C guy. but, here is an example of how to use NString to get the contents of a websites HTML
NSString *url = #"http://www.example.com"; // Your URL
NSURL *urlRequest = [NSURL URLWithString:url]; // Make a request with your URL
NSError *err = nil; // Error handler
NSString *html = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&err]; // Try to get the HTML in the string
if(err)
{
//Do something as it didn't work! Maybe a connection problem
}
else
{
// Use NScanner on html string
}
http://nshipster.com/nsscanner/ is a good place to learn about NScanner for swift
EDIT: Here is the above translated to swift
var err: NSError? // Error handler
let url: NSURL = NSURL(string: "http://www.example.com") // NSURL, put your website URL in here
let string = NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &err) // String will now hold your HTML
// Now use NScanner (See Link) to parse the HTML output
My swift is rusty. but this might help you. This is roughly translated but outlines exactly what you need

Related

How can I open a URL without specifying HTTP or HTTPS in iOS?

In my iOS app I am opening links using the code below:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",myurl]]];
The links come dynamically and HTTP/HTTPS is not provided.
I cannot hardcode HTTP or HTTPS because I don't know if the URL has HTTP or HTTPS. How can I open a URL without specifying HTTP or HTTPS?
Solution for Swift:
let urlString = "example.com"
let urlHasHttpPrefix = urlString.hasPrefix("http://")
let urlHasHttpsPrefix = urlString.hasPrefix("https://")
let validUrlString = (urlHasHttpPrefix || urlHasHttpsPrefix) ? urlString : "http://\(urlString)"
I think this a better approach than the ones presented here, since it avoids string comparison & manipulation.
public extension URL {
var sanitise: URL {
if var components = URLComponents(url: self, resolvingAgainstBaseURL: false) {
if components.scheme == nil {
components.scheme = "http"
}
return components.url ?? self
}
return self
}
}
Who said you don't know whether url contain http or not? You can find out...
In prefixheader.pch write below.
#define contains(str1, str2) ([str1 rangeOfString: str2 ].location != NSNotFound)
Then in your .m write below.
if (!contains(myurl, "http")) {
myurl = [NSString stringWithFormat:#"http://%#", myurl];
}
You are done!!!
Let me know if you need anything else.
Matching with rangeOfString is not a good approach.
You can match it as:
NSString *urlScheme = [url scheme];
if (urlScheme == nil) {
url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#",urlString]];
}
And you don't have to worry about whether it's http or https. whenever you'll hit a url on http it'll automatically redirects to https

iOS URL Scheme Microsoft Outlook App

This seems impossible to find, unless perhaps there isn't one for it. But anyone know (if there is one) the iOS URL Scheme for opening the Microsoft Outlook Mobile App right to the Compose Screen with pre-defined TO_EMAIL, SUBJECT and BODY?
Here is a link I found that helped me out with the IOS Outlook URL Scheme.
From that I was able to come up with this code:
// Create an array of recipients for the email.
NSArray* emailRecipients = #[#"example#email.com", #"example2#email.com"];
// Create a mutable string to hold all of the recipient email addresses and add the first one.
NSMutableString* emailTo = [[NSMutableString alloc] initWithString:emailRecipients[0]];
// Loop through all of the email recipients except for the first one.
for (int index = 1; index < emailRecipients.count; index++)
{
// Add a semicolon and then the email address at the current index.
[emailTo appendFormat:#";%#", emailRecipients[index]];
}
// Get the email subject from the subject text field.
NSString* emailSubject = fieldSubject.text;
// Encode the string for URL.
NSString* encodedSubject = [emailSubject stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
// Get the email body from the body text field.
NSString* emailBody = fieldBody.text;
// Encode the string for URL.
NSString* encodedBody = [emailBody stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
// See if the subject or body are empty.
if (![emailSubject length] || ![emailBody length])
{
// Exit.
return;
}
// Create a string with the URL scheme and email properties.
NSString *stringURL = [NSString stringWithFormat:#"ms-outlook://compose?to=%#&subject=%#&body=%#", emailTo, encodedSubject, encodedBody];
// Convert the string to a URL.
NSURL *url = [NSURL URLWithString:stringURL];
// Open the app that responds to the URL scheme (should be Outlook).
[[UIApplication sharedApplication] openURL:url];
The URL scheme for Outlook is: ms-outlook://compose?to=example#email.com&subject=Subject&body=Message
Hope this helps!
Swift
func outlookDeepLink(subject: String, body: String, recipients: [String]) throws -> URL {
enum MailComposeError: Error {
case emptySubject
case emptyBody
case unexpectedError
}
guard !subject.isEmpty else { throw MailComposeError.emptySubject }
guard !body.isEmpty else { throw MailComposeError.emptyBody }
let emailTo = recipients.joined(separator: ";")
var components = URLComponents()
components.scheme = "ms-outlook"
components.host = "compose"
components.queryItems = [
URLQueryItem(name: "to", value: emailTo),
URLQueryItem(name: "subject", value: subject),
URLQueryItem(name: "body", value: body),
]
guard let deepURL = components.url else { throw MailComposeError.unexpectedError }
return deepURL
}
Usage
try! UIApplication.shared.open(
outlookDeepLink(
subject: "subject",
body: "body",
recipients: ["example#email.com", "example2#email.com"]
)
)
Note that:
Don't forget to tell iOS you are going to call ms-outlook. (Add it to LSApplicationQueriesSchemes in info.plist, Otherwise, You will get an clear error message in console if you forget it)
Also don't forget to check if the app actually exists before trying to open the url. (canOpenURL is here to help)

How to get the html content from UIWebView?

I'm loading a web page using UIWebView
let urlStr = "http://duckduckgo.com"
let urlReq = NSMutableURLRequest(URL: NSURL(string: urlStr)!)
webView.loadRequest(urlReq)
Then, when the page has finished loading, I want to access the html content
func webViewDidFinishLoad(webView: UIWebView) {
let href = webView.stringByEvaluatingJavaScriptFromString("window.location.href")
println("window.location.href = \(href)")
let doc = webView.stringByEvaluatingJavaScriptFromString("document")
println("document = \(doc)")
}
But document just return an empty string (Optional("")). The window.location.href part is working fine. What I'm I doing wrong?
I think you have to evaluate the javascript like this:
let doc = webView.stringByEvaluatingJavaScriptFromString("document.documentElement.outerHTML")
In this case you get the entire HTML.
Now, when UIWebView is deprecated, you'll need to use syntax like this:
webView.evaluateJavaScript("document.documentElement.outerHTML") { (html, error) in
guard let html = html as? String else {
print(error)
return
}
// Here you have HTML of the whole page.
}
After that you can create a function like this that'll easily get HTML from webView:
func getHTML(_ completion: #escaping (String) -> ()) {
webView.evaluateJavaScript("document.documentElement.outerHTML") { (html, error) in
guard let html = html as? String else {
print(error)
return
}
completion(html)
}
}
getHTML { html in
// Here you have HTML string
print(html) // for example...
}
I Found the solution of problem regarding jqxWidget.
That UIWebView content were referencing .js and .css file which is already bundled in App. I had just only add the base url of App's MainBundle.
NSString *html = [self.webview1 stringByEvaluatingJavaScriptFromString: #"document.documentElement.outerHTML"]; //document.body.innerHTML
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[objFullScreenViewCntrl.webview2 loadHTMLString:html baseURL:baseURL];

WKWebView not loading local files under iOS 8

For previous iOS 8 betas, load a local web app (in Bundle) and it works fine for both UIWebView and WKWebView, and I even ported a web game using the new WKWebView API.
var url = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("car", ofType:"html"))
webView = WKWebView(frame:view.frame)
webView!.loadRequest(NSURLRequest(URL:url))
view.addSubview(webView)
But in beta 4, I just got a blank white screen (UIWebView still work), looks like nothing is loaded or executed. I saw an error in the log:
Could not create a sandbox extension for /
Any help to guide me to the right direction? Thanks!
They finally solved the bug! Now we can use -[WKWebView loadFileURL:allowingReadAccessToURL:].
Apparently the fix was worth some seconds in WWDC 2015 video 504 Introducing Safari View Controller
For iOS8 ~ iOS10 (Swift 3)
As Dan Fabulish's answer states this is a bug of WKWebView which apparently is not being solved any time soon and as he said there is a work-around :)
I am answering just because I wanted to show the work-around here. IMO code shown in https://github.com/shazron/WKWebViewFIleUrlTest is full of unrelated details most people are probably not interested in.
The work-around is 20 lines of code, error handling and comments included, no need of a server :)
func fileURLForBuggyWKWebView8(fileURL: URL) throws -> URL {
// Some safety checks
if !fileURL.isFileURL {
throw NSError(
domain: "BuggyWKWebViewDomain",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")])
}
try! fileURL.checkResourceIsReachable()
// Create "/temp/www" directory
let fm = FileManager.default
let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("www")
try! fm.createDirectory(at: tmpDirURL, withIntermediateDirectories: true, attributes: nil)
// Now copy given file to the temp directory
let dstURL = tmpDirURL.appendingPathComponent(fileURL.lastPathComponent)
let _ = try? fm.removeItem(at: dstURL)
try! fm.copyItem(at: fileURL, to: dstURL)
// Files in "/temp/www" load flawlesly :)
return dstURL
}
And can be used as:
override func viewDidLoad() {
super.viewDidLoad()
var fileURL = URL(fileURLWithPath: Bundle.main.path(forResource:"file", ofType: "pdf")!)
if #available(iOS 9.0, *) {
// iOS9 and above. One year later things are OK.
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
} else {
// iOS8. Things can (sometimes) be workaround-ed
// Brave people can do just this
// fileURL = try! pathForBuggyWKWebView8(fileURL: fileURL)
// webView.load(URLRequest(url: fileURL))
do {
fileURL = try fileURLForBuggyWKWebView8(fileURL: fileURL)
webView.load(URLRequest(url: fileURL))
} catch let error as NSError {
print("Error: " + error.debugDescription)
}
}
}
WKWebView can't load content from file: URLs via its loadRequest: method. http://www.openradar.me/18039024
You can load content via loadHTMLString:, but if your baseURL is a file: URL, then it still won't work.
iOS 9 has a new API that will do what you want, [WKWebView loadFileURL:allowingReadAccessToURL:].
There is a workaround for iOS 8, demonstrated by shazron in Objective-C here https://github.com/shazron/WKWebViewFIleUrlTest to copy files into /tmp/www and load them from there.
If you're working in Swift, you could try nachos4d's sample instead. (It's also much shorter than shazron's sample, so if you're having trouble with shazron's code, give that a try instead.)
An example of how to use [WKWebView loadFileURL:allowingReadAccessToURL:] on iOS 9.
When you are moving the web folder to a project, select "Create folder references"
Then use code that is something like this(Swift 2):
if let filePath = NSBundle.mainBundle().resourcePath?.stringByAppendingString("/WebApp/index.html"){
let url = NSURL(fileURLWithPath: filePath)
if let webAppPath = NSBundle.mainBundle().resourcePath?.stringByAppendingString("/WebApp") {
let webAppUrl = NSURL(fileURLWithPath: webAppPath, isDirectory: true)
webView.loadFileURL(url, allowingReadAccessToURL: webAppUrl)
}
}
In the html file use filepaths like this
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
not like this
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
An example of directory that is moved to a xcode project.
Temporary workaround: I'm using GCDWebServer, as suggested by GuidoMB.
I first find the path of my bundled "www/" folder (which contains an "index.html"):
NSString *docRoot = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"www"].stringByDeletingLastPathComponent;
... then start it up like so:
_webServer = [[GCDWebServer alloc] init];
[_webServer addGETHandlerForBasePath:#"/" directoryPath:docRoot indexFilename:#"index.html" cacheAge:3600 allowRangeRequests:YES];
[_webServer startWithPort:port bonjourName:nil];
To stop it:
[_webServer stop];
_webServer = nil;
Performance appears fine, even on an iPad 2.
I did notice a crash after the app goes into the background, so I stop it on applicationDidEnterBackground: and applicationWillTerminate:; I start/restart it on application:didFinishLaunching... and applicationWillEnterForeground:.
[configuration.preferences setValue:#"TRUE" forKey:#"allowFileAccessFromFileURLs"];
This solved the problem for me
iOS 8.0+ dev.apple.com
also this seems to worked just fine too...
NSString* FILE_PATH = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"htmlapp/FILE"];
[self.webView
loadFileURL: [NSURL fileURLWithPath:FILE_PATH]
allowingReadAccessToURL: [NSURL fileURLWithPath:FILE_PATH]
];
Besides solutions mentioned by Dan Fabulich, XWebView is another workaround. [WKWebView loadFileURL:allowingReadAccessToURL:] is implemented through extension.
I cannot comment yet, so I am posting this as a separate answer.
This is an objective-c version of nacho4d's solution. The best workaround I've seen so far.
- (NSString *)pathForWKWebViewSandboxBugWithOriginalPath:(NSString *)filePath
{
NSFileManager *manager = [NSFileManager defaultManager];
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"www"];
NSError *error = nil;
if (![manager createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(#"Could not create www directory. Error: %#", error);
return nil;
}
NSString *destPath = [tempPath stringByAppendingPathComponent:filePath.lastPathComponent];
if (![manager fileExistsAtPath:destPath]) {
if (![manager copyItemAtPath:filePath toPath:destPath error:&error]) {
NSLog(#"Couldn't copy file to /tmp/www. Error: %#", error);
return nil;
}
}
return destPath;
}
In the case that you are trying to display a local image in the middle of a larger HTML string like: <img src="file://...">, it still does not appear on device so I loaded the image file into NSData and was able to display it by replacing the src string with the data itself. Sample code to help build the HTML string to load into WKWebView, where result is what will replace what's inside the quotes of src="":
Swift:
let pathURL = NSURL.fileURLWithPath(attachmentFilePath)
guard let path = pathURL.path else {
return // throw error
}
guard let data = NSFileManager.defaultManager().contentsAtPath(path) else {
return // throw error
}
let image = UIImage.init(data: data)
let base64String = data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
result += "data:image/" + attachmentType + "base64," + base64String
var widthHeightString = "\""
if let image = image {
widthHeightString += " width=\"\(image.size.width)\" height=\"\(image.size.height)\""
}
result += widthHeightString
Objective-C:
NSURL *pathURL = [NSURL fileURLWithPath:attachmentFilePath];
NSString *path = [pathURL path];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
UIImage *image = [UIImage imageWithData:data];
NSString *base64String = [data base64EncodedStringWithOptions:0];
[result appendString:#"data:image/"];
[result appendString:attachmentType]; // jpg, gif etc.
[result appendString:#";base64,"];
[result appendString:base64String];
NSString *widthHeightString = #"\"";
if (image) {
widthHeightString = [NSString stringWithFormat:#"\" width=\"%f\" height=\"%f\"", image.size.width, image.size.height];
}
[result appendString:widthHeightString];
I'm using the below. Has some extra stuff I'm working on but you can see where I've commented out the loadRequest and am substituting loadHTMLString call. Hope this helps until they fix the bug.
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
var theWebView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
var path = NSBundle.mainBundle().pathForResource("index", ofType: "html", inDirectory:"www" )
var url = NSURL(fileURLWithPath:path)
var request = NSURLRequest(URL:url)
var theConfiguration = WKWebViewConfiguration()
theConfiguration.userContentController.addScriptMessageHandler(self, name: "interOp")
theWebView = WKWebView(frame:self.view.frame, configuration: theConfiguration)
let text2 = String.stringWithContentsOfFile(path, encoding: NSUTF8StringEncoding, error: nil)
theWebView!.loadHTMLString(text2, baseURL: nil)
//theWebView!.loadRequest(request)
self.view.addSubview(theWebView)
}
func appWillEnterForeground() {
}
func appDidEnterBackground() {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func userContentController(userContentController: WKUserContentController!, didReceiveScriptMessage message: WKScriptMessage!){
println("got message: \(message.body)")
}
}
For who must workaround this issue under iOS8:
If your page is not complicated, you might choose to make the page as a Single Page Application.
In other words, to embed all the resources into the html file.
To do:
1. copy your js/css file's content into / tags in the html file respectively;
2. convert your image files into svg to replace the accordingly.
3. load the page as before, using [webView loadHTMLString: baseURL:], for example
It was a bit different to styling a svg image, but it should not block you so much.
It seemed that the page render performance decreased a bit, but it was worthy to have such a simple workaround worked under iOS8/9/10.
In the same line of GCDWebServer, I am using SImpleHttpServer (http://www.andyjamesdavies.com/blog/javascript/simple-http-server-on-mac-os-x-in-seconds) and then loadRequest with the localhost url. With this approach you do not have to add any library, but the website files won't be in the bundle so It will not be deliverable. Because of that, this would be more appropriate for Debug cases.
I’ve managed to use PHP’s web server on OS X. Copying to the temporary/www directory did not work for me. The Python SimpleHTTPServer complained about wanting to read MIME types, probably a sandboxing issue.
Here’s a server using php -S:
let portNumber = 8080
let task = NSTask()
task.launchPath = "/usr/bin/php"
task.arguments = ["-S", "localhost:\(portNumber)", "-t", directoryURL.path!]
// Hide the output from the PHP server
task.standardOutput = NSPipe()
task.standardError = NSPipe()
task.launch()
#nacho4d solution is good. I want to change it a little but I don't know how to change it in your post. So I put it here I hope you don't mind. thanks.
In case you have a www folder there are many other files such as png, css, js etc. Then you have to copy all files to tmp/www folder.
for example, you have a www folder like this:
then in Swift 2.0:
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().resourcePath! + "/www";
var fileURL = NSURL(fileURLWithPath: path)
if #available(iOS 9.0, *) {
let path = NSBundle.mainBundle().pathForResource("index", ofType: "html", inDirectory: "www")
let url = NSURL(fileURLWithPath: path!)
self.webView!.loadRequest(NSURLRequest(URL: url))
} else {
do {
fileURL = try fileURLForBuggyWKWebView8(fileURL)
let url = NSURL(fileURLWithPath: fileURL.path! + "/index.html")
self.webView!.loadRequest( NSURLRequest(URL: url))
} catch let error as NSError {
print("Error: \(error.debugDescription)")
}
}
}
the function fileURLForBuggyWKWebView8 is copied from #nacho4d:
func fileURLForBuggyWKWebView8(fileURL: NSURL) throws -> NSURL {
// Some safety checks
var error:NSError? = nil;
if (!fileURL.fileURL || !fileURL.checkResourceIsReachableAndReturnError(&error)) {
throw error ?? NSError(
domain: "BuggyWKWebViewDomain",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")])
}
// Create "/temp/www" directory
let fm = NSFileManager.defaultManager()
let tmpDirURL = NSURL.fileURLWithPath(NSTemporaryDirectory())
try! fm.createDirectoryAtURL(tmpDirURL, withIntermediateDirectories: true, attributes: nil)
// Now copy given file to the temp directory
let dstURL = tmpDirURL.URLByAppendingPathComponent(fileURL.lastPathComponent!)
let _ = try? fm.removeItemAtURL(dstURL)
try! fm.copyItemAtURL(fileURL, toURL: dstURL)
// Files in "/temp/www" load flawlesly :)
return dstURL
}
Try using
[webView loadHTMLString:htmlFileContent baseURL:baseURL];
Seems it's still working. Yet.

URL encoding iOS NSURL error

URL which opens in Firefox,Chrome browsers on desktop, doesn't open in WebView on iPhone.
This URL is supposedly accessing a GET request.
When creating the NSURL without percentescaping the url doesn't get generated.
When using percentescape the url redirects to a Bad url content.
Is there a different encoding used on desktop browsers and not on the iPhone? or mobile Safari?
Are there different ways to encode the URL in iOS other than using
-stringByAddingPercentEscapesUsingEncoding
-CFURLCreateStringByAddingPercentEscapes
which generates bad request content pages from server.
Any help would be really great, Thanks.
EDIT:
The URL been generated is as below http://something.test.com/iostest/index.html?{"a":"b"}
Managed to figure that not encoding the curly brackets is causing the issue in iOS.
as in
NSString *tempUrlSting = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)tempURLA,CFSTR("{}"), CFSTR("\""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)));
NSURL *tempUrl=[NSURL URLWithString:tempUrlSting];
If not encoding the braces in the URL but encoding the rest using [Rob's answer][1] as above. When creating the NSURL, the url is empty.
If encoding the braces the URL gets generated fine, but the server throws an exception.
This Question suggests to use CFNetworking.
EDIT
Used CFNetworking as below
-(void)getDataFromUrl{
CFStringRef tempURLA = CFSTR("http://my.test.server/iostest/index.html?{\"a\":\"b\"}");
CFStringRef tempUrlSting = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)tempURLA,CFSTR("{}"), CFSTR("\""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, tempUrlSting, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL,kCFHTTPVersion1_1);
CFStringRef headerFieldName = CFSTR("Accept");
CFStringRef headerFieldValue = CFSTR("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
[self performHTTPRequest:myRequest];
}
-(void)performHTTPRequest:(CFHTTPMessageRef)request {
CFURLRef gotdatab = (__bridge CFURLRef)(CFBridgingRelease(CFHTTPMessageCopyRequestURL(request)));
// NSLog(#"(CFHTTPMessageRef request %#",gotdatab);
CFReadStreamRef requestStream = CFReadStreamCreateForHTTPRequest(NULL, request);
CFReadStreamOpen(requestStream);
NSMutableData *responseBytes = [NSMutableData data];
NSError *error;
while (TRUE) {
if (CFReadStreamHasBytesAvailable(requestStream)) {
UInt8 streambuffer[1024];
int readBytes = CFReadStreamRead (requestStream,streambuffer,sizeof(streambuffer));
NSLog(#"Read: %d",readBytes);
[responseBytes appendBytes:streambuffer length:readBytes];
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusError) {
error = (NSError*)CFBridgingRelease(CFReadStreamCopyError (requestStream));
if ([error code] == 61) {
// connection refused
NSLog(#"Error occured: %d",[error code]);
}
break;
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusAtEnd) {
NSLog(#"Stream reached end!");
error = nil;
break;
}
}//
CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader);
if (response==NULL) {
NSLog(#"response is null");
return;
}
}
The above was done using examples from here and here
Above method still has the same issue. That is: if {} are not encoded the URL doesn't get generated. If the {} are encoded the server doesn't return a proper value.
Any suggestions pls?
Sometimes URL encoded format already except for the é-character which should probably be encoded as %c3%a9. Desktop browser is quite liberal with invalid URLs, thats why it works in Safari etc.
So if you have a NSString and you want to convert it into a proper URL encoding then use the below method of NSString class.
NSURL* url = [NSURL URLWithString:[strURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
You should edit your question showing us an example of your URL and your GET parameters. If you're percent escaping, for example, some reserved character in the domain name or the URL path, that suggests one solution (e.g. stringByAddingPercentEscapesUsingEncoding is fine). If you're percent escaping the broader array of reserved characters in the parameters of a GET request (notably = or +), then stringByAddingPercentEscapesUsingEncoding is simply not up to the job and you'd have to use CFURLCreateStringByAddingPercentEscapes (but only on the parameter keys and their values, not on the full URL string). I use a method like the following on the parameters as I append them to the URL:
- (NSString *)percentEscapeURLParameter:(NSString *)string
{
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
NULL,
(CFStringRef)#":/?#!$&'()*+,;=",
kCFStringEncodingUTF8));
}
If you're saying that CFURLCreateStringByAddingPercentEscapes is not working for you, you'd have to show us how you're using it. Make sure you are doing it just on the GET parameter values, that you're supplying the necessary "legal characters to escape" parameter, that you're not escaping something that shouldn't be, etc.

Resources