UIWebView, Javascript and Objective-C


This is a short blogpost explaining how to communicate between a UIWebView and your Objective-C code in Xcode (for iOS) using Javascript and a UIWebView instance method called:

stringByEvaluatingJavaScriptFromString:

Here's what you need to do:

(1) Create a New Project with a Storyboard
(2) In the Storyboard drag out a UIWebView
(3) Connect the UIWebView to your ViewController.h file and give it a name so that your .h file looks like this

//
//  JavascriptViewController.h
//  Javascript


#import

@interface JavascriptViewController : UIViewController
@property (weaknonatomicIBOutlet UIWebView *myWebView;

@end

(4) Next we need the ViewController class to follow the UIWebViewDelegate protocol so we add this after the superclass name so the ViewController.h file now looks like this:

//
//  JavascriptViewController.h
//  Javascript

#import

@interface JavascriptViewController : UIViewController <UIWebViewDelegate>
@property (weaknonatomicIBOutlet UIWebView *myWebView;

@end

(5) Moving to the ViewController.m file we then need to add to the viewDidLoad: method the following

myWebView.delegate = self;


(6) Our ViewController now receives the following calls from myWebView:



(7)  Now we need to load some content. Add this to your viewDidLoad: method:


[myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundlepathForResource:@"index" ofType:@"html" inDirectory:@""isDirectory:NO]]];

(8) Now drag a file named index.html into your Xcode project. It could look like this:

<html>
<script>
function addOne(a)
{
return 1+a;
};
        
</script>
    
<div id="text"></div>
</html>

(9) Now create a -webViewDidFinishLoad: method that looks something like this:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
   
    [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"text\").innerHTML=\"Hello World\";"];
    
    NSString *windowWidth = [webView stringByEvaluatingJavaScriptFromString:@"window.innerWidth;"];
    NSString *windowHeight = [webView stringByEvaluatingJavaScriptFromString:@"window.innerHeight;"];
    NSString *callFunction = [webView stringByEvaluatingJavaScriptFromString:@"addOne(4);"];
    NSLog(@"Window Inner Width = %@ \n Window Inner Height= %@ \n The result of the function call= %@", windowWidth, windowHeight, callFunction);
}

(10) Your complete ViewController.m will now look like this:


//
//  JavascriptViewController.m
//  Javascript
//

#import "JavascriptViewController.h"

@interface JavascriptViewController ()

@end

@implementation JavascriptViewController
@synthesize myWebView;

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    myWebView.delegate = self;
    [myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@""] isDirectory:NO]]];
}

- (void)viewDidUnload
{
    myWebView.delegate=nil;
    [self setMyWebView:nil];
     [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
   
    [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"text\").innerHTML=\"Hello World\";"];
    
    NSString *windowWidth = [webView stringByEvaluatingJavaScriptFromString:@"window.innerWidth;"];
    NSString *windowHeight = [webView stringByEvaluatingJavaScriptFromString:@"window.innerHeight;"];
    NSString *callFunction = [webView stringByEvaluatingJavaScriptFromString:@"addOne(4);"];
    NSLog(@"Window Inner Width = %@ \n Window Inner Height= %@ \n The result of the function call= %@", windowWidth, windowHeight, callFunction);
}


@end

(11) You can now run your app and see how great all this works. There are a couple of things to be aware of though. First, you need to set the UIWebView delegate to nil before the UIWebView is dismissed as advised by Apple in their documentation. You could do this (as I've done in point 10) in viewDidUnload: so it looks like this:

- (void)viewDidUnload
{
    myWebView.delegate=nil;
    [self setMyWebView:nil];
     [super viewDidUnload];
    // Release any retained subviews of the main view.
}

Second, before you go Javascript crazy be aware that, as stated in the Apple documentation:

"JavaScript execution time is limited to 10 seconds for each top-level entry point. If your script executes for more than 10 seconds, the web view stops executing the script. This is likely to occur at a random place in your code, so unintended consequences may result. This limit is imposed because JavaScript execution may cause the main thread to block, so when scripts are running, the user is not able to interact with the webpage.
JavaScript allocations are also limited to 10 MB. The web view raises an exception if you exceed this limit on the total memory allocation for JavaScript."





Comments

  1. please help me
    as a i am new to iOS development,
    i don't know where to put html file in project structure.

    ReplyDelete
    Replies
    1. Open left sidebar with the list of files and folders displayed and drag the html file from Finder into here or use the File menu to Add Files to '[Project Name]'.

      Delete
  2. How to create a bridge for javascript call in ios

    ReplyDelete

Post a Comment