extract text from webview - ios

I am trying to extract data from website.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"finish loading");
NSLog(#"TEXT of website \n %#",[_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerText;"]);
NSString *webTextString = [_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innertext;"];
NSLog(#"Website Text: %#",webTextString);
}
NSLog is actually display data but when I copy data to NSString it always stay empty;
Here is response output:
2014-02-04 17:41:07.795 MYAPP[76113:70b] TEXT of website
...... // some more text
ouncils are warning that parts of Britain's road network could become so unsafe the they will need to be shut completely.
Local authorities in some areas say finances are so squeezed they may have to consider withdrawing maintenance from their rural road network.
......// some more text
2014-02-04 17:41:07.795 MYAPP[76113:70b] Website Text:

In the line
NSString *webTextString = [_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innertext;"];
your capitalization is wrong. Should be innerText, not innertext.

Related

how to check the response type(Json/Html) in webview in IOS

I have a web view which request one web page, now that web has some action events which may reply to IOS app as HTML or json. So how would the app will come to know the response type sent. So that the response is handled within the app.
Reading of static HTML content in webview using its delegate is what i have tried, when it is dynamic then how can one handle.
code logic:-
ON load of controller, request page with URL(something) in web view, user will interact
check response type if JSON then 4 else 3
load web page with different URL
Deserialize the JSON Data and store in native DB
Method 1
First, You need to set and handle the UIWebView delegate methods in your UIViewController
Then, in webView: shouldStartLoadWithRequest: navigationType: method, use the following
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSError *error;
NSString *responseString = [NSString stringWithContentsOfURL:request.URL
encoding:NSASCIIStringEncoding
error:&error];
//Parse the string here to confirm if it's JSON or HTML
//In case of JSON, stop the loading of UIWebview
if(json) {
retrun NO;
}
return YES;
}
Note: This will take a performance hit in case of HTML content as the response will be loaded 2 times. Once in stringWithContentsOfURL method and second time when the web view loads.
Method 2
To avoid the double loading you can let the web view load, irrespective of the content type. And then get the loaded content in webViewDidFinishLoad method.
For this you may need to perform some changes on the server end as well.
Suppose your HTML page with JSON is structured as :
<html>
<body>
<div id="json" style="display: none">{"jsonvalue":"{{result}}"}</div>
</body>
</html>
Then in webViewDidFinishLoad
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *res = [webView stringByEvaluatingJavaScriptFromString:#"document.getElementById('json').innerHTML"];
//Use the JSON string as required
}
After the long brainstorming as i am new to IOS, I figure out the solution for swift as I could not find the solution in swift language. Here are the few steps for solutions-
First drag and drop the webView to create the connection of webview
#IBOutlet weak var webViewlLoad: UIWebView!
Now load your webView by calling
webViewlLoad.loadRequest(URL)
Now wait for some time and check the webview for getting the data by the following code
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 5 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
//put your code which should be executed with a delay here
let doc = self.webViewlLoad.stringByEvaluatingJavaScriptFromString("document.documentElement.outerHTML")!
print("document JSON = \(doc)")
let startIndexJSON = doc.rangeOfString("{")?.startIndex
let endIndexJSON = doc.rangeOfString("}}")?.startIndex
var finalJson = doc.substringWithRange( Range<String.Index>(start:startIndexJSON!, end: endIndexJSON!.advancedBy(2)))
print("\n\n finalJson JSON = \(finalJson)")
}
In above code i wait for 5 seconds , then the webView load the json. I read it by substring the result.

XCode NSMutableURLRequest not hitting the web server

I have several series of images stored in folders on a web server. The folder hierarchy looks something like this…
WebServer’s Web Folder
_20160123161915_4671579
Final
t1.jpg
t2.jpg
i1.jpg
i2.jpg
Recall
t1.jpg
t2.jpg
i1.jpg
i2.jpg
Initial
t1.jpg
t2.jpg
i1.jpg
i2.jpg
The user selects one of the series, initial, Recall, or Final from a list on the iPad and the series is retrieved from the server and displayed. I am using the following code to retrieve the images. In this example I am retrieving the the jpgs that start with a t…
for (int i = 0; i < imageCount; i++) {
fileName = [NSString stringWithFormat:#"t%i.jpg", i+1];
imagePath = [NSString stringWithFormat:#"_%#/%#/%#", [opHelper ID], [seriesArray objectAtIndex:thumbsSeriesIndex], fileName];
urlString = [[NSString stringWithFormat:#"http://%#/%#", [opHelper hostIP], imagePath] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
url = [NSURL URLWithString:urlString];
imageURL = [NSMutableURLRequest requestWithURL:url];
NSURLResponse *response;
NSError *error;
imageData = [NSURLConnection sendSynchronousRequest:imageURL returningResponse:&response error:&error];
//consume the imageData
}
This works except for once in a while I get back blank images for one of the series. In my example, I would get good images with Initial and Recall, but Final comes back with blanks. A 500kb file is requested and imageData gets 800 bytes. I can watch the server hit count increase for each image request. If a series fails the server does not get hit at all. ie. If in the above example file hierarchy I select Recall the server count increases by 4, same with Initial, but if I select Final the server count does not increment.
Here are the actual NSURLs being sent…
url NSURL * #"http://192.168.1.100/_20160123161915_4671579/Final/t1.jpg" 0x80a7f640
url NSURL * #"http://192.168.1.100/_20160123161915_4671579/Recall%201/t1.jpg" 0x804fbcf0
url NSURL * #"http://192.168.1.100/_20160123161915_4671579/Initial/t1.jpg" 0x8088da30
The url for Final in this case was acting up and not hitting the server, but I don’t see anything that jumps out at me in the URLs that might be suspect. Does anyone see anything in my code that might be contributing to this problem? I know it is not a file issue as even if I rename one of the working folders so that the requested file cannot be found, the server gets hit and the iPad receives blank images without any errors.
Thanks for any help.
John
Ok. It was a cache issue. I fixed it by modifying the cache policy...
imageURL = [NSMutableURLRequest requestWithURL:url];
imageURL.cachePolicy = NSURLRequestReloadIgnoringCacheData;
John

Arabic characters (effective power bug) crash my swift iOS app. how do I properly sanitize inputs to avoid this and related problems?

the text that caused the crash is the following:
the error occurred at the following line:
let size = CGSize(width: 250, height: DBL_MAX)
let font = UIFont.systemFontOfSize(16.0)
let attributes = [
NSFontAttributeName:font ,
NSParagraphStyleAttributeName: paraStyle
]
var rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context: nil)
where text variable contains the inputted string
parastyle is declared as follows:
let paraStyle = NSMutableParagraphStyle()
paraStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
My initial idea is that the system font can't handle these characters and I need to do an NSCharacterSet, but I'm not sure how to either just ban characters that'll crash my app or make it so i can handle this input (ideal). I don't want to ban emojis/emoticons either.
Thanks!
Not an answer but some information and that possibly provids a way code way to avoid it.
Updated to information from The Register:
The problem isn’t with the Arabic characters themselves, but in how the unicode representing them is processed by CoreText, which is a library of software routines to help apps display text on screens.
The bug causes CoreText to access memory that is invalid, which forces the operating system to kill off the currently running program: which could be your text message app, your terminal, or in the case of the notification screen, a core part of the OS.
From Reddit but this may not be completely correct:
It only works when the message has to be abbreviated with ‘…’. This is usually on the lock screen and main menu of Messages.app.
The words effective and power can be anything as long as they’re on two different lines, which forces the Arabic text farther down the message where some of the letters will be replaced with ‘…’
The crash happens when the first dot replaces part of one of the Arabic characters (they require more than one byte to store) Normally there are safety checks to make sure half characters aren’t stored, but this replacement bypasses those checks for whatever reason.
My solution is the next category:
static NSString *const CRASH_STRING = #"\u0963h \u0963 \u0963";
#implementation NSString (CONEffectivePower)
- (BOOL)isDangerousStringForCurrentOS
{
if (IS_IOS_7_OR_LESS || IS_IOS_8_4_OR_HIGHER) {
return NO;
}
return [self containsEffectivePowerText];
}
- (BOOL)containsEffectivePowerText
{
return [self containsString:CRASH_STRING];
}
#end
Filter all characters to have same directionality. Unfortunately, I'm only aware of such API in Java.
Don't even try. This is a bug in the operating system that will be fixed. It's not your problem. If you try to fix it, you are just wasting your time. And you are very likely to introduce bugs - when you say you "sanitise" input that means you cannot handle some perfectly fine input.
The company I work at develops a multiplatform group video chat.
In Crashlytics report we started noticing that some users are "effectively" trolling iOS users using this famous unicode sequence.
We can't just sit and wait for Apple to fix this bug.
So, I've worked on this problem, this is the shortest crashing sequence I got:
// unichar representation
unichar crashChars[8] = {1585, 1611, 32, 2403, 32, 2403, 32, 2403};
// string representation
NSString *crashString = #"\u0631\u064b \u0963 \u0963 \u0963"
So, I decided to filter out all text messages that contains two U+0963 'ॣ' symbols with one symbol between them (hope you are able to decipher this phrase)
My code from NSString+Extensions category.
static const unichar kDangerousSymbol = 2403;
- (BOOL)isDangerousUnicode {
NSUInteger distance = 0;
NSUInteger charactersFound = 0;
for (NSUInteger i = 0; i < self.length; i++) {
unichar character = [self characterAtIndex:i];
if (charactersFound) {
distance++;
}
if (distance > 2) {
charactersFound = 0;
}
if (kDangerousSymbol == character) {
charactersFound++;
}
if (charactersFound > 1 && distance > 0) {
return YES;
}
}
return NO;
}
Lousy Specta test:
SpecBegin(NSStringExtensions)
describe(#"NSString+Extensions", ^{
//....
it(#"should detect dangerous Unicode sequences", ^{
expect([#"\u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beFalsy();
});
//....
});
SpecEnd
I'm not sure if it's OK to "discriminate" messages with too many "devanagari vowel sign vocalic ll".
I'm open to corrections, suggestions, criticism :).
I would love to see a better solution to this problem.

Compare Static String and String from webview

My App sends html to a Arduino with an Ethernet Shield. The Ethernet shield acts as a webserver and sends a simple message back to a UIWebview in the App. I'm using
NSString *myText = [myWebView2 stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
If I ask NSLog to print my "myText" It prints out
<h2>Relay1 ON</h2>
Which is what is sent to the webview. Now if I try to Compare myText with a static string that matches exactly, I get no result.
Heres the entire code block.
- (void)webViewDidFinishLoad:(UIWebView *)myWebView2;
{
NSString *myText = [myWebView2
stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
NSLog(#"my Text=%#",myText);
if ([myText isEqualToString:#"<h2>Relay1 ON</h2>"]) {
NSLog (#"If statement was triggered");
}
}
If I look at the value of myText in NSLog it exactly matches yet the if statement is never triggered.
What am I missing in that if statement?
Thanks!!
Not Really Solved but I used NSRange to search myText for "Relay1 ON" and that works more efficiently than dealing with hidden Characters. Thanks so Much for your help.

Dropbox detect file change using delta IOS

I want the user to be advised if any file changes in the dropbox folder. To do this I have to use this code:
[self.restCLient loadDelta: nil];
and the methods:
-(void)restClient:(DBRestClient *)client loadedDeltaEntries:(NSArray *)entries reset:(BOOL)shouldReset cursor:(NSString *)cursor hasMore:(BOOL)hasMore{
NSLog(#"WORKED: %#, %#, %c, %c", entries, cursor, hasMore, shouldReset);
}
-(void)restClient:(DBRestClient *)client loadDeltaFailedWithError:(NSError *)error{
NSLog(#"THE ERROR: %#", error);
}
This is the type of response I am getting:
2013-03-06 20:46:33.373 Splash-it[1659:907] WORKED: (
"<DBDeltaEntry: 0x1e2afbf0>",
"<DBDeltaEntry: 0x1e0e4030>",
"<DBDeltaEntry: 0x1e013640>",
"<DBDeltaEntry: 0x1e28e590>"
)
How can I understand form this if something has changed in my dropbox?
This question is a bit old, but I thought I'd answer anyway. :)
You're going to want to access the properties of the DBDeltaEntry object.
Step 1: Import DBDeltaEntry.h
I have no idea why this isn't included with the rest of the Dropbox stuff (I emailed Dropbox to ask why). Add this to your class:
#import "DBDeltaEntry.h"
Step 2: Loop Through the Results
Inside the loadedDeltaEntries delegate method, you can loop through your results like this:
for(DBDeltaEntry *file in entries) {
NSLog(#"Entry name: %# / Metadata: %#",file.lowercasePath, file.metadata.filename);
}
To see what else you can access on the metadata of an DBDeltaEntry object, look inside DBMetadata.h:
BOOL thumbnailExists;
long long totalBytes;
NSDate* lastModifiedDate;
NSDate *clientMtime; // file's mtime for display purposes only
NSString* path;
BOOL isDirectory;
NSArray* contents;
NSString* hash;
NSString* humanReadableSize;
NSString* root;
NSString* icon;
NSString* rev;
long long revision; // Deprecated; will be removed in version 2. Use rev whenever possible
BOOL isDeleted;
NSString *filename;
Step 3: Understanding The Results
This list of entries represents the most recent changes to your Dropbox folder (what files were modified, deleted, or added). Using the cursor is important in the loadedDeltaEntries method because it helps you keep track of which changes you're aware of. You can store the cursor and then pass it in with each delta call to tell Dropbox "this is as far as I'm aware when it comes to changes" and Dropbox will only tell you what has changed since that cursor.
I hope that helps.

Resources