之前項目中有一部分內(nèi)容和H5的小伙伴協(xié)同開發(fā)的,使用了各種與H5的交互,現(xiàn)在有時間整理出來,和大家分享一下。
這篇文章會介紹這么幾個內(nèi)容:
1、Html調(diào)用OC的方法。
2、Html向OC傳值,單個值與多個值。
3、OC調(diào)用Html的方法。
4、OC向Html傳值,多個值。
為了能讓小伙伴們能夠深入體會,作為Html小白,我就從網(wǎng)上現(xiàn)學(xué)現(xiàn)賣的。
Html都是我自己寫的,可能會有很多不雅觀的地方,還請各位看官多多包含~
第一步,新建一個項目TestHtml5。
第二步,新建三個文件分別為
File.html 主體內(nèi)容,包含各個按鈕及其方法的實現(xiàn)。
File.js 可以將方法寫在這里并調(diào)用,然而為了大家方便查看方法,我沒有使用這個文件,我把內(nèi)容都放在File.html中了。
File.css 設(shè)置html的樣式等。
第三步,新建一個繼承于NSObject的CustomJSObject對象,導(dǎo)入<JavaScriptCore/JavaScriptCore.h>頭文件,并定義一個CustomJSProtocol。
第四步,我們先進(jìn)行Html的編碼。
<!DOCTYPE html>
<html>
<header>
<title id = "title">Title of this page</title>
<!--樣式從File.css文件中獲取-->
<link rel="stylesheet" type="text/css" href="File.css">
</header>
<body>
<!-- 標(biāo)簽,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<p id = "wql">This is my first try to write Html5 file.</p>
<br/>
<!-- 加粗的文本,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<b id = "myp">This text is bold</b>
<!-- 換行符-->
<br/><br/><br/><br/>
<!-- 按鈕,點擊按鈕觸發(fā)helloWQL()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:點擊后觸發(fā)OC的方法-->
<button type="button" onclick = "helloWQL()">點擊出彈框</button>
<!-- 定義各個方法-->
<script type="text/javascript">
//調(diào)用native的helloWQL方法,native對象由OC注入
function helloWQL(){
native.helloWQL();
}
</script>
</body>
</html>
第五步,在CustomJSProtocol中新添加方法helloWQL。然后在CustomJSObject中實現(xiàn)helloWQL方法,并寫好相關(guān)回調(diào)。
第六步,在ViewController中編碼,加載本地的Html。
//加載本地的html文件
- (void)loadWebView
{
self.mainWebView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 100, PhoneScreen_WIDTH, PhoneScreen_HEIGHT-100)];
self.mainWebView.delegate = self;
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"File" ofType:@"html"];
NSString *htmlCont = [NSString stringWithContentsOfFile:htmlPath
encoding:NSUTF8StringEncoding
error:nil];
[self.mainWebView loadHTMLString:htmlCont baseURL:baseURL];
[self.view addSubview:self.mainWebView];
}
第七步,在完成html加載的時候,也就是webViewDidFinishLoad方法中進(jìn)行context注入:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//加載完成后注入object,讓我們可以得到html的點擊事件
[self addCustomAction];
}
- (void)addCustomAction
{
//獲取context,這里的path是固定的
JSContext *context = [self.mainWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//自定義的JS對象,需要注入到context中
CustomJSObject *object = [[CustomJSObject alloc]initWithSuccessCallback:^(NSDictionary *dic) {
if ([[dic.allKeys firstObject] isEqualToString:@"helloWQL"]) {
//html調(diào)用OC的方法
NSLog(@"HelloWQLDic:%@",dic);
[self webViewClickButtonAction];
}
} faileCallback:^(NSDictionary *dic) {
NSLog(@"FailDic:%@",dic);
}];
//這里要使用native,html那邊調(diào)用的是native
context[@"native"] = object;
}
- (void)webViewClickButtonAction
{
NSLog(@"OC 接收到 H5按鈕點擊事件");
}
此時我們點擊html的按鈕就能夠調(diào)用OC的方法了。
小伙伴們會不會有點云里霧里的,我覺得口頭描述會有一點復(fù)雜,我就直接做了一張圖,請笑納:

看看點擊按鈕會有什么效果:

第八步,從Html傳值給OC。
整體的流程和調(diào)用方法一致的,需要注意的是:傳值的時候,請注意方法名的大小寫,尤其是傳多個參數(shù)時,第二個參數(shù)的名字要大寫開頭。
<!DOCTYPE html>
<html>
<header>
<title id = "title">Title of this page</title>
<!--樣式從File.css文件中獲取-->
<link rel="stylesheet" type="text/css" href="File.css">
</header>
<body>
<!-- 標(biāo)簽,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<p id = "wql">This is my first try to write Html5 file.</p>
<br/>
<!-- 加粗的文本,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<b id = "myp">This text is bold</b>
<!-- 換行符-->
<br/><br/><br/><br/>
<!-- 按鈕,點擊按鈕觸發(fā)helloWQL()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:點擊后觸發(fā)OC的方法-->
<button type="button" onclick = "helloWQL()">點擊出彈框</button>
<br/><br/>
<!-- 按鈕,點擊該按鈕會觸發(fā)sendValueFromHtml()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:將某個值傳給OC,我們這里分別傳了一個值、兩個值-->
<button type="button" onclick = "sendValueFromHtml()">點擊傳值</button>
<br/><br/>
<!-- 定義各個方法-->
<script type="text/javascript">
//調(diào)用native的helloWQL方法,native對象由OC注入
function helloWQL(){
native.helloWQL();
}
function sendValueFromHtml(){
//需要注意的是傳兩個值的時候,第二個參數(shù)應(yīng)該以大寫字母開頭(WithValueTwo)。
//正確 sendValueFromHtmlToOCWithValue:(NSString*)valueOne WithValueTwo:(NSString*)valueTwo
//錯誤 sendValueFromHtmlToOCWithValue:(NSString*)valueOne withValueTwo:(NSString*)valueTwo
native.sendValueFromHtmlToOCWithValue('This is send one Value');
native.sendValueFromHtmlToOCWithValueWithValueTwo('Good','Boy');
}
</script>
</body>
</html>
傳值的效果:

第九步:OC調(diào)用Html的方法。
這個比較簡單需要Html為我們預(yù)留方法即可。我寫了一個按鈕,按鈕觸發(fā)以下方法:
//調(diào)用html的方法
- (void)callHtmlMethodAction:(UIButton*)sender
{
JSContext *context = [self.mainWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
CustomJSObject *object = [CustomJSObject new];
NSString *textJS = [NSString stringWithFormat:@"methodForOC()"];
[context evaluateScript:textJS];
context[@"native"] = object;
}
看看File.html文件:
<!DOCTYPE html>
<html>
<header>
<title id = "title">Title of this page</title>
<!--樣式從File.css文件中獲取-->
<link rel="stylesheet" type="text/css" href="File.css">
</header>
<body>
<!-- 標(biāo)簽,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<p id = "wql">This is my first try to write Html5 file.</p>
<br/>
<!-- 加粗的文本,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<b id = "myp">This text is bold</b>
<!-- 換行符-->
<br/><br/><br/><br/>
<!-- 按鈕,點擊按鈕觸發(fā)helloWQL()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:點擊后觸發(fā)OC的方法-->
<button type="button" onclick = "helloWQL()">點擊出彈框</button>
<br/><br/>
<!-- 按鈕,點擊該按鈕會觸發(fā)sendValueFromHtml()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:將某個值傳給OC,我們這里分別傳了一個值、兩個值-->
<button type="button" onclick = "sendValueFromHtml()">點擊傳值</button>
<br/><br/>
<!-- 按鈕,點擊該按鈕會觸發(fā)getValueFromOC()方法,按鈕上的文本是“從OC拿值”-->
<!-- 該按鈕的目的是:點擊按鈕后,從OC獲取某個值-->
<button type="button" onclick = "getValueFromOC()">從OC拿值</button>
<!-- 定義各個方法-->
<script type="text/javascript">
//調(diào)用native的helloWQL方法,native對象由OC注入
function helloWQL(){
native.helloWQL();
}
function sendValueFromHtml(){
//需要注意的是傳兩個值的時候,第二個參數(shù)應(yīng)該以大寫字母開頭(WithValueTwo)。
//正確 sendValueFromHtmlToOCWithValue:(NSString*)valueOne WithValueTwo:(NSString*)valueTwo
//錯誤 sendValueFromHtmlToOCWithValue:(NSString*)valueOne withValueTwo:(NSString*)valueTwo
native.sendValueFromHtmlToOCWithValue('This is send one Value');
native.sendValueFromHtmlToOCWithValueWithValueTwo('Good','Boy');
}
//這個方法html并不調(diào)用,而是給OC調(diào)用的
function methodForOC(){
alert('這個是Html的方法,OC調(diào)的到嗎?');
}
</script>
</body>
</html>
主要看后面幾行,我們調(diào)的是那個methodForOC方法。
看一下效果:

第十步:點擊html的按鈕,然后從OC獲取值。
主體流程:點擊html按鈕,觸發(fā)OC方法,然后從OC傳值給Html。
Html內(nèi)容:
<!DOCTYPE html>
<html>
<header>
<title id = "title">Title of this page</title>
<!--樣式從File.css文件中獲取-->
<link rel="stylesheet" type="text/css" href="File.css">
<!--響應(yīng)的方法從File.js文件中獲取-->
<!--<script type="text/javascript" src="File.js"></script>-->
</header>
<body>
<!-- 標(biāo)簽,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<p id = "wql">This is my first try to write Html5 file.</p>
<br/>
<!-- 加粗的文本,css中設(shè)置樣式時,會根據(jù)id來設(shè)置-->
<b id = "myp">This text is bold</b>
<!-- 換行符-->
<br/><br/><br/><br/>
<!-- 按鈕,點擊按鈕觸發(fā)helloWQL()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:點擊后觸發(fā)OC的方法-->
<button type="button" onclick = "helloWQL()">點擊出彈框</button>
<br/><br/>
<!-- 按鈕,點擊該按鈕會觸發(fā)sendValueFromHtml()方法,按鈕上的文本是“點擊出彈框”-->
<!-- 該按鈕的目的是:將某個值傳給OC,我們這里分別傳了一個值、兩個值-->
<button type="button" onclick = "sendValueFromHtml()">點擊傳值</button>
<br/><br/>
<!-- 按鈕,點擊該按鈕會觸發(fā)getValueFromOC()方法,按鈕上的文本是“從OC拿值”-->
<!-- 該按鈕的目的是:點擊按鈕后,從OC獲取某個值-->
<button type="button" onclick = "getValueFromOC()">從OC拿值</button>
<!-- 定義各個方法-->
<script type="text/javascript">
//調(diào)用native的helloWQL方法,native對象由OC注入
function helloWQL(){
native.helloWQL();
}
function sendValueFromHtml(){
//需要注意的是傳兩個值的時候,第二個參數(shù)應(yīng)該以大寫字母開頭(WithValueTwo)。
//正確 sendValueFromHtmlToOCWithValue:(NSString*)valueOne WithValueTwo:(NSString*)valueTwo
//錯誤 sendValueFromHtmlToOCWithValue:(NSString*)valueOne withValueTwo:(NSString*)valueTwo
native.sendValueFromHtmlToOCWithValue('This is send one Value');
native.sendValueFromHtmlToOCWithValueWithValueTwo('Good','Boy');
}
//需要從OC那里拿值,之后會觸發(fā)OC的sendValueToHtml方法
function getValueFromOC(){
native.sendValueToHtml();
}
//接收從OC傳過來的值,需要OC調(diào)用該方法,并傳入值
function getUserNameAndAge(ocValueOne,ocValueTwo){
alert('name:'+ocValueOne+' '+'age:'+ocValueTwo);
}
//這個方法html并不調(diào)用,而是給OC調(diào)用的
function methodForOC(){
alert('這個是Html的方法,OC調(diào)的到嗎?');
}
</script>
</body>
</html>
傳值的核心代碼:
if ([[dic.allKeys firstObject] isEqualToString:@"sendValueToHtml"]){
//從OC傳值給html
NSLog(@"sendValueToHtml:%@",dic);
NSString *name = @"WQL";
NSString *age = @"22";
NSString *textJS = [NSString stringWithFormat:@"getUserNameAndAge('%@','%@')",name,age];
[context evaluateScript:textJS];
}
哈哈,“口說無憑”,直接上圖:

流程梳理完畢,就是上效果圖了:

這個做的有點瑕疵,彈框不知道為什么取消不了。好尷尬....但是數(shù)據(jù)確實傳給了Html那邊。如果有知道原因的小伙伴,請留言哈~
整體流程就是這樣了。我們實現(xiàn)了各種和H5的交互,感覺也沒有那么難哈~
此外,如果運(yùn)行代碼時,點擊按鈕沒有效果,請clean一下,H5好像是有緩存的。
有什么意見或建議還請各位大神不吝指教~
今天愚人節(jié),但學(xué)習(xí)我們是認(rèn)真的!