IOS開發中Objective-C與JS互相調用實例教程
本文我們來講講iOS系統上通用的本地Objective-C代碼與Javascript互操作的基本方法,本文還涉及到html5的應用,這里把實現方法簡單介紹。
項目中要用到html5來實現,涉及到Objective-C調用JS,以及JS調用Objective-C的方法,這里把遇到的問題以及實現方法介紹一下。
Objective-C
//
// ViewController.h
// OC_And_JS
//
// Created by 張杰 on 15/7/9.
// Copyright ? 2015年 張杰. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIWebViewDelegate>
@property (weak, nonatomic) IBOutlet UIButton *oc_call_js_no_params;
@property (weak, nonatomic) IBOutlet UIButton *oc_call_js_has_params;
@property (weak, nonatomic) IBOutlet UIWebView *mWebView;
@property (weak, nonatomic) IBOutlet UILabel *js_call_oc_show;
- (IBAction)ocCallJsNoParams:(id)sender;
- (IBAction)ocCallJsHasParams:(id)sender;
@end
Objective-C
//
// ViewController.m
// OC_And_JS
//
// Created by 張杰 on 15/7/9.
// Copyright ? 2015年 張杰. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_mWebView.delegate = self;
//打開URL
NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
[self.mWebView loadRequest:[NSURLRequest <a href="/tags.php/request/" target="_blank">request</a>WithURL:[NSURL fileURLWithPath: path]]];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *urlstr = request.URL.absoluteString;
NSRange range = [urlstr rangeOfString:@"ios://jwzhangjie"];
if (range.length!=0) {
_js_call_oc_show.text = [NSString stringWithFormat:@"請訪問地址:%@", urlstr];
}
return YES;
}
-(void)webView:(nonnull UIWebView *)webView didFailLoadWithError:(nullable NSError *)error{
NSLog(@"加載失敗");
}
-(void)webViewDidStartLoad:(nonnull UIWebView *)webView{
NSLog(@"開始加載");
}
-(void)webViewDidFinishLoad:(nonnull UIWebView *)webView{
NSLog(@"開始結束");
// 對于調用js的時候最好這個方法里面或者之后
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)ocCallJsNoParams:(id)sender {
NSString *js = [NSString stringWithFormat:@"ocCallJsNoParamsFunction();"];
[self.mWebView stringByEvaluatingJavaScriptFromString:js];
}
- (IBAction)ocCallJsHasParams:(id)sender {
NSString *js = [NSString stringWithFormat:@"ocCallJsHasParamsFunction('%@','%@');",@"jwzhangjie",@"http://jwzhangjie.cn"];
[self.mWebView stringByEvaluatingJavaScriptFromString:js];
}
@end
JavasSctipt
function ocCallJsNoParamsFunction()
{
alert("OC調用JS中的無參方法");
var e = document.getElementById("js_shouw_text");
e.options.add(new Option("OC調用JS中的無參方法", 2));
}
function ocCallJsHasParamsFunction(name, url)
{
alert(name+"的博客地址為:"+url);
var e = document.getElementById("js_shouw_text");
e.options.add(new Option("OC調用JS中的有參方法", 2));
}
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OC與JS互相調用</title>
</head>
<body>
<div >
<<a href="/tags.php/select/" target="_blank">select</a> id="js_shouw_text">
<option>
展示OC調用JS無參數
</option>
</select>
</div>
<div>
<BR/>
<input type="button" value="JS調用OC方法" onclick="js_call_oc()"/>
</div>
<!-- 這里要清楚,雖然test.js跟index.html不同及目錄,實際安裝到程序里面后,是在同級目錄的,所以這里src不能加目錄,同樣css也是一樣的 -->
<script type="text/<a href="/js_a/js.html" target="_blank">javascript</a>" src="test.js" charset="UTF-8"></script>
<script type="text/javascript">
function js_call_oc()
{
var iFrame;
iFrame = document.createElement("<a href="/tags.php/iframe/" target="_blank">iframe</a>");
iFrame.setAttribute("src", "ios://jwzhangjie");
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
// 發起請求后這個iFrame就沒用了,所以把它從dom上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
</script>
</body>
</html>
規避1:對于OC去調用JS內容最好在webViewDidFinishLoad方法里或者之后
規避2:在html里面引用js或者css的時候src不要帶有路徑,因為安裝后文件都在同級目錄下面
規避3:OC調用JS的規范
NSString *js = [NSString stringWithFormat:@"ocCallJsHasParamsFunction('%@','%@');",@"jwzhangjie",@"http://jwzhangjie.cn"];
[self.mWebView stringByEvaluatingJavaScriptFromString:js];
規避4:JS調用OC,這里通過html里面發送一個請求,然后在ios中使用shouldStartLoadWithRequest攔截請求,根據請求url的不同進行處理。
javascript
function js_call_oc()
{
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", "ios://jwzhangjie");
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
// 發起請求后這個iFrame就沒用了,所以把它從dom上移除掉
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *urlstr = request.URL.absoluteString;
NSRange range = [urlstr rangeOfString:@"ios://jwzhangjie"];
if (range.length!=0) {
_js_call_oc_show.text = [NSString stringWithFormat:@"請訪問地址:%@", urlstr];
}
return YES;
}
javascript與Objective-C的相互調用
Objective-C調用Javascript方法:
前提:
UIWebView已經完全加載完成包含需要調用的頁面(注:在UIWebViewDelegate托管中通過監視- (void)webViewDidFinishLoad:(UIWebView *)webView調用來確定頁面是否加載完成)。
方法:
假設某視圖對象的子視圖屬性self.webview加載的頁面包含如下Javascript函數:
function getString(){ return “Hello javascript!”;}
并且該函數在該頁面上可被正常調用,則可以通過形如下面的Objectvie-C方法調用此函數:
NSString *str = [self.webview stringByEvaluatingJavaScriptFromString:@"getString();"];
該函數調用實際模擬了頁面上的一次Javascript函數調用,因此在該函數內部任何有效的Javascript代碼都可被執行!該Objective-C代碼返回值為被調用的Javascript代碼的返回值,在上例中,str的值將被賦為@”Hello javascript!”。
被調用的函數可以帶有字符串或數值型的參數。若調用的Javascript函數名稱帶有參數,需保證傳進去的參數的格式正確性,特別是字符串參數的引號很容易被忽略。
系統響應頁面Javascript代碼:
前提:
需要實現UIWebViewDelegate的
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
托管函數(以下簡稱跳轉監視函數)并將實現了該托管函數的對象設置為UIWebView的delegate。
方法:
UIWebView的當前頁面將要被Javascript代碼通過以下方式轉向的時候,會調用上述跳轉監視函數:
window.location.href=”http://www.strongsoft.net”;
此時實現了該托管協議的對象的跳轉監視函數會被調用,通過如下代碼監視瀏覽器跳轉的地址:
NSString *url = [[request URL] absoluteString];
若該托管函數返回值為NO,則頁面UIWebView的頁面跳轉將被否決。利用這一思路,監視頁面上的特定格式的跳轉地址加以攔截,并執行相應的本地代碼,即可實現Javascript與Objective-C代碼的交互。
例如,規定攔截URL地址前綴為”objc:”的所有地址,并且用if…else…語句判定本地需要執行的代碼,則實現形如以下格式的Objective-C托管函數:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
NSString *urlString = [[request URL] absoluteString];
NSArray *urlComps = [urlString componentsSeparatedByString:@":"];
if([urlComps count] && [[urlComps objectAtIndex:o] isEqualToString:@"objc"])
{
NSString *funcStr = [urlComps objectAtIndex:1];
if([funcStr isEqualToString:@"doFunc1"])
{
}
else if([funcStr isEqualToString:@"doFunc2"])
{
}
return NO;
}
return YES;
}
當需要調用本地函數1時,可以通過如下Javascript函數進行:
window.location.href=”objc:doFunc1”;
根據上述思路,可以完善通過Javascript調用本地帶參數的Objective-C代碼。