Hi Guyz, in this section i will write about the bridging between the native Objective-C code with the web portion(JavaScript/HTML) code. The
iOS hybrid application delivers a native experience on iOS devices
by wrapping the mobile Web storefront with a native shell. The native
shell elements are coded using the iOS Software Development Kit (SDK),
while the storefront is accessed using the mobile Web interface. That generally means hybrid app is a combination of web app + native iOS features. We use UIWebView for loading the webapp (linking URL) and we can have our own iOS feature included with it. So, In this section, i will be describing about how to call native Objective-C method from particular button in web portion and vice versa.
function myJavascriptFunction () {
// Do whatever your want!
}
// -----------------------------------
// And in your Objective-C code:
// Call Javascript function from Objective-C:
[webViewObject stringByEvaluatingJavaScriptFromString:@"myJavascriptFunction()"];
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// Intercept custom location change, URL begins with "js-call:"
if ([[[request URL] absoluteString] hasPrefix:@"js-call:"]) {
// Extract the selector name from the URL
NSArray *components = [requestString componentsSeparatedByString:@":"];
NSString *functionName = [components objectAtIndex:1];
// Call the given selector
[self performSelector:NSSelectorFromString(functionName)];
// Cancel the location change
return NO;
}
// Accept this location change
return YES;
}
- (void)myObjectiveCFunction {
// Do whatever you want!
}
// -----------------------------------
Call Javascript function from Objective-C
// In your Javascript files:function myJavascriptFunction () {
// Do whatever your want!
}
// -----------------------------------
// And in your Objective-C code:
// Call Javascript function from Objective-C:
[webViewObject stringByEvaluatingJavaScriptFromString:@"myJavascriptFunction()"];
Call Objective-C function from Javascript
// In Objective-C
- viewDidLoad {
webView = [[UIWebView alloc] init];
// Register the UIWebViewDelegate in order to shouldStartLoadWithRequest to be called (next function)
webView.delegate = self;
}
// This function is called on all location change :- viewDidLoad {
webView = [[UIWebView alloc] init];
// Register the UIWebViewDelegate in order to shouldStartLoadWithRequest to be called (next function)
webView.delegate = self;
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// Intercept custom location change, URL begins with "js-call:"
if ([[[request URL] absoluteString] hasPrefix:@"js-call:"]) {
// Extract the selector name from the URL
NSArray *components = [requestString componentsSeparatedByString:@":"];
NSString *functionName = [components objectAtIndex:1];
// Call the given selector
[self performSelector:NSSelectorFromString(functionName)];
// Cancel the location change
return NO;
}
// Accept this location change
return YES;
}
- (void)myObjectiveCFunction {
// Do whatever you want!
}
// -----------------------------------
// In Javascript files
// Now in your javascript simply do this to call your objective-c function:
// Now in your javascript simply do this to call your objective-c function:
window.location = "js-call:myObjectiveCFunction";
Note : There is weird but apprehensible bugs with this practice: a lot of javascript/html stuff get broken when we cancel a location change. So, if you are having such problem then the next better solution will be: instead of changing the
document location in Javascript file, we create an IFrame and set its location to a value that
trigger the shouldStartLoadWithRequest method.
// In Javascript files (a better way)
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "js-frame:myObjectiveCFunction";
iframe.setAttribute("src", "js-frame:myObjectiveCFunction";
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
iframe.parentNode.removeChild(iframe);
iframe = null;
/* Example with multiple parameters sending from Javascript to Objective-C */
1. In Javascript file
// Use this in javascript to request native objective-c code
// functionName : string
// args : array of arguments
call : function call(functionName, args) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "js-frame:" + functionName + ":" + encodeURIComponent(JSON.stringify(args)));
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
2. In Objective-C file
// functionName : string
// args : array of arguments
call : function call(functionName, args) {
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "js-frame:" + functionName + ":" + encodeURIComponent(JSON.stringify(args)));
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
2. In Objective-C file
// This selector is called when something is loaded in our webview like:
// - main html document
// - sub iframes document
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
if ([requestString hasPrefix:@"js-frame:"]) {
NSArray *components = [requestString componentsSeparatedByString:@":"];
NSString *functionName = (NSString*)[components objectAtIndex:1];
NSString *argsAsString = [(NSString*)[components objectAtIndex:2]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// Instanciate JSON parser library
// include json library for json parsing or formating of parameters sent by javascript
// or you may have send the parameters as a URL componenets separated by ":" without JSON
//For this example Javascript is sending parameters as a json string so we need to parse it on client side
SBJSON *json = [ SBJSON new ];
NSArray *args = (NSArray*)[json objectWithString:argsAsString error:nil];
// args are the parameters sent from web to your client side in iPhone/iPad, so handle this as per your requirement
//and generate/call respective native Objective-C functions
return NO;
}
return YES;
}
// - main html document
// - sub iframes document
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
if ([requestString hasPrefix:@"js-frame:"]) {
NSArray *components = [requestString componentsSeparatedByString:@":"];
NSString *functionName = (NSString*)[components objectAtIndex:1];
NSString *argsAsString = [(NSString*)[components objectAtIndex:2]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// Instanciate JSON parser library
// include json library for json parsing or formating of parameters sent by javascript
// or you may have send the parameters as a URL componenets separated by ":" without JSON
//For this example Javascript is sending parameters as a json string so we need to parse it on client side
SBJSON *json = [ SBJSON new ];
NSArray *args = (NSArray*)[json objectWithString:argsAsString error:nil];
// args are the parameters sent from web to your client side in iPhone/iPad, so handle this as per your requirement
//and generate/call respective native Objective-C functions
return NO;
}
return YES;
}
Thank u Samir.
ReplyDeleteIt Will Work in Code.. Thanks Lot Again
perform selector may cause a leak . errrrrrooooor x-(
ReplyDeleteJavaScriptCore.framework is available in iOS7. This library may be more helpful: https://github.com/liaojinxing/HybridBridge
ReplyDeleteCan you please show how to do this in a example. not getting how to create javascript file and exactly what to do.
ReplyDeleteThanks.